diff --git a/.claude/commands/upgrade-webkit.md b/.claude/commands/upgrade-webkit.md index 26be69a72f24..4d9d8e33434a 100644 --- a/.claude/commands/upgrade-webkit.md +++ b/.claude/commands/upgrade-webkit.md @@ -36,6 +36,6 @@ To do that: Things to check for a successful upgrade: -- Did Source/JavaScriptCore/runtime/JSType.h change? The enum values must align with Bun's mirror in src/jsc/JSType.rs (src/jsc/JSType.zig is a non-compiled porting reference, not the live code). +- Did Source/JavaScriptCore/runtime/JSType.h change? The enum values must align with Bun's mirror in src/jsc/JSType.rs. - Were there any changes to the WebCore code generator? If there are C++ compilation errors, check for differences in the generated reference code in vendor/WebKit/Source/WebCore/bindings/scripts/test/JS/ - If the merge touched the fork's .github/workflows, the release tarball names must still match prebuiltSuffix() in scripts/build/deps/webkit.ts diff --git a/.claude/docs/landing-prs.md b/.claude/docs/landing-prs.md index f8efa05161e2..04bca60ea615 100644 --- a/.claude/docs/landing-prs.md +++ b/.claude/docs/landing-prs.md @@ -62,6 +62,6 @@ Companion to the "Landing PRs: What Bun Reviewers Catch" section in CLAUDE.md. T - **Audit the full diff for accidental ride-alongs.** Submodule pointer bumps, lockfile churn from rebases, regenerated snapshots, formatter churn on untouched code, stash leakage. After every merge/rebase with main, re-diff against main: conflict resolution can silently resurrect deleted code or drop your own headline fix while keeping its test (a "one-line test tweak" commit once touched 33 files and reverted the entire production fix). Every file in the diff must be explainable from the PR's stated purpose. - **The PR description is the permanent squash-commit message — keep it true.** State the root cause and make the exact fixing line identifiable apart from refactoring ("Which line was the fix?"). Name the verifying tests and state they fail on the unfixed build. "Fixes #N" must match the issue's actual repro; a partial fix says so. Re-sync title/description whenever review reworks the change. Every hunk needs an articulable one-sentence justification — pre-empt it in the description or a code comment for anything a reviewer can't explain from context. On large mechanical diffs, leave self-review comments pointing at the load-bearing hunks. Never delete unrelated code, others' TODOs, or debug tooling in passing — deletions your change orphans are required (see "Delete dead code"), but each is intentional and named. - **Treat every review suggestion — especially from bots — as an unverified hypothesis.** Reproduce or check it against actual API semantics before applying or dismissing. Apply real findings; decline wrong ones in-thread with checkable evidence (file:line, run transcripts) — evidence-backed rebuttals close threads, bare dismissals don't. Never blanket-apply (blindly-applied suggestions have reintroduced known ASAN failures), never resolve threads silently in bulk (a bulk-resolve once swallowed a genuine correctness bug). When a reviewer flags a pattern once, sweep and fix every instance — Jarred leaves one substantive comment then "ditto" on each clone; fixing only the commented line guarantees another round. -- **Green CI on every platform is a hard precondition.** Maintainers file changes-requested reviews consisting solely of "CI is failing". Confirm you changed the implementation that ships (a complete fix to a dormant .zig reference file got the one-line review "redo this PR in Rust"). Regenerate checked-in codegen outputs — again after every rebase. Every failure on your branch but not on main is yours to root-cause; "probably a flake" requires a link to the same failure on main. Check per-job results, not the aggregate icon, and confirm CI actually executed your tests — path filters silently skip them. +- **Green CI on every platform is a hard precondition.** Maintainers file changes-requested reviews consisting solely of "CI is failing". Regenerate checked-in codegen outputs — again after every rebase. Every failure on your branch but not on main is yours to root-cause; "probably a flake" requires a link to the same failure on main. Check per-job results, not the aggregate icon, and confirm CI actually executed your tests — path filters silently skip them. - **One concern per PR, scoped to the narrowest change that fixes it.** Fixing every instance of the same bug class is ONE concern (see "Fix the whole class"); drive-by refactors, style cleanups of adjacent code, and vendored upgrades are not. If one part triggers design debate mid-review, carve it out so the uncontroversial part merges. Diff size itself is grounds for changes-requested. - **Pre-existing bugs surfaced by review: acknowledge, scope, track.** Never silently ignore, never silently widen your diff. State the mechanism in-thread, note your PR doesn't change it, file a tracking issue — "out of scope" without a tracker is not accepted. Exception: if it's the exact bug class your PR claims to eliminate, fix all instances in the same PR ("pre-existing, will follow up" for the same crash class gets "no, fix it."). diff --git a/.claude/hooks/post-edit-zig-format.js b/.claude/hooks/post-edit-format.js similarity index 68% rename from .claude/hooks/post-edit-zig-format.js rename to .claude/hooks/post-edit-format.js index 6f9cf9aa924c..85ab0a2c95a0 100755 --- a/.claude/hooks/post-edit-zig-format.js +++ b/.claude/hooks/post-edit-format.js @@ -20,29 +20,6 @@ if (!filePath) { process.exit(0); } -function formatZigFile() { - try { - // Format the Zig file - const result = spawnSync("vendor/zig/zig.exe", ["fmt", filePath], { - cwd: process.env.CLAUDE_PROJECT_DIR || process.cwd(), - encoding: "utf-8", - }); - - if (result.error) { - console.error(`Failed to format ${filePath}: ${result.error.message}`); - process.exit(0); - } - - if (result.status !== 0) { - console.error(`zig fmt failed for ${filePath}:`); - if (result.stderr) { - console.error(result.stderr); - } - process.exit(0); - } - } catch (error) {} -} - function formatTypeScriptFile() { try { // Format only — NO organize-imports plugin. That plugin strips imports @@ -56,9 +33,7 @@ function formatTypeScriptFile() { } catch (error) {} } -if (ext === ".zig") { - formatZigFile(); -} else if ( +if ( [ ".cjs", ".css", diff --git a/.claude/hooks/pre-bash-zig-build.js b/.claude/hooks/pre-bash-guard.js similarity index 94% rename from .claude/hooks/pre-bash-zig-build.js rename to .claude/hooks/pre-bash-guard.js index 90901d765e86..51f41e102867 100755 --- a/.claude/hooks/pre-bash-zig-build.js +++ b/.claude/hooks/pre-bash-guard.js @@ -63,16 +63,6 @@ useSystemBun = inlineEnv.get("USE_SYSTEM_BUN") ?? useSystemBun; // Get the executable name (argv0) const argv0 = basename(tokens[0], extname(tokens[0])); -// Check if it's zig or zig.exe -if (argv0 === "zig") { - // Filter out flags (starting with -) to get positional arguments - const positionalArgs = tokens.slice(1).filter(arg => !arg.startsWith("-")); - - // Check if the positional args contain "build" followed by "obj" - if (positionalArgs.length >= 2 && positionalArgs[0] === "build" && positionalArgs[1] === "obj") { - denyWithReason("error: Use `bun bd` to build Bun and wait patiently"); - } -} // Disallow direct `rustfmt`: it doesn't read the workspace edition from // Cargo.toml the way `cargo fmt` does, so its output can disagree with CI's diff --git a/.claude/settings.json b/.claude/settings.json index 387633d5fdbd..563850ddf672 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -6,7 +6,7 @@ "hooks": [ { "type": "command", - "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pre-bash-zig-build.js" + "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pre-bash-guard.js" } ] } @@ -17,7 +17,7 @@ "hooks": [ { "type": "command", - "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit-zig-format.js" + "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/post-edit-format.js" } ] } diff --git a/.claude/skills/implementing-jsc-classes-rust/SKILL.md b/.claude/skills/implementing-jsc-classes-rust/SKILL.md new file mode 100644 index 000000000000..6dd76be69442 --- /dev/null +++ b/.claude/skills/implementing-jsc-classes-rust/SKILL.md @@ -0,0 +1,131 @@ +--- +name: implementing-jsc-classes-rust +description: Creates JavaScript classes using Bun's Rust bindings generator (.classes.ts). Use when implementing new JS APIs in Rust with JSC integration, prototypes, or constructors. +--- + +# Bun's JavaScriptCore Class Bindings Generator + +Bridge JavaScript and Rust through `.classes.ts` definitions and Rust implementations. + +## Architecture + +1. **JavaScript Interface Definition** (`.classes.ts` files) +2. **Rust Implementation** (`.rs` files) +3. **Generated Code** — `src/codegen/generate-classes.ts` emits C++ + Rust into `${BUN_CODEGEN_DIR}/generated_classes.rs`, `include!`d as `crate::generated_classes` in `bun_runtime`. Run `bun bd` to regenerate. + +## Class Definition (.classes.ts) + +```typescript +export default [ + define({ + name: "Glob", + construct: true, + finalize: true, + hasPendingActivity: true, + proto: { + scan: { fn: "scan", length: 1 }, + match: { fn: "match", length: 1 }, + }, + }), +]; +``` + +Options: + +- `construct`: Has a public `new Foo()` constructor +- `finalize`: Needs cleanup beyond `Drop` (rarely — see Finalize below) +- `hasPendingActivity`: GC keep-alive while async work is in flight +- `proto`: Methods (`fn:`), getters (`getter: true`, optionally `cache: true`) +- `values: [...]`: WriteBarrier slots for JS values the native side holds (callbacks, buffers) + +## Rust Implementation + +```rust +use bun_jsc::{CallFrame, JSGlobalObject, JSValue, JsResult}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[bun_jsc::JsClass] +pub struct Glob { + pattern: Box<[u8]>, + has_pending_activity: AtomicUsize, +} + +impl Glob { + pub fn constructor(global: &JSGlobalObject, frame: &CallFrame) -> JsResult> { + let arg = frame.argument(0); + let pattern = bun_core::String::from_js(arg, global)?.to_utf8_bytes().into(); + Ok(Box::new(Glob { pattern, has_pending_activity: AtomicUsize::new(0) })) + } + + #[bun_jsc::host_fn(method)] + pub fn r#match(&self, global: &JSGlobalObject, frame: &CallFrame) -> JsResult { + // ... + Ok(JSValue::TRUE) + } + + pub fn has_pending_activity(&self) -> bool { + self.has_pending_activity.load(Ordering::SeqCst) > 0 + } +} +``` + +### Canonical signatures + +| Hook | Signature | +| ------------------- | ------------------------------------------------------------------------------------ | +| constructor | `pub fn constructor(global: &JSGlobalObject, frame: &CallFrame) -> JsResult>` | +| method (`fn:`) | `pub fn name(&self, global: &JSGlobalObject, frame: &CallFrame) -> JsResult` | +| getter | `pub fn get_x(this: &Self, global: &JSGlobalObject) -> JsResult` | +| finalize | `pub fn finalize(self: Box)` — or omit; the blanket `JsFinalize` just drops | +| hasPendingActivity | `pub fn has_pending_activity(&self) -> bool` | + +A missing or mis-typed hook is a **compile error** in `cargo check -p bun_runtime` — the generated code calls the inherent method directly. + +## Hooking into the generated module + +`#[bun_jsc::JsClass]` on the struct implements the `JsClass` trait (`to_js`, `from_js`, `from_js_direct`, `get_constructor`) by binding the C++ externs. Attribute knobs: `no_constructor`, `no_finalize`, `estimated_size`. + +The codegen also emits a `js_$T` module with the cached-value accessors. Re-export it when you need `*_set_cached` / `*_get_cached` or `detach_ptr`: + +```rust +pub use crate::generated_classes::js_Glob as js; +// or +bun_jsc::impl_js_class_via_generated!(Archive => crate::generated_classes::js_Archive); +``` + +The `js_$T` module surface: + +```rust +pub fn from_js(value: JSValue) -> Option>; +pub fn from_js_direct(value: JSValue) -> Option>; +pub fn get_constructor(global: &JSGlobalObject) -> JSValue; +pub fn to_js(this: *mut T, global: &JSGlobalObject) -> JSValue; // ownership transfer +pub fn detach_ptr(value: JSValue); +// per cached getter / `values: [...]` entry: +pub fn _set_cached(this_value: JSValue, global: &JSGlobalObject, value: JSValue); +pub fn _get_cached(this_value: JSValue) -> Option; +``` + +## Finalize + +Most classes need nothing — `#[bun_jsc::JsClass]` wires the blanket `JsFinalize` whose default is `drop(Box)`. Override only when you must release a JS handle or defer to a heap helper: + +```rust +pub fn finalize(self: Box) { + bun_ptr::finalize_js_box(self, |this| this.this_value.with_mut(|v| v.finalize())); +} +``` + +Override with an **inherent** method, never `impl JsFinalize for T`. + +## Holding JS values + +Never store raw `JSValue` in a struct field. Declare a slot in `.classes.ts` (`values: ["callback"]` or a `cache: true` getter) and read/write it through `js::callback_set_cached(this_value, global, v)` / `js::callback_get_cached(this_value)`. The slot is a `WriteBarrier` visited by the GC, so the value stays alive without a `Strong`. + +## Reference implementations + +- `src/runtime/api/glob.rs` + `Glob.classes.ts` — constructor, methods, `hasPendingActivity`, default finalize +- `src/runtime/api/cron.rs` + `cron.classes.ts` — `noConstructor`, cached getter, `values: [...]`, custom finalize +- `src/runtime/image/Image.rs:56` — the `pub use crate::generated_classes::js_Image as js;` one-liner +- `src/jsc/host_fn.rs` — the host-fn adapters the codegen dispatches through +- `src/jsc_macros/lib.rs` — `#[bun_jsc::JsClass]` proc-macro source diff --git a/.claude/skills/implementing-jsc-classes-zig/SKILL.md b/.claude/skills/implementing-jsc-classes-zig/SKILL.md deleted file mode 100644 index d9077f8b0766..000000000000 --- a/.claude/skills/implementing-jsc-classes-zig/SKILL.md +++ /dev/null @@ -1,206 +0,0 @@ ---- -name: implementing-jsc-classes-zig -description: Creates JavaScript classes using Bun's Zig bindings generator (.classes.ts). Use when implementing new JS APIs in Zig with JSC integration. ---- - -# Bun's JavaScriptCore Class Bindings Generator - -Bridge JavaScript and Zig through `.classes.ts` definitions and Zig implementations. - -## Architecture - -1. **Zig Implementation** (.zig files) -2. **JavaScript Interface Definition** (.classes.ts files) -3. **Generated Code** (C++/Zig files connecting them) - -## Class Definition (.classes.ts) - -```typescript -define({ - name: "TextDecoder", - constructor: true, - JSType: "object", - finalize: true, - proto: { - decode: { args: 1 }, - encoding: { getter: true, cache: true }, - fatal: { getter: true }, - }, -}); -``` - -Options: - -- `name`: Class name -- `constructor`: Has public constructor -- `JSType`: "object", "function", etc. -- `finalize`: Needs cleanup -- `proto`: Properties/methods -- `cache`: Cache property values via WriteBarrier - -## Zig Implementation - -```zig -pub const TextDecoder = struct { - pub const js = JSC.Codegen.JSTextDecoder; - pub const toJS = js.toJS; - pub const fromJS = js.fromJS; - pub const fromJSDirect = js.fromJSDirect; - - encoding: []const u8, - fatal: bool, - - pub fn constructor( - globalObject: *JSGlobalObject, - callFrame: *JSC.CallFrame, - ) bun.JSError!*TextDecoder { - return bun.new(TextDecoder, .{ .encoding = "utf-8", .fatal = false }); - } - - pub fn decode( - this: *TextDecoder, - globalObject: *JSGlobalObject, - callFrame: *JSC.CallFrame, - ) bun.JSError!JSC.JSValue { - const args = callFrame.arguments(); - if (args.len < 1 or args.ptr[0].isUndefinedOrNull()) { - return globalObject.throw("Input cannot be null", .{}); - } - return JSC.JSValue.jsString(globalObject, "result"); - } - - pub fn getEncoding(this: *TextDecoder, globalObject: *JSGlobalObject) JSC.JSValue { - return JSC.JSValue.createStringFromUTF8(globalObject, this.encoding); - } - - fn deinit(this: *TextDecoder) void { - // Release resources - } - - pub fn finalize(this: *TextDecoder) void { - this.deinit(); - bun.destroy(this); - } -}; -``` - -**Key patterns:** - -- Use `bun.JSError!JSValue` return type for error handling -- Use `globalObject` not `ctx` -- `deinit()` for cleanup, `finalize()` called by GC -- Update `src/jsc/bindings/generated_classes_list.zig` - -## CallFrame Access - -```zig -const args = callFrame.arguments(); -const first_arg = args.ptr[0]; // Access as slice -const argCount = args.len; -const thisValue = callFrame.thisValue(); -``` - -## Property Caching - -For `cache: true` properties, generated accessors: - -```zig -// Get cached value -pub fn encodingGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { - const result = TextDecoderPrototype__encodingGetCachedValue(thisValue); - if (result == .zero) return null; - return result; -} - -// Set cached value -pub fn encodingSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { - TextDecoderPrototype__encodingSetCachedValue(thisValue, globalObject, value); -} -``` - -## Error Handling - -```zig -pub fn method(this: *MyClass, globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue { - const args = callFrame.arguments(); - if (args.len < 1) { - return globalObject.throw("Missing required argument", .{}); - } - return JSC.JSValue.jsString(globalObject, "Success!"); -} -``` - -## Memory Management - -```zig -pub fn deinit(this: *TextDecoder) void { - this._encoding.deref(); - if (this.buffer) |buffer| { - bun.default_allocator.free(buffer); - } -} - -pub fn finalize(this: *TextDecoder) void { - JSC.markBinding(@src()); - this.deinit(); - bun.default_allocator.destroy(this); -} -``` - -## Creating a New Binding - -1. Define interface in `.classes.ts`: - -```typescript -define({ - name: "MyClass", - constructor: true, - finalize: true, - proto: { - myMethod: { args: 1 }, - myProperty: { getter: true, cache: true }, - }, -}); -``` - -2. Implement in `.zig`: - -```zig -pub const MyClass = struct { - pub const js = JSC.Codegen.JSMyClass; - pub const toJS = js.toJS; - pub const fromJS = js.fromJS; - - value: []const u8, - - pub const new = bun.TrivialNew(@This()); - - pub fn constructor(globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!*MyClass { - return MyClass.new(.{ .value = "" }); - } - - pub fn myMethod(this: *MyClass, globalObject: *JSGlobalObject, callFrame: *JSC.CallFrame) bun.JSError!JSC.JSValue { - return JSC.JSValue.jsUndefined(); - } - - pub fn getMyProperty(this: *MyClass, globalObject: *JSGlobalObject) JSC.JSValue { - return JSC.JSValue.jsString(globalObject, this.value); - } - - pub fn deinit(this: *MyClass) void {} - - pub fn finalize(this: *MyClass) void { - this.deinit(); - bun.destroy(this); - } -}; -``` - -3. Add to `src/jsc/bindings/generated_classes_list.zig` - -## Generated Components - -- **C++ Classes**: `JSMyClass`, `JSMyClassPrototype`, `JSMyClassConstructor` -- **Method Bindings**: `MyClassPrototype__myMethodCallback` -- **Property Accessors**: `MyClassPrototype__myPropertyGetterWrap` -- **Zig Bindings**: External function declarations, cached value accessors diff --git a/.claude/skills/javascriptcore-garbage-collector/SKILL.md b/.claude/skills/javascriptcore-garbage-collector/SKILL.md index 93df2e2ab35e..79b075187e10 100644 --- a/.claude/skills/javascriptcore-garbage-collector/SKILL.md +++ b/.claude/skills/javascriptcore-garbage-collector/SKILL.md @@ -97,7 +97,7 @@ if (obj->cellState <= blackThreshold) // 0 normally, bumped while GC is markin `vendor/WebKit/Source/JavaScriptCore/heap/ConservativeRoots.cpp` walks the native stack/registers word-by-word (after `MachineThreads::tryCopyOtherThreadStacks` snapshots them). Any aligned word inside a live `MarkedBlock` cell or `PreciseAllocation` is a root. -**This means:** a `JSCell*` / `JSValue` in a C++/Zig local variable _usually_ keeps the object alive — no `Handle`/`Local` ceremony like V8. +**This means:** a `JSCell*` / `JSValue` in a C++/Rust local variable _usually_ keeps the object alive — no `Handle`/`Local` ceremony like V8. **This does NOT mean you're always safe.** The compiler may dead-store-eliminate the local after its last visible use, or never spill it. If you extract an interior pointer (`string->characters8()`, butterfly storage, typed-array `vector()`) and then call something that can allocate, the original cell may no longer be on the stack: @@ -106,7 +106,7 @@ JSC::EnsureStillAliveScope keepAlive(cell); // RAII: forces cell onto stack un // ... use interior pointer, call things that allocate ... ``` -or `ensureStillAliveHere(cell)`. In Zig: `value.ensureStillAlive()`. +or `ensureStillAliveHere(cell)`. In Rust: `value.ensure_still_alive()`. ## `visitChildren` — the per-cell tracing hook @@ -213,37 +213,37 @@ JSC::Weak m_wrapper { jsFoo, &myOwnerSingleton, nativeThing }; `Weak` is **move-only** (allocates a `WeakImpl`). Don't put it in a hot path; cache it. -## Zig: `jsc.JSRef` — the native↔wrapper reference pattern +## `JSRef` — the native↔wrapper reference pattern -In Bun's Zig code, when a native object needs to hold a reference back to its own JS wrapper, **use `jsc.JSRef`** (`src/jsc/bindings/JSRef.zig`), not `gcProtect`, not a raw `JSValue` field, and usually not `jsc.Strong` directly. +When a native object needs to hold a reference back to its own JS wrapper, **use `JSRef`** (`src/jsc/JSRef.rs`), not `gcProtect`, not a raw `JSValue` field, and usually not `Strong` directly. `JSRef` is a tagged union with three states: -- `.weak` — a bare `JSValue`. Does **not** keep the wrapper alive. Valid only because the wrapper's `finalize()` will flip this to `.finalized` before the cell is freed, so `tryGet()` returns `null` instead of a dangling pointer. (This is _not_ a `JSC::Weak`; it's cheaper — no `WeakImpl` allocation.) -- `.strong` — wraps `jsc.Strong` (a `JSC::Strong` root). Keeps the wrapper alive. -- `.finalized` — terminal; `tryGet()` returns `null`. +- `Weak` — a bare `JSValue`. Does **not** keep the wrapper alive. Valid only because the wrapper's `finalize()` will flip this to `Finalized` before the cell is freed, so `try_get()` returns `None` instead of a dangling pointer. (This is _not_ a `JSC::Weak`; it's cheaper — no `WeakImpl` allocation.) +- `Strong` — wraps `bun_jsc::Strong` (a `JSC::Strong` root). Keeps the wrapper alive. +- `Finalized` — terminal; `try_get()` returns `None`. Pattern: **strong while busy, weak while idle.** -```zig -this_value: jsc.JSRef = .empty(), +```rust +this_value: JSRef, // initialized with JSRef::empty() // On construction / when work starts: -this.this_value.setStrong(js_wrapper, globalThis); // or .upgrade(globalThis) +self.this_value.set_strong(js_wrapper, global); // or .upgrade(global) // When the last in-flight operation completes: -this.this_value.downgrade(); // strong → weak, GC may now collect +self.this_value.downgrade(); // Strong -> Weak, GC may now collect // In any callback that needs the wrapper: -const js_this = this.this_value.tryGet() orelse return; +let Some(js_this) = self.this_value.try_get() else { return }; // In the codegen'd finalize(): -this.this_value.finalize(); +self.this_value.finalize(); ``` See `ServerWebSocket`, `UDPSocket`, `MySQLConnection`, `ValkeyClient` for real examples. -**`JSRef` requires a finalizer.** The `.weak` state is only sound because the codegen'd `finalize()` flips it to `.finalized` before the cell is reused. If your `.classes.ts` entry has `finalize: true` (almost all native-backed classes do), `JSRef` is the default choice for self-references. +**`JSRef` requires a finalizer.** The `Weak` state is only sound because the codegen'd `finalize()` flips it to `Finalized` before the cell is reused. If your `.classes.ts` entry has `finalize: true` (almost all native-backed classes do), `JSRef` is the default choice for self-references. **`JSRef` vs `hasPendingActivity`:** prefer `JSRef`. `hasPendingActivity: true` is a GC-thread-polled atomic predicate; its only real justification is when **many concurrent operations** independently keep the wrapper alive and there's no single place to call `upgrade()`/`downgrade()` — i.e., refcount-style liveness where the count is touched from multiple threads. That's uncommon. If you can identify "work started" / "work finished" edges, use `JSRef`. Don't add `hasPendingActivity` reflexively; it costs a constraint-fixpoint poll on every GC. @@ -253,7 +253,7 @@ See `ServerWebSocket`, `UDPSocket`, `MySQLConnection`, `ValkeyClient` for real e - It's a raw global root with manual unprotect — easy to leak. - It has no owner, so heap snapshots can't attribute the retention. -- `jsc.Strong` / `JSRef` give the same guarantee with RAII and a destructor. +- `bun_jsc::Strong` / `JSRef` give the same guarantee with RAII and a destructor. The only legitimate uses are inside the JSC C API shims themselves, or one-off debugging. @@ -276,7 +276,7 @@ visitor.reportExtraMemoryVisited(thisObject->wrapped().byteSize()); - If the size changes over time, report the delta on growth (`reportExtraMemoryAllocated(cell, newSize - oldSize)`) and report the current size in `visitChildren`. - `deprecatedReportExtraMemory` exists for callers that can't satisfy the visit-side half — avoid it. -In `.classes.ts`, `estimatedSize: true` generates the `reportExtraMemoryVisited` side; you implement `estimatedSize()` in Zig. You still call `reportExtraMemoryAllocated` (or the binding's helper) at allocation time. +In `.classes.ts`, `estimatedSize: true` generates the `reportExtraMemoryVisited` side; you implement `estimated_size()` in Rust. You still call `reportExtraMemoryAllocated` (or the binding's helper) at allocation time. ## `HeapAnalyzer` — heap snapshots and labelling @@ -305,25 +305,25 @@ If your class shows up as an opaque blob in heap snapshots, implement `analyzeHe ## How to keep things alive (decision table) -| Scenario | Mechanism | -| ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| JSCell field pointing to another JSCell | `WriteBarrier` member + `visitor.append(m_field)` in `visitChildren` | -| Native state inside the wrapped C++ object holds JS values | `visitAdditionalChildren` + register subspace as output-constraint | -| C++/Zig local across allocation/call | Conservative scan (free) — add `EnsureStillAliveScope` / `value.ensureStillAlive()` if extracting interior pointers or seeing release-only crashes | -| **Zig** native object holds its own JS wrapper (class has `finalize: true`) | **`jsc.JSRef`** — `upgrade()` when work starts, `downgrade()` when idle. **This is the default.** | -| **Zig** native object owns an arbitrary JS value (callback, options object) | `jsc.Strong.Optional` — `deinit()` in `finalize()`. Watch for cycles | -| C++ non-GC object owns a JS value as a root | `JSC::Strong`. **Danger:** cycle if the JS value can reach back → leak | -| Weak ref with resurrection predicate / finalize callback (C++) | `JSC::Weak` + `WeakHandleOwner` | -| Wrapper kept alive by **many concurrent operations** with no single busy/idle edge | `.classes.ts` `hasPendingActivity: true` (atomic flag polled on GC thread). **Uncommon — prefer `JSRef` if you can.** | -| Group of wrappers share lifetime via a native graph | `visitor.addOpaqueRoot(ptr)` + `containsOpaqueRoot(ptr)` | -| Temporarily forbid GC in a critical section | `DeferGC deferGC(vm)` — defers until scope exit. Never hold across user JS | -| Tell GC about off-heap memory you own | `reportExtraMemoryAllocated` on alloc **and** `reportExtraMemoryVisited` in `visitChildren` | -| ~~Mark a value as root from C API~~ | ~~`gcProtect` / `JSValueProtect`~~ — **avoid**; use `jsc.Strong` / `JSRef` instead | +| Scenario | Mechanism | +| ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| JSCell field pointing to another JSCell | `WriteBarrier` member + `visitor.append(m_field)` in `visitChildren` | +| Native state inside the wrapped C++ object holds JS values | `visitAdditionalChildren` + register subspace as output-constraint | +| C++/Rust local across allocation/call | Conservative scan (free) — add `EnsureStillAliveScope` / `value.ensure_still_alive()` if extracting interior pointers or seeing release-only crashes | +| Native object holds its own JS wrapper (class has `finalize: true`) | **`JSRef`** — `upgrade()` when work starts, `downgrade()` when idle. **This is the default.** | +| Native object owns an arbitrary JS value (callback, options object) | `bun_jsc::Strong` — drop in `finalize()`. Watch for cycles | +| C++ non-GC object owns a JS value as a root | `JSC::Strong`. **Danger:** cycle if the JS value can reach back → leak | +| Weak ref with resurrection predicate / finalize callback (C++) | `JSC::Weak` + `WeakHandleOwner` | +| Wrapper kept alive by **many concurrent operations** with no single busy/idle edge | `.classes.ts` `hasPendingActivity: true` (atomic flag polled on GC thread). **Uncommon — prefer `JSRef` if you can.** | +| Group of wrappers share lifetime via a native graph | `visitor.addOpaqueRoot(ptr)` + `containsOpaqueRoot(ptr)` | +| Temporarily forbid GC in a critical section | `DeferGC deferGC(vm)` — defers until scope exit. Never hold across user JS | +| Tell GC about off-heap memory you own | `reportExtraMemoryAllocated` on alloc **and** `reportExtraMemoryVisited` in `visitChildren` | +| ~~Mark a value as root from C API~~ | ~~`gcProtect` / `JSValueProtect`~~ — **avoid**; use `bun_jsc::Strong` / `JSRef` instead | ## Destruction & finalizers - `static constexpr bool needsDestruction = true` → C++ destructor runs when the cell is swept. Sweep is **lazy** (next allocation from that block, or `IncrementalSweeper`), so destruction is delayed arbitrarily. Do not rely on it for prompt resource release — expose explicit `close()`/`dispose()`. -- In `.classes.ts`, `finalize: true` → Zig `finalize()` called from the destructor. Same laziness applies. +- In `.classes.ts`, `finalize: true` → native `finalize()` called from the destructor. Same laziness applies. - `WeakHandleOwner::finalize` runs earlier (at weak-reap time) but the cell is already dead; only use it to clear caches. - Destructors run on the mutator thread but **other JS objects may already be swept** — do not dereference `WriteBarrier` fields in a destructor. diff --git a/.claude/skills/rust-system-calls/SKILL.md b/.claude/skills/rust-system-calls/SKILL.md new file mode 100644 index 000000000000..461c93429d7a --- /dev/null +++ b/.claude/skills/rust-system-calls/SKILL.md @@ -0,0 +1,96 @@ +--- +name: rust-system-calls +description: Guides using bun_sys for system calls and file I/O in Rust. Use when implementing file operations, opening fds, or any syscall path instead of std::fs or libc. +--- + +# System Calls & File I/O in Rust + +Use `bun_sys` instead of `std::fs` or raw `libc` for cross-platform syscalls with proper error handling. + +## bun_sys::File (Preferred) + +For most file operations, use the `bun_sys::File` wrapper. It owns the fd and closes on `Drop`. + +```rust +use bun_sys::{File, Fd, O}; + +let file = File::openat(Fd::cwd(), b"path/to/file", O::RDONLY, 0)?; +let mut buf = vec![0u8; 4096]; +let n = file.read_all(&mut buf)?; // loops until EOF or full +// `file` closes on Drop. +``` + +### Complete Example + +```rust +use bun_sys::{File, Fd, O}; + +pub fn write_file(path: &[u8], data: &[u8]) -> Result<(), bun_sys::Error> { + let file = File::openat(Fd::cwd(), path, O::WRONLY | O::CREAT | O::TRUNC, 0o664)?; + file.write_all(data)?; + Ok(()) +} +``` + +## Why bun_sys? + +| Aspect | bun_sys | std::fs / libc | +| ----------- | ---------------------------------- | ---------------------- | +| Return Type | `Maybe` with rich `Error` | `io::Error` (lossy) | +| Windows | Full support with libuv fallback | Incomplete/POSIX-ish | +| Error Info | errno, syscall tag, path, fd | errno only | +| EINTR | Automatic retry | Manual handling | +| Paths | `&[u8]` (WTF-8 safe) | `&Path` (UTF-8 lossy) | + +## Error Handling with Maybe + +`bun_sys` functions return `Maybe = Result`. Propagate with `?`; convert to a JS exception via `bun_sys_jsc::ErrorJsc::to_js`: + +```rust +use bun_sys_jsc::ErrorJsc; +use bun_sys::{File, Fd, O}; + +let file = match File::openat(Fd::cwd(), path, O::RDONLY, 0) { + Ok(f) => f, + Err(err) => return Ok(err.to_js(global)?), +}; +``` + +`bun_sys::Error` carries `errno`, `syscall: Tag`, and `path: Box<[u8]>`. To branch on errno: + +```rust +match bun_sys::unlink(path) { + Ok(()) => {} + Err(e) if e.errno() == bun_c::ENOENT => {} // already gone + Err(e) => return Err(e), +} +``` + +## Key Types and Functions + +- `Fd` (`bun_core::Fd`) — cross-platform file descriptor. `Fd::cwd()`, `Fd::stdin()/stdout()/stderr()`, `fd.close()`. +- `File::open(path: &ZStr, flags, mode)` / `File::openat(dir: Fd, path: &[u8], flags, mode)` / `File::make_open(...)` (creates parent dirs) / `File::create(dir, path, truncate)` +- `file.read(buf)` / `read_all(buf)` / `read_to_end()` / `read_to_end_small()` / `write(buf)` / `write_all(buf)` +- `bun_sys::open`, `read`, `write`, `pread`, `pwrite`, `stat`, `fstat`, `lstat`, `mkdir`, `unlink`, `rename`, `symlink`, `chmod` — free fns over `Fd` +- Open flags: `bun_sys::O::RDONLY`, `O::WRONLY | O::CREAT | O::TRUNC`, etc. + +## Path Buffers + +Use `bun_paths` for joining/normalization and the path-buffer pool to avoid 64 KB stack allocations on Windows: + +```rust +use bun_paths::{path_buffer_pool, resolve_path::{self, platform}}; + +let mut buf = path_buffer_pool::get(); +let joined = resolve_path::join_string_buf::(&mut *buf, &[dir, name]); +let file = File::openat(Fd::cwd(), joined, O::RDONLY, 0)?; +``` + +## Common Mistakes + +- **Don't `.unwrap()`** a `bun_sys` result that user input or the OS can cause to fail at runtime — return the error. +- **Don't use `std::fs::File`** — it loses the syscall tag and path needed for Node-compatible error objects. +- **Don't allocate `PathBuffer` on the stack** in hot paths — use `path_buffer_pool::get()`. +- **Don't forget `Drop`** alone closes a `File` — never `file.fd().close()` while the `File` is still live (double close). + +See `src/CLAUDE.md` for the full `bun_core`/`bun_sys` reference. diff --git a/.claude/skills/zig-system-calls/SKILL.md b/.claude/skills/zig-system-calls/SKILL.md deleted file mode 100644 index 48f179463a4f..000000000000 --- a/.claude/skills/zig-system-calls/SKILL.md +++ /dev/null @@ -1,268 +0,0 @@ ---- -name: zig-system-calls -description: Guides using bun.sys for system calls and file I/O in Zig. Use when implementing file operations instead of std.fs or std.posix. ---- - -# System Calls & File I/O in Zig - -Use `bun.sys` instead of `std.fs` or `std.posix` for cross-platform syscalls with proper error handling. - -## bun.sys.File (Preferred) - -For most file operations, use the `bun.sys.File` wrapper: - -```zig -const File = bun.sys.File; - -const file = switch (File.open(path, bun.O.RDWR, 0o644)) { - .result => |f| f, - .err => |err| return .{ .err = err }, -}; -defer file.close(); - -// Read/write -_ = try file.read(buffer).unwrap(); -_ = try file.writeAll(data).unwrap(); - -// Get file info -const stat = try file.stat().unwrap(); -const size = try file.getEndPos().unwrap(); - -// std.io compatible -const reader = file.reader(); -const writer = file.writer(); -``` - -### Complete Example - -```zig -const File = bun.sys.File; - -pub fn writeFile(path: [:0]const u8, data: []const u8) File.WriteError!void { - const file = switch (File.open(path, bun.O.WRONLY | bun.O.CREAT | bun.O.TRUNC, 0o664)) { - .result => |f| f, - .err => |err| return err.toError(), - }; - defer file.close(); - - _ = switch (file.writeAll(data)) { - .result => {}, - .err => |err| return err.toError(), - }; -} -``` - -## Why bun.sys? - -| Aspect | bun.sys | std.fs/std.posix | -| ----------- | -------------------------------- | ------------------- | -| Return Type | `Maybe(T)` with detailed Error | Generic error union | -| Windows | Full support with libuv fallback | Limited/POSIX-only | -| Error Info | errno, syscall tag, path, fd | errno only | -| EINTR | Automatic retry | Manual handling | - -## Error Handling with Maybe(T) - -`bun.sys` functions return `Maybe(T)` - a tagged union: - -```zig -const sys = bun.sys; - -// Pattern 1: Switch on result/error -switch (sys.read(fd, buffer)) { - .result => |bytes_read| { - // use bytes_read - }, - .err => |err| { - // err.errno, err.syscall, err.fd, err.path - if (err.getErrno() == .AGAIN) { - // handle EAGAIN - } - }, -} - -// Pattern 2: Unwrap with try (converts to Zig error) -const bytes = try sys.read(fd, buffer).unwrap(); - -// Pattern 3: Unwrap with default -const value = sys.stat(path).unwrapOr(default_stat); -``` - -## Low-Level File Operations - -Only use these when `bun.sys.File` doesn't meet your needs. - -### Opening Files - -```zig -const sys = bun.sys; - -// Use bun.O flags (cross-platform normalized) -const fd = switch (sys.open(path, bun.O.RDONLY, 0)) { - .result => |fd| fd, - .err => |err| return .{ .err = err }, -}; -defer fd.close(); - -// Common flags -bun.O.RDONLY, bun.O.WRONLY, bun.O.RDWR -bun.O.CREAT, bun.O.TRUNC, bun.O.APPEND -bun.O.NONBLOCK, bun.O.DIRECTORY -``` - -### Reading & Writing - -```zig -// Single read (may return less than buffer size) -switch (sys.read(fd, buffer)) { - .result => |n| { /* n bytes read */ }, - .err => |err| { /* handle error */ }, -} - -// Read until EOF or buffer full -const total = try sys.readAll(fd, buffer).unwrap(); - -// Position-based read/write -sys.pread(fd, buffer, offset) -sys.pwrite(fd, data, offset) - -// Vector I/O -sys.readv(fd, iovecs) -sys.writev(fd, iovecs) -``` - -### File Info - -```zig -sys.stat(path) // Follow symlinks -sys.lstat(path) // Don't follow symlinks -sys.fstat(fd) // From file descriptor -sys.fstatat(fd, path) - -// Linux-only: faster selective stat -sys.statx(path, &.{ .size, .mtime }) -``` - -### Path Operations - -```zig -sys.unlink(path) -sys.unlinkat(dir_fd, path) -sys.rename(from, to) -sys.renameat(from_dir, from, to_dir, to) -sys.readlink(path, buf) -sys.readlinkat(fd, path, buf) -sys.link(T, src, dest) -sys.linkat(src_fd, src, dest_fd, dest) -sys.symlink(target, dest) -sys.symlinkat(target, dirfd, dest) -sys.mkdir(path, mode) -sys.mkdirat(dir_fd, path, mode) -sys.rmdir(path) -``` - -### Permissions - -```zig -sys.chmod(path, mode) -sys.fchmod(fd, mode) -sys.fchmodat(fd, path, mode, flags) -sys.chown(path, uid, gid) -sys.fchown(fd, uid, gid) -``` - -### Closing File Descriptors - -Close is on `bun.FD`: - -```zig -fd.close(); // Asserts on error (use in defer) - -// Or if you need error info: -if (fd.closeAllowingBadFileDescriptor(null)) |err| { - // handle error -} -``` - -## Directory Operations - -```zig -var buf: bun.PathBuffer = undefined; -const cwd = try sys.getcwd(&buf).unwrap(); -const cwdZ = try sys.getcwdZ(&buf).unwrap(); // Zero-terminated -sys.chdir(path, destination) -``` - -### Directory Iteration - -Use `bun.DirIterator` instead of `std.fs.Dir.Iterator`: - -```zig -var iter = bun.iterateDir(dir_fd); -while (true) { - switch (iter.next()) { - .result => |entry| { - if (entry) |e| { - const name = e.name.slice(); - const kind = e.kind; // .file, .directory, .sym_link, etc. - } else { - break; // End of directory - } - }, - .err => |err| return .{ .err = err }, - } -} -``` - -## Socket Operations - -**Important**: `bun.sys` has limited socket support. For network I/O: - -- **Non-blocking sockets**: Use `uws.Socket` (libuwebsockets) exclusively -- **Pipes/blocking I/O**: Use `PipeReader.zig` and `PipeWriter.zig` - -Available in bun.sys: - -```zig -sys.setsockopt(fd, level, optname, value) -sys.socketpair(domain, socktype, protocol, nonblocking_status) -``` - -Do NOT use `bun.sys` for socket read/write - use `uws.Socket` instead. - -## Other Operations - -```zig -sys.ftruncate(fd, size) -sys.lseek(fd, offset, whence) -sys.dup(fd) -sys.dupWithFlags(fd, flags) -sys.fcntl(fd, cmd, arg) -sys.pipe() -sys.mmap(...) -sys.munmap(memory) -sys.access(path, mode) -sys.futimens(fd, atime, mtime) -sys.utimens(path, atime, mtime) -``` - -## Error Type - -```zig -const err: bun.sys.Error = ...; -err.errno // Raw errno value -err.getErrno() // As std.posix.E enum -err.syscall // Which syscall failed (Tag enum) -err.fd // Optional: file descriptor -err.path // Optional: path string -``` - -## Key Points - -- Prefer `bun.sys.File` wrapper for most file operations -- Use low-level `bun.sys` functions only when needed -- Use `bun.O.*` flags instead of `std.os.O.*` -- Handle `Maybe(T)` with switch or `.unwrap()` -- Use `defer fd.close()` for cleanup -- EINTR is handled automatically in most functions -- For sockets, use `uws.Socket` not `bun.sys` diff --git a/.dockerignore b/.dockerignore index d76783768281..8a20dcd0c83d 100644 --- a/.dockerignore +++ b/.dockerignore @@ -10,9 +10,6 @@ packages/**/bun packages/**/bun-profile src/bun.js/WebKit src/bun.js/WebKit/LayoutTests -zig-build -.zig-cache -zig-out build vendor node_modules diff --git a/.gitattributes b/.gitattributes index a049d004f441..3918f44f7b9a 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8,7 +8,6 @@ *.cc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 *.yml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 *.toml text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 -*.zig text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 *.rs text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 *.h text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 *.json text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2 @@ -33,7 +32,6 @@ src/api/schema.js linguist-generated src/jsc/bindings/ZigGeneratedCode.h linguist-generated src/jsc/bindings/ZigGeneratedCode.cpp linguist-generated src/jsc/bindings/headers.h linguist-generated -src/jsc/bindings/headers.zig linguist-generated packages/bun-uws/fuzzing/seed-corpus/**/* linguist-generated diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 1c8e2a68fafd..5e96c0d3c9ae 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -106,9 +106,6 @@ jobs: fi echo "✅ All formatters completed successfully" - - name: Ban Words - run: | - bun ./test/internal/ban-words.test.ts - name: Verify checked-in codegen # `*.generated.rs` are deterministic outputs of `*.string-map.ts`; the # source `.ts` is the truth. This step regenerates and fails if the diff --git a/.gitignore b/.gitignore index d2fa1d6a6218..489f42e901b7 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,6 @@ Library/Caches .vs .vscode/clang* .vscode/cpp* -.zig-cache .bake-debug *.a *.bc @@ -64,7 +63,6 @@ Library/Caches /test-report.md /test.js /test.ts -/test.zig /testdir /build/ cmake/sources @@ -127,15 +125,8 @@ scripts/env.local sign.*.json sign.json src/bake/generated.ts -src/generated_enum_extractor.zig src/jsc/bindings-obj -src/jsc/bindings/GeneratedJS2Native.zig -src/jsc/bindings/GeneratedBindings.zig src/bun.js/debug-bindings-obj -src/deps/zig-clap/.gitattributes -src/deps/zig-clap/.github -src/deps/zig-clap/example -src/deps/zig-clap/README.md src/fallback.version src/js/out/DebugPath.h src/js/out/functions* @@ -144,7 +135,6 @@ src/js/out/tmp src/node-fallbacks/node_modules src/node-fallbacks/out/* src/runtime.version -src/tests.zig test.txt test/js/bun/glob/fixtures test/node.js/upstream @@ -152,10 +142,7 @@ tsconfig.tsbuildinfo txt.js x64 yarn.lock -zig-cache -zig-out test/node.js/upstream -.zig-cache scripts/env.local *.generated.ts src/bake/generated.ts @@ -207,3 +194,7 @@ test/integration/bun-types/fixture/bun.lock src/runtime/bake/generated.ts /target/ *.heapsnapshot +# Legacy codegen outputs (no longer written, but old build trees still have +# them on disk; keep ignored so they don't show as untracked). +src/jsc/bindings/GeneratedJS2Native.zig +src/jsc/bindings/GeneratedBindings.zig diff --git a/.vscode/launch.json b/.vscode/launch.json index 0c76e4cfcc34..5bfff0be2caf 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -343,7 +343,6 @@ "setupCommands": [ "handle SIGPWR nostop noprint pass", "source ${workspaceFolder}/misctools/gdb/std_gdb_pretty_printers.py", - "source ${workspaceFolder}/misctools/gdb/zig_gdb_pretty_printers.py", "set substitute-path /webkitbuild/vendor/WebKit ${workspaceFolder}/vendor/WebKit", "set substitute-path /webkitbuild/.WTF/Headers ${workspaceFolder}/vendor/WebKit/Source/WTF", // uncomment if you like diff --git a/.vscode/settings.json b/.vscode/settings.json index 826070d42b8c..4298099c2f49 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -26,32 +26,6 @@ "git.ignoreSubmodules": true, "git.ignoreLimitWarning": true, - // Zig - // "zig.initialSetupDone": true, - // "zig.buildOption": "build", - "zig.zls.zigLibPath": "${workspaceFolder}/vendor/zig/lib", - "zig.buildOnSaveArgs": [ - "-Dgenerated-code=./build/debug/codegen", - "--watch", - "-fincremental" - ], - // "zig.zls.buildOnSaveStep": "check", - // "zig.zls.enableBuildOnSave": true, - // "zig.buildOnSave": true, - // "zig.buildFilePath": "${workspaceFolder}/build.zig", - "zig.path": "${workspaceFolder}/vendor/zig/zig.exe", - "zig.zls.path": "${workspaceFolder}/vendor/zig/zls.exe", - "zig.formattingProvider": "zls", - // "zig.zls.enableInlayHints": false, - "[zig]": { - "editor.tabSize": 4, - "editor.useTabStops": false, - "editor.defaultFormatter": "ziglang.vscode-zig", - "editor.codeActionsOnSave": { - "source.organizeImports": "never", - }, - }, - // lldb "lldb.launch.initCommands": ["command source ${workspaceFolder}/.lldbinit"], "lldb.verboseLogging": false, diff --git a/CLAUDE.md b/CLAUDE.md index 4bee5917712d..1ab043f406e6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -114,8 +114,6 @@ test("(multi-file test) my feature", async () => { - **TypeScript** (`src/js/`): Built-in JavaScript modules with special syntax (see JavaScript Modules section) - **Generated code**: Many `.rs` and `.cpp` files are auto-generated from `.classes.ts` and other sources. The build regenerates them automatically when their inputs change. -You will see `.zig` files alongside many `.rs` files (e.g. `fetch.zig` next to `fetch.rs`). These are the **original Zig implementation, kept only as a porting reference** — they are **not compiled** and **not shipped**. New code goes in `.rs`. When fixing a bug or porting a behavior, the `.zig` sibling is the source of truth for *intended semantics*: read it, then make the `.rs` match. Never add new behavior to a `.zig` file. - ### Core Source Organization The Rust side is a Cargo workspace of ~200 crates rooted at `Cargo.toml`. The key ones: @@ -147,7 +145,7 @@ The Rust side is a Cargo workspace of ~200 crates rooted at `Cargo.toml`. The ke #### Vendored Dependencies (`vendor/`) -Third-party C/C++ libraries are vendored locally and can be read from disk (not git submodules): boringssl (TLS/crypto), brotli, cares (async DNS), hdrhistogram, highway (SIMD), libarchive (tar/zip), libdeflate, libuv (Windows event loop), lolhtml (HTML rewriter), lshpack (HTTP/2 HPACK), lsqpack + lsquic (HTTP/3), mimalloc (allocator), nodejs (headers), picohttpparser, tinycc (FFI JIT, fork: oven-sh/tinycc), WebKit (JavaScriptCore), zig (legacy toolchain, unused by the Rust build), zlib (zlib-ng), zstd. Build configuration for these is in `scripts/build/deps/*.ts`. +Third-party C/C++ libraries are vendored locally and can be read from disk (not git submodules): boringssl (TLS/crypto), brotli, cares (async DNS), hdrhistogram, highway (SIMD), libarchive (tar/zip), libdeflate, libuv (Windows event loop), lolhtml (HTML rewriter), lshpack (HTTP/2 HPACK), lsqpack + lsquic (HTTP/3), mimalloc (allocator), nodejs (headers), picohttpparser, tinycc (FFI JIT, fork: oven-sh/tinycc), WebKit (JavaScriptCore), zlib (zlib-ng), zstd. Build configuration for these is in `scripts/build/deps/*.ts`. ### JavaScript Class Implementation (C++) @@ -217,7 +215,7 @@ Several situational sections live in `.claude/docs/landing-prs.md` — read the - **Fix the whole class in the same PR** (same-class sites are ONE concern, not scope creep). Grep for every sibling site sharing the pattern: parallel switch arms, sync/async twins, fast/slow paths, POSIX/Windows branches, SSL/non-SSL variants, copy-pasted blocks, every caller of a changed helper. Prefer moving the guard into the shared helper. If a site is intentionally excluded, say so in the PR. - **Enumerate the input space deliberately.** Empty input, lone `.`, delimiter-only, inputs that become empty after processing, CRLF, IPv6 literals, integer max, every accepted spelling of an option. Treat "empty", "zero", and "unset" as three distinct states — gate on presence, not truthiness. Use real parsers, never prefix-stripping or regex heuristics over user-controlled input. When tightening validation, enumerate every legitimate input class and prove each still passes. - **Every line you add must be demonstrably live.** Trace any flag you gate on through every context that sets it; trace new state to an actual consumer — parsed-but-never-read is a red flag; check for an unconditional overwrite after a new conditional; manually exercise the failure path of any checker whose purpose is to fail. Delete defensive code only when you can show the condition cannot occur; when a new assertion trips, fix the violating call sites. -- **Verify semantics empirically, never from names or intuition.** Read the implementation of every helper, macro, and sentinel you rely on. For protocols, derive behavior from the spec and cite the upstream source line for every magic number. For ported code, the reference implementation (esbuild, the `.zig` siblings, Node) is the spec — diff control flow against it before "fixing" apparent bugs. For codecs, a self-round-trip proves nothing — validate against external known-answer vectors. Settle behavioral disputes by running the scenario. +- **Verify semantics empirically, never from names or intuition.** Read the implementation of every helper, macro, and sentinel you rely on. For protocols, derive behavior from the spec and cite the upstream source line for every magic number. For ported code, the reference implementation (esbuild, Node) is the spec — diff control flow against it before "fixing" apparent bugs. For codecs, a self-round-trip proves nothing — validate against external known-answer vectors. Settle behavioral disputes by running the scenario. - **Validate representation at every boundary.** Numbers from JS or the wire: handle NaN, ±Infinity, negatives, out-of-range before casting; compare in the wide type, cast last; coercing conversions (`toInt32(global)`, never `asInt32` on user values); 64-bit types for byte lengths. Strings: never run byte-level checks without branching on encoding (JSC 8-bit strings are Latin1, not UTF-8); never compare byte counts to code-unit counts across a conversion; WTF-8 helpers for lone surrogates (real Windows paths contain them); test with non-ASCII beyond emoji. - **Treat every refactor as guilty until proven behavior-preserving.** Diff the old path's complete behavior — out-parameter writes, error-path side effects, condition polarity, defaults, unconditional operations becoming conditional. Test status flags with bitwise-AND, not equality. Audit every hit of bulk find-and-replace. Before deleting odd-looking code, git-blame why it was written — it is usually load-bearing. If neighboring code does something differently than you're about to, find out why. - **One source of truth; update every consumer atomically.** When a fact lives in two places (mirrored tables, encode/decode pairs), derive one from the other. New enum variant or struct field → audit every switch on the discriminant, every constructor/clone site, every hasher/serialization pair. Signature changes and renames → grep the whole repo including cfg-gated code and generated-binding inputs; stale call sites compile fine and silently miss the new behavior. @@ -234,7 +232,7 @@ Several situational sections live in `.claude/docs/landing-prs.md` — read the ### Code style & idioms reviewers enforce - **In runtime native code, grep for the in-tree helper before hand-writing anything.** File I/O, paths, strings, hashing, formatting, validation, spawning, timers — use the most specific existing helper: `bun.sys`/FD syscall wrappers (never raw std fs/posix), bun_core strings/fmt/Output, shared ref-count helpers, WTF:: containers over std:: in C++ bindings. Being the only file touching a raw primitive is a red flag. New helpers go on the type that owns the concept; extend a maintained in-tree equivalent rather than forking. Verify the helper's actual semantics fit. -- **Match the exact file's local conventions:** the namespace aliases the neighboring lines actually use, import placement, canonical parameter names, the same error-path sequence as sibling exit sites, formatter output. New code is Rust — don't import Zig-era conventions from `.zig` reference files. Name things truthfully: booleans state the invariant positively; no numeric-suffix variants (create2); magic numbers become named constants derived from what they describe (`".tgz".len`, not 4). +- **Match the exact file's local conventions:** the namespace aliases the neighboring lines actually use, import placement, canonical parameter names, the same error-path sequence as sibling exit sites, formatter output. Name things truthfully: booleans state the invariant positively; no numeric-suffix variants (create2); magic numbers become named constants derived from what they describe (`".tgz".len`, not 4). - **Built-in JS modules (`src/js/`) are hot-path code in a hostile environment.** Tamper-resistance: $-prefixed intrinsics and primordial-safe calls (`$isJSArray`, `map.$get`, `$call`), globals captured at module load, `require` with the `node:` prefix, never route internal logic through user-overridable machinery (`Array.isArray`, never `instanceof Array`). Performance: heavy requires stay inside the branch that needs them (`x ??= require(...)`); named functions over inline closures; `Promise.$resolve`/withResolvers over `new Promise` executors; `createFIFO` over `Array#shift` queues; declare every instance field with a default in the class body; cache repeated property reads in locals; `process.platform === 'win32'` for platform checks (tree-shaken per platform). - **Delete dead code in the same PR that makes it dead** (required scope — name the deletions in the description): superseded implementations, helpers whose last caller you rewired, fields nothing reads, parameters discarded in the body, guards a new validator makes redundant. Public items escape dead-code lints — grep for callers manually. Prefer deleting an unmaintained dead feature over renaming it. - **Simplest honest shape; deduplicate within your own diff.** Early returns over else-after-return; `if let`/`?` over null-check-then-unwrap; exhaustive match over equality chains. Don't condense working explicit code into clever one-liners, and don't ride file-wide standardization on a focused bugfix. The second time a multi-line block appears in your diff, extract a named helper and use it at EVERY parallel site. If your fix makes two functions byte-identical, delete one. diff --git a/docs/project/bindgen.mdx b/docs/project/bindgen.mdx index f516c307b997..c67733cfd94f 100644 --- a/docs/project/bindgen.mdx +++ b/docs/project/bindgen.mdx @@ -5,48 +5,48 @@ description: Bindgen for Bun This document is for maintainers and contributors to Bun, and describes internal implementation details. -The new bindings generator, introduced to the codebase in Dec 2024, scans for -`*.bind.ts` to find function and class definition, and generates glue code to -interop between JavaScript and native code. +The bindings generator scans for `*.bind.ts` files to find function and class +definitions, and generates glue code to interop between JavaScript and native +code. There are currently other code generators and systems that achieve similar -purposes. The following will all eventually be completely phased out in favor of -this one: +purposes. The following will all eventually be phased out in favor of this one: - "Classes generator", converting `*.classes.ts` for custom classes. - "JS2Native", allowing ad-hoc calls from `src/js` to native code. -## Creating JS Functions in Zig +## Creating JS Functions in Rust -Given a file implementing a simple function, such as `add` +Given a file implementing a simple function, such as `add`: -```zig src/jsc/math.zig -pub fn add(global: *jsc.JSGlobalObject, a: i32, b: i32) !i32 { - return std.math.add(i32, a, b) catch { - // Binding functions can return `error.OutOfMemory` and `error.JSError`. - // Others like `error.Overflow` from `std.math.add` must be converted. - // Remember to be descriptive. - return global.throwPretty("Integer overflow while adding", .{}); - }; -} - -const gen = bun.gen.math; // "math" being this file's basename +```rust src/jsc/bindgen_test.rs +use crate::{JSGlobalObject, JsResult}; +use crate::r#gen::bindgen_test as generated; -const std = @import("std"); -const bun = @import("bun"); -const jsc = bun.jsc; +pub fn add(global: &JSGlobalObject, a: i32, b: i32) -> JsResult { + match a.checked_add(b) { + Some(v) => Ok(v), + None => { + // Binding functions can propagate out-of-memory and JS exceptions + // directly; other failures (like this integer overflow) must be + // converted into a thrown error. Remember to be descriptive. + Err(global.throw_pretty(format_args!("Integer overflow while adding"))) + } + } +} ``` -Then describe the API schema using a `.bind.ts` function. The binding file goes next to the Zig file. +Then describe the API schema using a `.bind.ts` file. The binding file goes +next to the Rust file. -```ts src/jsc/math.bind.ts icon="/icons/typescript.svg" -import { t, fn } from "bindgen"; +```ts src/jsc/bindgen_test.bind.ts icon="/icons/typescript.svg" +import { fn, t } from "bindgen"; export const add = fn({ args: { global: t.globalObject, a: t.i32, - b: t.i32.default(1), + b: t.i32.default(-1), }, ret: t.i32, }); @@ -59,34 +59,51 @@ This function declaration is equivalent to: * Throws if zero arguments are provided. * Wraps out of range numbers using modulo. */ -declare function add(a: number, b: number = 1): number; +declare function add(a: number, b: number = -1): number; +``` + +The code generator emits a C++ thunk that validates and coerces the JS +arguments, then calls the Rust implementation. On the Rust side the generated +module is reachable as `crate::r#gen::` (for `bindgen_test.bind.ts`, +that's `crate::r#gen::bindgen_test`). To construct a `JSFunction` wrapping the +native implementation, use `generated::create_add_callback(global)`: + +```rust +use crate::r#gen::bindgen_test as generated; + +let js_fn: JSValue = generated::create_add_callback(global); ``` -The code generator will provide `bun.gen.math.jsAdd`, which is the native -function implementation. To pass to JavaScript, use -`bun.gen.math.createAddCallback(global)`. JS files in `src/js/` may use -`$bindgenFn("math.bind.ts", "add")` to get a handle to the implementation. +JS files in `src/js/` may use `$bindgenFn("bindgen_test.bind.ts", "add")` to +get a handle to the implementation. + +Exported bindgen functions are snake_cased on the Rust side +(`requiredAndOptionalArg` → `required_and_optional_arg`), and the generated +callback constructor follows the same convention +(`create_required_and_optional_arg_callback`). ## Strings -The type for receiving strings is one of [`t.DOMString`](https://webidl.spec.whatwg.org/#idl-DOMString), [`t.ByteString`](https://webidl.spec.whatwg.org/#idl-ByteString), and [`t.USVString`](https://webidl.spec.whatwg.org/#idl-USVString). These map directly to their WebIDL counterparts, and have slightly different conversion logic. Bindgen will pass BunString to native code in all cases. +The type for receiving strings is one of [`t.DOMString`](https://webidl.spec.whatwg.org/#idl-DOMString), [`t.ByteString`](https://webidl.spec.whatwg.org/#idl-ByteString), and [`t.USVString`](https://webidl.spec.whatwg.org/#idl-USVString). These map directly to their WebIDL counterparts and have slightly different conversion logic. Bindgen passes `bun_core::String` to native code in all cases. When in doubt, use DOMString. -`t.UTF8String` can be used in place of `t.DOMString`, but will call `bun.String.toUTF8`. The native callback gets `[]const u8` (WTF-8 data) passed to native code, freeing it after the function returns. +`t.UTF8String` can be used in place of `t.DOMString`, but will eagerly convert +to UTF-8. The native callback receives a `&[u8]` slice (WTF-8 data) that is +freed after the function returns. -TLDRs from WebIDL spec: +TLDRs from the WebIDL spec: -- ByteString can only contain valid latin1 characters. It is not safe to assume bun.String is already in 8-bit format, but it is extremely likely. -- USVString will not contain invalid surrogate pairs, aka text that can be represented correctly in UTF-8. -- DOMString is the loosest but also most recommended strategy. +- ByteString can only contain valid latin1 characters. It is not safe to assume `bun_core::String` is already in 8-bit format, but it is extremely likely. +- USVString will not contain invalid surrogate pairs, i.e. text that can be represented correctly in UTF-8. +- DOMString is the loosest but also the most recommended strategy. ## Function Variants A `variants` can specify multiple variants (also known as overloads). -```ts src/jsc/math.bind.ts icon="/icons/typescript.svg" -import { t, fn } from "bindgen"; +```ts +import { fn, t } from "bindgen"; export const action = fn({ variants: [ @@ -106,35 +123,33 @@ export const action = fn({ }); ``` -In Zig, each variant gets a number, based on the order the schema defines. +Each variant gets a numbered Rust function: -```zig -fn action1(a: i32) i32 { - return a; +```rust +pub fn action_1(a: i32) -> i32 { + a } -fn action2(a: bun.String) bun.String { - return a; +pub fn action_2(a: bun_core::String) -> bun_core::String { + a } ``` ## `t.dictionary` -A `dictionary` is a definition for a JavaScript object, typically as a function inputs. For function outputs, it is usually a smarter idea to declare a class type to add functions and destructuring. +A `dictionary` is a definition for a JavaScript object, typically as a function input. For function outputs, it is usually smarter to declare a class type so you can add methods and support destructuring. ## Enumerations -To use [WebIDL's enumeration](https://webidl.spec.whatwg.org/#idl-enums) type, use either: +To use [WebIDL's enumeration](https://webidl.spec.whatwg.org/#idl-enums) type, use `t.stringEnum` to create and codegen a new enum type. -- `t.stringEnum`: Create and codegen a new enum type. -- `t.zigEnum`: Derive a bindgen type off of an existing enum in the codebase. - -An example of `stringEnum` as used in `fmt.zig` / `bun:internal-for-testing` +An example of `stringEnum` as used in `fmt_jsc.bind.ts` / `bun:internal-for-testing`: ```ts -export const Formatter = t.stringEnum("highlight-javascript", "escape-powershell"); +export const Formatter = t.stringEnum("highlight-javascript", "highlight-javascript-redacted", "escape-powershell"); export const fmtString = fn({ + implNamespace: "js_bindings", args: { global: t.globalObject, code: t.UTF8String, @@ -144,36 +159,82 @@ export const fmtString = fn({ }); ``` -WebIDL strongly encourages using kebab case for enumeration values, to be consistent with existing Web APIs. +On the Rust side, the enum is mirrored as a `#[repr(u8)]` enum. Note that +bindgen **sorts `t.stringEnum` values alphabetically** before emitting the C++ +`enum class`, so discriminants must match the generated header's order, not +the `.bind.ts` declaration order: + +```rust +pub mod js_bindings { + #[repr(u8)] + #[derive(Copy, Clone, Eq, PartialEq)] + pub enum Formatter { + EscapePowershell = 0, + HighlightJavascript = 1, + HighlightJavascriptRedacted = 2, + } + + pub fn fmt_string( + global: &JSGlobalObject, + code: &[u8], + formatter_id: Formatter, + ) -> JsResult { + // ... + } +} +``` + +WebIDL strongly encourages kebab-case for enumeration values, to be consistent with existing Web APIs. -### Deriving enums from Zig code +## `implNamespace` -TODO: zigEnum +Setting `implNamespace: "foo"` on a `fn({...})` routes the generated call to +`crate::::foo::fn_name` instead of `crate::::fn_name`. Use +this to group related binding implementations under a submodule. ## `t.oneOf` -A `oneOf` is a union between two or more types. It is represented by `union(enum)` in Zig. - -TODO: +A `oneOf` is a union between two or more types. It is represented as a Rust +`enum` with one variant per member type. ## Attributes -There are set of attributes that can be chained onto `t.*` types. On all types there are: +There is a set of attributes that can be chained onto `t.*` types. On all types: - `.required`, in dictionary parameters only - `.optional`, in function arguments only - `.default(T)` -When a value is optional, it is lowered to a Zig optional. +When a value is `.optional`, it is lowered to a Rust `Option`: + +```ts +export const requiredAndOptionalArg = fn({ + args: { + a: t.boolean, + b: t.usize.optional, + c: t.i32.enforceRange(0, 100).default(42), + d: t.u8.optional, + }, + ret: t.i32, +}); +``` + +```rust +pub fn required_and_optional_arg(a: bool, b: Option, c: i32, d: Option) -> i32 { + // ... +} +``` -Depending on the type, there are more attributes available. See the type definitions in auto-complete for more details. Note that one of the above three can only be applied, and they must be applied at the end. +Depending on the type, more attributes are available. See the type definitions +in auto-complete for details. Note that only one of the above three can be +applied, and it must be applied last. ### Integer Attributes -Integer types allow customizing the overflow behavior with `clamp` or `enforceRange` +Integer types allow customizing overflow behavior with `clamp` or `enforceRange`: ```ts -import { t, fn } from "bindgen"; +import { fn, t } from "bindgen"; export const add = fn({ args: { @@ -184,19 +245,24 @@ export const add = fn({ b: t.u16, // enforce in arbitrary range, with a default if not provided c: t.i32.enforceRange(0, 1000).default(5), - // clamp to arbitrary range, or null + // clamp to arbitrary range, or None d: t.u16.clamp(0, 10).optional, }, ret: t.i32, }); ``` -Various Node.js validator functions such as `validateInteger`, `validateNumber`, and more are available. Use these when implementing Node.js APIs, so the error messages match 1:1 what Node would do. +Various Node.js validator functions such as `validateInteger`, `validateNumber`, +and more are available. Use these when implementing Node.js APIs so the error +messages match Node exactly. -Unlike `enforceRange`, which is taken from WebIDL, `validate*` functions are much more strict on the input they accept. For example, Node's numerical validator check `typeof value === 'number'`, while WebIDL uses `ToNumber` for lossy conversion. +Unlike `enforceRange`, which is taken from WebIDL, the `validate*` functions +are much stricter on the input they accept. For example, Node's numerical +validator checks `typeof value === 'number'`, while WebIDL uses `ToNumber` for +lossy conversion. ```ts -import { t, fn } from "bindgen"; +import { fn, t } from "bindgen"; export const add = fn({ args: { @@ -204,11 +270,11 @@ export const add = fn({ // throw if not given a number a: t.f64.validateNumber(), // valid in i32 range - a: t.i32.validateInt32(), + b: t.i32.validateInt32(), // f64 within safe integer range - b: t.f64.validateInteger(), + c: t.f64.validateInteger(), // f64 in given range - c: t.f64.validateNumber(-10000, 10000), + d: t.f64.validateNumber(-10000, 10000), }, ret: t.i32, }); diff --git a/misctools/compression.zig b/misctools/compression.zig deleted file mode 100644 index a9aa6941186b..000000000000 --- a/misctools/compression.zig +++ /dev/null @@ -1,293 +0,0 @@ -/// Demo app testing the macOS libcompression bindings. -const std = @import("std"); -const CompressionFramework = struct { - var handle: ?*anyopaque = null; - pub fn load() !void { - handle = std.posix.darwin.dlopen("libcompression.dylib", 1); - - if (handle == null) - return error.@"failed to load Compression.framework"; - - compression_encode_scratch_buffer_size = @alignCast(@ptrCast(std.c.dlsym(handle, "compression_encode_scratch_buffer_size").?)); - compression_encode_buffer = @alignCast(@ptrCast(std.c.dlsym(handle, "compression_encode_buffer").?)); - compression_decode_scratch_buffer_size = @alignCast(@ptrCast(std.c.dlsym(handle, "compression_decode_scratch_buffer_size").?)); - compression_decode_buffer = @alignCast(@ptrCast(std.c.dlsym(handle, "compression_decode_buffer").?)); - compression_stream_init = @alignCast(@ptrCast(std.c.dlsym(handle, "compression_stream_init").?)); - compression_stream_process = @alignCast(@ptrCast(std.c.dlsym(handle, "compression_stream_process").?)); - compression_stream_destroy = @alignCast(@ptrCast(std.c.dlsym(handle, "compression_stream_destroy").?)); - } - - pub const compression_algorithm = enum(c_uint) { - LZ4 = 256, - ZLIB = 0x205, - LZMA = 774, - LZ4_RAW = 257, - BROTLI = 2818, - LZFSE = 2049, - LZBITMAP = 1794, - - pub fn fromName(name: []const u8) ?compression_algorithm { - if (std.mem.endsWith(u8, name, ".br")) { - return .BROTLI; - } else if (std.mem.endsWith(u8, name, ".lz4")) { - return .LZ4; - } else if (std.mem.endsWith(u8, name, ".lzma")) { - return .LZMA; - } else if (std.mem.endsWith(u8, name, ".lzfse")) { - return .LZFSE; - } else if (std.mem.endsWith(u8, name, ".zlib") or std.mem.endsWith(u8, name, ".gz")) { - return .ZLIB; - } else { - return null; - } - } - }; - const compression_encode_scratch_buffer_size_type = fn (algorithm: compression_algorithm) callconv(.c) usize; - const compression_encode_buffer_type = fn (noalias dst_buffer: [*]u8, dst_size: usize, noalias src_buffer: ?[*]const u8, src_size: usize, noalias scratch_buffer: ?*anyopaque, algorithm: compression_algorithm) callconv(.c) usize; - const compression_decode_scratch_buffer_size_type = fn (algorithm: compression_algorithm) callconv(.c) usize; - const compression_decode_buffer_type = fn (noalias dst_buffer: [*]u8, dst_size: usize, noalias src_buffer: ?[*]const u8, src_size: usize, noalias scratch_buffer: ?*anyopaque, algorithm: compression_algorithm) callconv(.c) usize; - - const compression_stream_init_type = fn (stream: *compression_stream, operation: compression_stream_operation, algorithm: compression_algorithm) callconv(.c) compression_status; - const compression_stream_process_type = fn (stream: *compression_stream, flags: c_int) callconv(.c) compression_status; - const compression_stream_destroy_type = fn (stream: *compression_stream) callconv(.c) compression_status; - - var compression_encode_scratch_buffer_size: *const compression_encode_scratch_buffer_size_type = undefined; - var compression_encode_buffer: *const compression_encode_buffer_type = undefined; - var compression_decode_scratch_buffer_size: *const compression_decode_scratch_buffer_size_type = undefined; - var compression_decode_buffer: *const compression_decode_buffer_type = undefined; - - var compression_stream_init: *const compression_stream_init_type = undefined; - var compression_stream_process: *const compression_stream_process_type = undefined; - var compression_stream_destroy: *const compression_stream_destroy_type = undefined; - pub const compression_stream = extern struct { - dst_ptr: ?[*]u8 = null, - dst_size: usize = 0, - src_ptr: ?[*]const u8 = null, - src_size: usize = 0, - state: ?*anyopaque = null, - - pub fn init(src: []const u8, operation: compression_stream_operation, algorithm: compression_algorithm) !compression_stream { - var stream = compression_stream{ - .src_ptr = src.ptr, - .src_size = src.len, - .dst_ptr = null, - .dst_size = 0, - }; - - switch (compression_stream_init(&stream, operation, algorithm)) { - .OK => {}, - .ERROR => return error.@"failed to initialize compression stream", - .END => return error.@"compression stream init returned END", - } - - return stream; - } - - pub fn process(stream: *compression_stream, data: []const u8, is_done: bool, comptime Iterator: type, iter: *Iterator) !StreamResult { - stream.src_ptr = data.ptr; - stream.src_size = data.len; - - const initial_dest = try iter.wrote(0); - stream.dst_ptr = initial_dest.ptr; - stream.dst_size = initial_dest.len; - - var total_written: usize = 0; - while (true) { - var flags: c_int = 0; - if (stream.src_size == 0 and is_done) { - flags = COMPRESSION_STREAM_FINALIZE; - } else if (stream.src_size == 0) { - return .{ - .progress = .{ - .read = data.len - stream.src_size, - .wrote = total_written, - }, - }; - } - - const prev_size = stream.dst_size; - const rc = compression_stream_process(stream, flags); - const wrote = prev_size - stream.dst_size; - switch (rc) { - .OK => { - const new_buffer = try iter.wrote(wrote); - stream.dst_ptr = new_buffer.ptr; - stream.dst_size = new_buffer.len; - total_written += wrote; - }, - .END => { - _ = try iter.wrote(wrote); - total_written += wrote; - - return .{ - .done = .{ - .read = data.len - stream.src_size, - .wrote = total_written, - }, - }; - }, - .ERROR => { - return .{ - .err = .{ - .err = error.@"failed to process compression stream", - .read = data.len - stream.src_size, - .wrote = total_written, - }, - }; - }, - } - } - } - }; - pub const COMPRESSION_STREAM_ENCODE: c_int = 0; - pub const COMPRESSION_STREAM_DECODE: c_int = 1; - pub const compression_stream_operation = enum(c_uint) { - ENCODE = 0, - DECODE = 1, - }; - pub const COMPRESSION_STREAM_FINALIZE: c_int = 1; - pub const compression_stream_flags = c_uint; - pub const compression_status = enum(c_int) { - OK = 0, - ERROR = -1, - END = 1, - }; - - const StreamResult = union(enum) { - done: struct { - read: usize = 0, - wrote: usize = 0, - }, - err: struct { - read: usize = 0, - wrote: usize = 0, - err: anyerror, - }, - progress: struct { - read: usize = 0, - wrote: usize = 0, - }, - }; - - pub fn compress(data: []const u8, algorithm: compression_algorithm, is_done: bool, writer: anytype) !StreamResult { - var scratch_buffer: [64 * 1024]u8 = undefined; - - const scratch_buffer_size = compression_encode_scratch_buffer_size(algorithm); - if (scratch_buffer_size >= scratch_buffer.len) { - std.debug.panic("scratch buffer size is too small {d}", .{scratch_buffer_size}); - } - - var stream = try compression_stream.init(data, .ENCODE, algorithm); - - defer _ = compression_stream_destroy(&stream); - const Iterator = struct { - writer: @TypeOf(writer), - scratch_buffer: []u8, - pub fn wrote(this: *@This(), w: usize) ![]u8 { - try this.writer.writeAll(this.scratch_buffer[0..w]); - return this.scratch_buffer; - } - }; - - var iter = Iterator{ - .writer = writer, - .scratch_buffer = &scratch_buffer, - }; - - return try stream.process(data, is_done, Iterator, &iter); - } - - pub fn decompress(data: []const u8, algorithm: compression_algorithm, is_done: bool, writer: anytype) !StreamResult { - var scratch_buffer: [64 * 1024]u8 = undefined; - - const scratch_buffer_size = compression_decode_scratch_buffer_size(algorithm); - if (scratch_buffer_size >= scratch_buffer.len) { - std.debug.panic("scratch buffer size is too small {d}", .{scratch_buffer_size}); - } - - var stream = try compression_stream.init(data, .DECODE, algorithm); - defer _ = compression_stream_destroy(&stream); - - const Iterator = struct { - writer: @TypeOf(writer), - scratch_buffer: []u8, - pub fn wrote(this: *@This(), w: usize) ![]u8 { - try this.writer.writeAll(this.scratch_buffer[0..w]); - return this.scratch_buffer; - } - }; - - var iter = Iterator{ - .writer = writer, - .scratch_buffer = &scratch_buffer, - }; - - return try stream.process(data, is_done, Iterator, &iter); - } -}; - -pub fn main() anyerror!void { - try CompressionFramework.load(); - - var args = std.process.args(); - const argv0 = args.next() orelse ""; - - const first = args.next() orelse ""; - const second = args.next() orelse ""; - var algorithm: ?CompressionFramework.compression_algorithm = null; - var operation: ?CompressionFramework.compression_stream_operation = null; - - if (CompressionFramework.compression_algorithm.fromName(first)) |a| { - algorithm = a; - operation = .DECODE; - } else if (CompressionFramework.compression_algorithm.fromName(second)) |o| { - algorithm = o; - operation = .ENCODE; - } - - if (algorithm == null or operation == null) { - try std.io.getStdErr().writer().print("to compress: {s} ./file ./out.{{br,gz,lz4,lzfse}}\nto decompress: {s} ./out.{{br,gz,lz4,lzfse}} ./out\n", .{ argv0, argv0 }); - std.posix.exit(1); - } - - var output_file: std.fs.File = undefined; - var input_file: std.fs.File = undefined; - - if (second.len == 0) { - output_file = std.io.getStdOut(); - } else { - output_file = try std.fs.cwd().createFile(second, .{ - .truncate = true, - }); - } - - if (first.len == 0) { - input_file = std.io.getStdIn(); - } else { - input_file = try std.fs.cwd().openFile(first, .{}); - } - - var writer = std.io.BufferedWriter(64 * 1024, @TypeOf(output_file.writer())){ - .unbuffered_writer = output_file.writer(), - }; - - const input_bytes = try input_file.readToEndAlloc(std.heap.c_allocator, std.math.maxInt(usize)); - - if (operation == .ENCODE) { - switch (try CompressionFramework.compress(input_bytes, algorithm.?, true, writer.writer())) { - .err => |err| { - return err.err; - }, - else => {}, - } - } else { - switch (try CompressionFramework.decompress(input_bytes, algorithm.?, true, writer.writer())) { - .err => |err| { - return err.err; - }, - else => {}, - } - } - - try writer.flush(); -} diff --git a/misctools/features.zig b/misctools/features.zig deleted file mode 100644 index 392391dfa016..000000000000 --- a/misctools/features.zig +++ /dev/null @@ -1,25 +0,0 @@ -const std = @import("std"); - -const path_handler = @import("../src/resolver/resolve_path.zig"); -const bun = @import("bun"); -const string = []const u8; -const Output = bun.Output; -const Global = bun.Global; -const Environment = bun.Environment; -const strings = bun.strings; -const MutableString = bun.MutableString; -const stringZ = [:0]const u8; -const default_allocator = bun.default_allocator; -const Features = bun.analytics.Features; - -// zig run --main-pkg-path ../ ./features.zig -pub fn main() anyerror!void { - var stdout_ = std.io.getStdOut(); - var stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); - defer Output.flush(); - - var writer = Output.writer(); - try Features.Serializer.writeAll(@TypeOf(writer), writer); -} diff --git a/misctools/gdb/zig_gdb_pretty_printers.py b/misctools/gdb/zig_gdb_pretty_printers.py deleted file mode 100644 index 1bc4b36e5749..000000000000 --- a/misctools/gdb/zig_gdb_pretty_printers.py +++ /dev/null @@ -1,63 +0,0 @@ -# pretty printing for the language. -# put "source /path/to/zig_gdb_pretty_printers.py" in ~/.gdbinit to load it automatically. -import gdb.printing - - -class ZigPrettyPrinter(gdb.printing.PrettyPrinter): - def __init__(self): - super().__init__('Zig') - - def __call__(self, val): - tag = val.type.tag - if tag is None: - return None - if tag == '[]u8': - return StringPrinter(val) - if tag.startswith('[]'): - return SlicePrinter(val) - if tag.startswith('?'): - return OptionalPrinter(val) - return None - - -class SlicePrinter: - def __init__(self, val): - self.val = val - - def to_string(self): - return f"{self.val['len']} items at {self.val['ptr']}" - - def children(self): - def it(val): - for i in range(int(val['len'])): - item = val['ptr'] + i - yield (f'[{i}]', item.dereference()) - return it(self.val) - - def display_hint(self): - return 'array' - - -class StringPrinter: - def __init__(self, val): - self.val = val - - def to_string(self): - return self.val['ptr'].string(length=int(self.val['len'])) - - def display_hint(self): - return 'string' - - -class OptionalPrinter: - def __init__(self, val): - self.val = val - - def to_string(self): - if self.val['some']: - return self.val['data'] - else: - return 'null' - - -gdb.printing.register_pretty_printer(gdb.current_objfile(), ZigPrettyPrinter()) diff --git a/misctools/generate-add-completions.ts b/misctools/generate-add-completions.ts index f9057de69e64..83179ef51a41 100644 --- a/misctools/generate-add-completions.ts +++ b/misctools/generate-add-completions.ts @@ -1,6 +1,5 @@ import * as fs from "fs"; import path from "path"; -import { execSync } from "child_process"; interface LetterGroup { offset: number; @@ -8,8 +7,11 @@ interface LetterGroup { packages: string[]; } +const INPUT = path.join(__dirname, "..", "src", "runtime", "cli", "add_completions.txt"); +const OUTPUT = path.join(__dirname, "..", "src", "runtime", "cli", "add_completions.rs"); + // Read and parse input file -const content = fs.readFileSync(path.join(__dirname, "..", "src", "cli", "add_completions.txt"), "utf8"); +const content = fs.readFileSync(INPUT, "utf8"); const packages = content .split("\n") .map(line => line.trim()) @@ -37,12 +39,6 @@ for (const pkg of packages) { maxListSize = Math.max(maxListSize, group.length); } -// Helper to ensure temp dir exists -const tmpDir = path.join(__dirname, "tmp"); -if (!fs.existsSync(tmpDir)) { - fs.mkdirSync(tmpDir); -} - // Create a single buffer with all package data const dataChunks: Buffer[] = []; let totalUncompressed = 0; @@ -64,16 +60,8 @@ for (const pkg of packages) { const uncompressedData = Buffer.concat(dataChunks); -// Write to temp file and compress with zstd -const uncompressedPath = path.join(tmpDir, "packages.bin"); -const compressedPath = path.join(tmpDir, "packages.bin.zst"); - -fs.writeFileSync(uncompressedPath, uncompressedData); -execSync(`zstd -1 --rm -f "${uncompressedPath}" -o "${compressedPath}"`); - -// Read back compressed data -const compressedData = fs.readFileSync(compressedPath); -fs.unlinkSync(compressedPath); +// Compress with zstd (level 1, matching the old `zstd -1` CLI invocation) +const compressedData = Bun.zstdCompressSync(uncompressedData, { level: 1 }); // Calculate compression ratio const totalCompressed = compressedData.length; @@ -84,148 +72,107 @@ console.log(`Uncompressed size: ${totalUncompressed} bytes`); console.log(`Compressed size: ${totalCompressed} bytes`); console.log(`Compression ratio: ${ratio}%`); -// Generate Zig code -const chunks: string[] = []; +// Generate index entries +const letters = "abcdefghijklmnopqrstuvwxyz"; +const indexEntries: string[] = []; +let offset = 0; +for (const letter of letters) { + const group = letterGroups.get(letter); + const len = group?.length ?? 0; + indexEntries.push(` (${offset}, ${len}), // ${letter}`); + offset += len; +} + +// Split the compressed blob into 16-byte rows for readability +const blobLines: string[] = []; +for (let i = 0; i < compressedData.length; i += 16) { + const row = [...compressedData.slice(i, i + 16)].join(", "); + blobLines.push(` ${row},`); +} -// Header with comments and imports -chunks.push(`// Auto-generated file. Do not edit. -// To regenerate this file, run: -// -// bun misctools/generate-add-completions.ts +const out = `// Auto-generated by misctools/generate-add-completions.ts. Do not edit. +// +// Regenerate after editing src/runtime/cli/add_completions.txt: // -// If you update add_completions.txt, then you should run this script again. +// bun misctools/generate-add-completions.ts // -// This used to be a comptime block, but it made the build too slow. // Compressing the completions list saves about 100 KB of binary size. -const std = @import("std"); -const bun = @import("bun"); -const zstd = bun.zstd; -const Environment = bun.Environment; - -pub const FirstLetter = enum(u8) { - a = 'a', - b = 'b', - c = 'c', - d = 'd', - e = 'e', - f = 'f', - g = 'g', - h = 'h', - i = 'i', - j = 'j', - k = 'k', - l = 'l', - m = 'm', - n = 'n', - o = 'o', - p = 'p', - q = 'q', - r = 'r', - s = 's', - t = 't', - u = 'u', - v = 'v', - w = 'w', - x = 'x', - y = 'y', - z = 'z', -};`); - -// Add the compressed data -chunks.push(`const compressed_data = [_]u8{${[...compressedData].join(",")}};`); - -// Add uncompressed size constant -chunks.push(`const uncompressed_size: usize = ${totalUncompressed};`); -// Generate index entries -const indexEntries: string[] = []; -let offset = 0; -for (const letter of "abcdefghijklmnopqrstuvwxyz") { - const group = letterGroups.get(letter); - if (group) { - indexEntries.push(` .${letter} = .{ .offset = ${offset}, .length = ${group.length} }`); - offset += group.length; - } else { - indexEntries.push(` .${letter} = .{ .offset = ${offset}, .length = 0 }`); - } +use bun_core::Once; + +#[repr(u8)] +#[derive(Copy, Clone, Eq, PartialEq)] +pub(crate) enum FirstLetter { +${[...letters].map(l => ` ${l.toUpperCase()} = b'${l}',`).join("\n")} } -// Generate index type and instance -chunks.push(`pub const IndexEntry = struct { - offset: usize, - length: usize, -}; +/// Largest per-letter package list length. +pub(crate) const BIGGEST_LIST: usize = ${maxListSize}; + +const UNCOMPRESSED_SIZE: usize = ${totalUncompressed}; -pub const Index = std.EnumArray(FirstLetter, IndexEntry); +/// (offset, length) into the decompressed package list for each letter a-z. +const INDEX: [(usize, usize); 26] = [ +${indexEntries.join("\n")} +]; -pub const index = Index.init(.{ -${indexEntries.join(",\n")} - });`); +static COMPRESSED_DATA: &[u8] = &[ +${blobLines.join("\n")} +]; -// Generate the decompression and access function -chunks.push(`var decompressed_data: ?[]u8 = null; -var packages_list: ?[][]const u8 = null; +struct Table { + _decompressed: Vec, + packages: Vec<&'static [u8]>, +} -pub fn init(allocator: std.mem.Allocator) !void { - // Decompress data - var data = try allocator.alloc(u8, uncompressed_size); - errdefer allocator.free(data); +static TABLE: Once = >::new(); - const result = zstd.decompress(data, &compressed_data); - decompressed_data = data[0..result.success]; +fn build_table() -> Table { + let decompressed = bun_zstd::decompress_alloc(COMPRESSED_DATA) + .expect("add_completions: zstd decompress failed"); + debug_assert_eq!(decompressed.len(), UNCOMPRESSED_SIZE); - // Parse package list - const total_count = std.mem.readInt(u32, data[0..4], .little); - var packages = try allocator.alloc([]const u8, total_count); - errdefer allocator.free(packages); + // SAFETY: the decompressed Vec is moved into TABLE (a process-lifetime + // Once) and never dropped or reallocated, so its storage is valid for + // 'static. The package slices below borrow this storage. + let data: &'static [u8] = + unsafe { core::slice::from_raw_parts(decompressed.as_ptr(), decompressed.len()) }; - var pos: usize = 4; - var i: usize = 0; - while (i < total_count) : (i += 1) { - const len = std.mem.readInt(u16, data[pos..][0..2], .little); + let total = u32::from_le_bytes([data[0], data[1], data[2], data[3]]) as usize; + let mut packages: Vec<&'static [u8]> = Vec::with_capacity(total); + let mut pos: usize = 4; + for _ in 0..total { + let len = u16::from_le_bytes([data[pos], data[pos + 1]]) as usize; pos += 2; - packages[i] = data[pos..pos + len]; + packages.push(&data[pos..pos + len]); pos += len; } - packages_list = packages; + Table { _decompressed: decompressed, packages } } -pub fn deinit(allocator: std.mem.Allocator) void { - if (packages_list) |pkgs| { - allocator.free(pkgs); - packages_list = null; - } +/// Decompress the package-name table. Idempotent. +pub fn init() { + TABLE.get_or_init(build_table); +} - if (decompressed_data) |data| { - allocator.free(data); - decompressed_data = null; +/// Returns the slice of package names beginning with \`letter\`. +pub(crate) fn get_packages(letter: FirstLetter) -> &'static [&'static [u8]] { + let table = TABLE.get_or_init(build_table); + let (offset, length) = INDEX[(letter as u8 - b'a') as usize]; + if length == 0 { + return &[]; } + &table.packages[offset..offset + length] } +`; -pub fn getPackages(letter: FirstLetter) []const []const u8 { - const entry = index.get(letter); - if (entry.length == 0) return &[_][]const u8{}; - - return packages_list.?[entry.offset..entry.offset + entry.length]; -}`); - -// Add biggest_list constant -chunks.push(`pub const biggest_list: usize = ${maxListSize};`); - -// Write the output -let zigCode = chunks.join("\n\n"); - -zigCode = execSync("zig fmt --stdin", { - input: zigCode, - encoding: "utf8", -}).toString(); - -fs.writeFileSync(path.join(__dirname, "..", "src", "cli", "add_completions.zig"), zigCode); - -// Clean up temp dir +fs.writeFileSync(OUTPUT, out); try { - fs.rmdirSync(tmpDir); -} catch {} + const { execSync } = await import("child_process"); + execSync(`rustfmt "${OUTPUT}"`, { stdio: "inherit" }); +} catch { + // rustfmt not available; committed output is already formatted reasonably +} -console.log(`\nGenerated Zig completions for ${packages.length} packages`); +console.log(`\nGenerated ${OUTPUT} for ${packages.length} packages`); diff --git a/misctools/http_bench.zig b/misctools/http_bench.zig deleted file mode 100644 index 64853e3d4322..000000000000 --- a/misctools/http_bench.zig +++ /dev/null @@ -1,295 +0,0 @@ -const std = @import("std"); -const bun = @import("bun"); -const string = []const u8; -const Output = bun.Output; -const Global = bun.Global; -const Environment = bun.Environment; -const strings = bun.strings; -const MutableString = bun.MutableString; -const stringZ = [:0]const u8; -const default_allocator = bun.default_allocator; -const clap = @import("../src/deps/zig-clap/clap.zig"); - -const URL = @import("../src/url.zig").URL; -const Method = @import("../src/http/Method.zig").Method; -const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType; -const HeadersTuple = ColonListType(string, noop_resolver); -const path_handler = @import("../src/resolver/resolve_path.zig"); - -fn noop_resolver(in: string) !string { - return in; -} - -const VERSION = "0.0.0"; - -const params = [_]clap.Param(clap.Help){ - clap.parseParam("-v, --verbose Show headers & status code") catch unreachable, - clap.parseParam("-H, --header ... Add a header") catch unreachable, - clap.parseParam("-r, --max-redirects Maximum number of redirects to follow (default: 128)") catch unreachable, - clap.parseParam("-b, --body HTTP request body as a string") catch unreachable, - clap.parseParam("-f, --file File path to load as body") catch unreachable, - clap.parseParam("-n, --count How many runs? Default 10") catch unreachable, - clap.parseParam("-r, --retry Max retry count") catch unreachable, - clap.parseParam("--no-gzip Disable gzip") catch unreachable, - clap.parseParam("--no-deflate Disable deflate") catch unreachable, - clap.parseParam("--no-compression Disable gzip & deflate") catch unreachable, - clap.parseParam("--version Print the version and exit") catch unreachable, - clap.parseParam("--turbo Skip sending TLS shutdown signals") catch unreachable, - clap.parseParam("--repeat Repeat N times") catch unreachable, - clap.parseParam("--max-concurrency Max concurrent") catch unreachable, - clap.parseParam("... ") catch unreachable, -}; - -const MethodNames = std.ComptimeStringMap(Method, .{ - .{ "GET", Method.GET }, - .{ "get", Method.GET }, - - .{ "POST", Method.POST }, - .{ "post", Method.POST }, - - .{ "PUT", Method.PUT }, - .{ "put", Method.PUT }, - - .{ "PATCH", Method.PATCH }, - .{ "patch", Method.PATCH }, - - .{ "OPTIONS", Method.OPTIONS }, - .{ "options", Method.OPTIONS }, - - .{ "HEAD", Method.HEAD }, - .{ "head", Method.HEAD }, -}); - -var file_path_buf: bun.PathBuffer = undefined; -var cwd_buf: bun.PathBuffer = undefined; - -pub const Arguments = struct { - url: URL, - method: Method, - verbose: bool = false, - headers: Headers.Entries, - headers_buf: string, - body: string = "", - turbo: bool = false, - count: usize = 10, - repeat: usize = 0, - concurrency: u16 = 32, - - pub fn parse(allocator: std.mem.Allocator) !Arguments { - var diag = clap.Diagnostic{}; - - var args = clap.parse(clap.Help, ¶ms, .{ - .diagnostic = &diag, - .allocator = allocator, - }) catch |err| { - // Report useful error and exit - diag.report(Output.errorWriter(), err) catch {}; - return err; - }; - - const positionals = args.positionals(); - var raw_args: std.ArrayListUnmanaged(string) = undefined; - - if (positionals.len > 0) { - raw_args = .{ .capacity = positionals.len, .items = @as([*][]const u8, @ptrFromInt(@intFromPtr(positionals.ptr)))[0..positionals.len] }; - } else { - raw_args = .{}; - } - - if (args.flag("--version")) { - try Output.writer().writeAll(VERSION); - Global.exit(0); - } - - var method = Method.GET; - var url: URL = .{}; - var body_string: string = args.option("--body") orelse ""; - - if (args.option("--file")) |file_path| { - if (file_path.len > 0) { - const cwd = try std.process.getCwd(&cwd_buf); - var parts = [_]string{file_path}; - const absolute_path = path_handler.joinAbsStringBuf(cwd, &file_path_buf, &parts, .auto); - file_path_buf[absolute_path.len] = 0; - file_path_buf[absolute_path.len + 1] = 0; - const absolute_path_len = absolute_path.len; - const absolute_path_ = file_path_buf[0..absolute_path_len :0]; - - var body_file = std.fs.openFileAbsoluteZ(absolute_path_, .{ .mode = .read_only }) catch |err| { - Output.printErrorln("{s} opening file {s}", .{ @errorName(err), absolute_path }); - Global.exit(1); - }; - - const file_contents = body_file.readToEndAlloc(allocator, try body_file.getEndPos()) catch |err| { - Output.printErrorln("{s} reading file {s}", .{ @errorName(err), absolute_path }); - Global.exit(1); - }; - body_string = file_contents; - } - } - - { - var raw_arg_i: usize = 0; - while (raw_arg_i < raw_args.items.len) : (raw_arg_i += 1) { - const arg = raw_args.items[raw_arg_i]; - if (MethodNames.get(arg[0..])) |method_| { - method = method_; - _ = raw_args.swapRemove(raw_arg_i); - } - } - - if (raw_args.items.len == 0) { - Output.prettyErrorln("error: Missing URL\n\nExample:\nfetch GET https://example.com\n\nfetch example.com/foo\n\n", .{}); - Global.exit(1); - } - - const url_position = raw_args.items.len - 1; - url = URL.parse(raw_args.swapRemove(url_position)); - if (!url.isAbsolute()) { - Output.prettyErrorln("error: Invalid URL\n\nExample:\nfetch GET https://example.com\n\nfetch example.com/foo\n\n", .{}); - Global.exit(1); - } - } - - return Arguments{ - .url = url, - .method = method, - .verbose = args.flag("--verbose"), - .headers = .{}, - .headers_buf = "", - .body = body_string, - // .keep_alive = !args.flag("--no-keep-alive"), - .concurrency = std.fmt.parseInt(u16, args.option("--max-concurrency") orelse "32", 10) catch 32, - .turbo = args.flag("--turbo"), - .count = std.fmt.parseInt(usize, args.option("--count") orelse "10", 10) catch |err| { - Output.prettyErrorln("{s} parsing count", .{@errorName(err)}); - Global.exit(1); - }, - }; - } -}; - -const HTTP = bun.http; -const NetworkThread = HTTP.NetworkThread; - -var stdout_: std.fs.File = undefined; -var stderr_: std.fs.File = undefined; -pub fn main() anyerror!void { - stdout_ = std.io.getStdOut(); - stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); - - defer Output.flush(); - - const args = try Arguments.parse(default_allocator); - - var channel = try default_allocator.create(HTTP.HTTPChannel); - channel.* = HTTP.HTTPChannel.init(); - - try channel.buffer.ensureTotalCapacity(args.count); - - try NetworkThread.init(); - if (args.concurrency > 0) HTTP.AsyncHTTP.max_simultaneous_requests.store(args.concurrency, .monotonic); - const Group = struct { - response_body: MutableString = undefined, - context: HTTP.HTTPChannelContext = undefined, - }; - const Batch = bun.ThreadPool.Batch; - var groups = try default_allocator.alloc(Group, args.count); - var repeat_i: usize = 0; - while (repeat_i < args.repeat + 1) : (repeat_i += 1) { - var i: usize = 0; - var batch = Batch{}; - while (i < args.count) : (i += 1) { - groups[i] = Group{}; - const response_body = &groups[i].response_body; - response_body.* = try MutableString.init(default_allocator, 1024); - - var ctx = &groups[i].context; - ctx.* = .{ - .channel = channel, - .http = try HTTP.AsyncHTTP.init( - default_allocator, - args.method, - args.url, - args.headers, - args.headers_buf, - response_body, - "", - ), - }; - ctx.http.client.verbose = args.verbose; - ctx.http.callback = HTTP.HTTPChannelContext.callback; - ctx.http.schedule(default_allocator, &batch); - } - NetworkThread.global.schedule(batch); - - var read_count: usize = 0; - var success_count: usize = 0; - var fail_count: usize = 0; - var min_duration: usize = std.math.maxInt(usize); - var max_duration: usize = 0; - var timer = try std.time.Timer.start(); - while (read_count < args.count) { - const http = channel.readItem() catch continue; - read_count += 1; - - Output.printElapsed(@as(f64, @floatCast(@as(f128, @floatFromInt(http.elapsed)) / std.time.ns_per_ms))); - if (http.response) |resp| { - if (resp.status_code == 200) { - success_count += 1; - } else { - fail_count += 1; - } - - max_duration = @max(max_duration, http.elapsed); - min_duration = @min(min_duration, http.elapsed); - - switch (resp.status_code) { - 200, 202, 302 => { - Output.prettyError(" {d}", .{resp.status_code}); - }, - else => { - Output.prettyError(" {d}", .{resp.status_code}); - }, - } - - if (http.gzip_elapsed > 0) { - Output.prettyError(" {s} - {s} ({d} bytes, ", .{ - @tagName(http.client.method), - http.client.url.href, - http.response_buffer.list.items.len, - }); - Output.printElapsed(@as(f64, @floatCast(@as(f128, @floatFromInt(http.gzip_elapsed)) / std.time.ns_per_ms))); - Output.prettyError(" gzip)\n", .{}); - } else { - Output.prettyError(" {s} - {s} ({d} bytes)\n", .{ - @tagName(http.client.method), - http.client.url.href, - http.response_buffer.list.items.len, - }); - } - } else if (http.err) |err| { - fail_count += 1; - Output.printError(" err: {s}\n", .{@errorName(err)}); - } else { - fail_count += 1; - Output.prettyError(" Uh-oh: {s}\n", .{@tagName(http.state.raw)}); - } - - Output.flush(); - } - Output.prettyErrorln("\n------\n\n", .{}); - Output.prettyErrorln("Success: {d}\nFailure: {d}\n\n", .{ - success_count, - fail_count, - }); - - Output.printElapsed(@as(f64, @floatCast(@as(f128, @floatFromInt(timer.read())) / std.time.ns_per_ms))); - Output.prettyErrorln(" {d} requests", .{ - read_count, - }); - Output.flush(); - } -} diff --git a/misctools/lldb/README.md b/misctools/lldb/README.md index 7e943c766d88..dbe6d1f8b74b 100644 --- a/misctools/lldb/README.md +++ b/misctools/lldb/README.md @@ -5,7 +5,6 @@ This directory contains LLDB pretty printers for various Bun data structures to ## Files - `bun_pretty_printer.py` - Pretty printers for Bun-specific types (bun.String, WTFStringImpl, ZigString, BabyList, etc.) -- `lldb_pretty_printers.py` - Pretty printers for Zig language types from the Zig project - `lldb_webkit.py` - Pretty printers for WebKit/JavaScriptCore types - `init.lldb` - LLDB initialization commands @@ -70,8 +69,8 @@ bun bd ```bash lldb ./build/debug/bun-debug (lldb) command script import misctools/lldb/bun_pretty_printer.py -(lldb) breakpoint set --file your_test.zig --line -(lldb) run your_test.zig +(lldb) breakpoint set --file your_file.rs --line +(lldb) run your_test.ts (lldb) frame variable ``` diff --git a/misctools/lldb/init.lldb b/misctools/lldb/init.lldb index c2749b47fe85..5648ab11aef1 100644 --- a/misctools/lldb/init.lldb +++ b/misctools/lldb/init.lldb @@ -11,10 +11,6 @@ process handle -p true -s false -n false SIGPWR process handle -p true -s false -n false SIGUSR1 process handle -p true -s false -n false SIGUSR2 -command script import -c lldb_pretty_printers.py -type category enable zig.lang -type category enable zig.std - command script import -c lldb_webkit.py command script import -c bun_pretty_printer.py diff --git a/misctools/lldb/lldb_pretty_printers.py b/misctools/lldb/lldb_pretty_printers.py deleted file mode 100644 index 4455d1872008..000000000000 --- a/misctools/lldb/lldb_pretty_printers.py +++ /dev/null @@ -1,732 +0,0 @@ -# https://github.com/ziglang/zig/blob/master/tools/lldb_pretty_printers.py - -# pretty printing for the zig language, zig standard library, and zig stage 2 compiler. -# put commands in ~/.lldbinit to run them automatically when starting lldb -# `command script import /path/to/zig/tools/lldb_pretty_printers.py` to import this file -# `type category enable zig.lang` to enable pretty printing for the zig language -# `type category enable zig.std` to enable pretty printing for the zig standard library -# `type category enable zig.stage2` to enable pretty printing for the zig stage 2 compiler -import lldb -import re - -page_size = 1 << 12 - -def log2_int(i): return i.bit_length() - 1 - -# Define Zig Language - -zig_keywords = { - 'addrspace', - 'align', - 'allowzero', - 'and', - 'anyframe', - 'anytype', - 'asm', - 'async', - 'await', - 'break', - 'callconv', - 'catch', - 'comptime', - 'const', - 'continue', - 'defer', - 'else', - 'enum', - 'errdefer', - 'error', - 'export', - 'extern', - 'fn', - 'for', - 'if', - 'inline', - 'noalias', - 'noinline', - 'nosuspend', - 'opaque', - 'or', - 'orelse', - 'packed', - 'pub', - 'resume', - 'return', - 'linksection', - 'struct', - 'suspend', - 'switch', - 'test', - 'threadlocal', - 'try', - 'union', - 'unreachable', - 'var', - 'volatile', - 'while', -} -zig_primitives = { - 'anyerror', - 'anyframe', - 'anyopaque', - 'bool', - 'c_int', - 'c_long', - 'c_longdouble', - 'c_longlong', - 'c_short', - 'c_uint', - 'c_ulong', - 'c_ulonglong', - 'c_ushort', - 'comptime_float', - 'comptime_int', - 'f128', - 'f16', - 'f32', - 'f64', - 'f80', - 'false', - 'isize', - 'noreturn', - 'null', - 'true', - 'type', - 'undefined', - 'usize', - 'void', -} -zig_integer_type = re.compile('[iu][1-9][0-9]+') -zig_identifier_regex = re.compile('[A-Z_a-z][0-9A-Z_a-z]*') -def zig_IsVariableName(string): return string != '_' and string not in zig_keywords and string not in zig_primitives and not zig_integer_type.fullmatch(string) and zig_identifier_regex.fullmatch(string) -def zig_IsFieldName(string): return string not in zig_keywords and zig_identifier_regex.fullmatch(string) - -class zig_Slice_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.ptr = self.value.GetChildMemberWithName('ptr') - self.len = self.value.GetChildMemberWithName('len').unsigned if self.ptr.unsigned > page_size else 0 - self.elem_type = self.ptr.type.GetPointeeType() - self.elem_size = self.elem_type.size - except: pass - def has_children(self): return True - def num_children(self): return self.len or 0 - def get_child_index(self, name): - try: return int(name.removeprefix('[').removesuffix(']')) - except: return -1 - def get_child_at_index(self, index): - if index not in range(self.len): return None - try: return self.ptr.CreateChildAtOffset('[%d]' % index, index * self.elem_size, self.elem_type) - except: return None - -def zig_String_decode(value, offset=0, length=None): - try: - value = value.GetNonSyntheticValue() - data = value.GetChildMemberWithName('ptr').GetPointeeData(offset, length if length is not None else value.GetChildMemberWithName('len').unsigned) - b = bytes(data.uint8) - b = b.replace(b'\\', b'\\\\') - b = b.replace(b'\n', b'\\n') - b = b.replace(b'\r', b'\\r') - b = b.replace(b'\t', b'\\t') - b = b.replace(b'"', b'\\"') - b = b.replace(b'\'', b'\\\'') - s = b.decode(encoding='ascii', errors='backslashreplace') - return s if s.isprintable() else ''.join((c if c.isprintable() else '\\x%02x' % ord(c) for c in s)) - except: return None -def zig_String_SummaryProvider(value, _=None): return '"%s"' % zig_String_decode(value) -def zig_String_AsIdentifier(value, pred): - string = zig_String_decode(value) - return string if pred(string) else '@"%s"' % string - -class zig_Optional_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.child = self.value.GetChildMemberWithName('some').unsigned == 1 and self.value.GetChildMemberWithName('data').Clone('child') - except: pass - def has_children(self): return bool(self.child) - def num_children(self): return int(self.child) - def get_child_index(self, name): return 0 if self.child and (name == 'child' or name == '?') else -1 - def get_child_at_index(self, index): return self.child if self.child and index == 0 else None -def zig_Optional_SummaryProvider(value, _=None): - child = value.GetChildMemberWithName('child') - return child or 'null' - -class zig_ErrorUnion_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.error_set = self.value.GetChildMemberWithName('tag').Clone('error_set') - self.payload = self.value.GetChildMemberWithName('value').Clone('payload') if self.error_set.unsigned == 0 else None - except: pass - def has_children(self): return True - def num_children(self): return 1 - def get_child_index(self, name): return 0 if name == ('payload' if self.payload else 'error_set') else -1 - def get_child_at_index(self, index): return self.payload or self.error_set if index == 0 else None - -class zig_TaggedUnion_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.tag = self.value.GetChildMemberWithName('tag') - self.payload = self.value.GetChildMemberWithName('payload').GetChildMemberWithName(self.tag.value) - except: pass - def has_children(self): return True - def num_children(self): return 1 + (self.payload is not None) - def get_child_index(self, name): - try: return ('tag', 'payload').index(name) - except: return -1 - def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None - -# Define Zig Standard Library - -class std_SegmentedList_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.prealloc_segment = self.value.GetChildMemberWithName('prealloc_segment') - self.dynamic_segments = zig_Slice_SynthProvider(self.value.GetChildMemberWithName('dynamic_segments')) - self.dynamic_segments.update() - self.len = self.value.GetChildMemberWithName('len').unsigned - except: pass - def has_children(self): return True - def num_children(self): return self.len - def get_child_index(self, name): - try: return int(name.removeprefix('[').removesuffix(']')) - except: return -1 - def get_child_at_index(self, index): - try: - if index not in range(self.len): return None - prealloc_item_count = len(self.prealloc_segment) - if index < prealloc_item_count: return self.prealloc_segment.child[index] - prealloc_exp = prealloc_item_count.bit_length() - 1 - shelf_index = log2_int(index + 1) if prealloc_item_count == 0 else log2_int(index + prealloc_item_count) - prealloc_exp - 1 - shelf = self.dynamic_segments.get_child_at_index(shelf_index) - box_index = (index + 1) - (1 << shelf_index) if prealloc_item_count == 0 else index + prealloc_item_count - (1 << ((prealloc_exp + 1) + shelf_index)) - elem_type = shelf.type.GetPointeeType() - return shelf.CreateChildAtOffset('[%d]' % index, box_index * elem_type.size, elem_type) - except: return None - -class std_MultiArrayList_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.len = 0 - - value_type = self.value.type - for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): - ptr_self_type, ptr_child_type, ptr_field_type, ptr_entry_type = helper.function.type.GetFunctionArgumentTypes() - if ptr_self_type.GetPointeeType() == value_type: break - else: return - - self.entry_type = ptr_entry_type.GetPointeeType() - self.bytes = self.value.GetChildMemberWithName('bytes') - self.len = self.value.GetChildMemberWithName('len').unsigned - self.capacity = self.value.GetChildMemberWithName('capacity').unsigned - except: pass - def has_children(self): return True - def num_children(self): return self.len - def get_child_index(self, name): - try: return int(name.removeprefix('[').removesuffix(']')) - except: return -1 - def get_child_at_index(self, index): - try: - if index not in range(self.len): return None - offset = 0 - data = lldb.SBData() - for field in self.entry_type.fields: - field_type = field.type.GetPointeeType() - field_size = field_type.size - data.Append(self.bytes.CreateChildAtOffset(field.name, offset + index * field_size, field_type).address_of.data) - offset += self.capacity * field_size - return self.bytes.CreateValueFromData('[%d]' % index, data, self.entry_type) - except: return None -class std_MultiArrayList_Slice_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.len = 0 - - value_type = self.value.type - for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): - ptr_self_type, ptr_child_type, ptr_field_type, ptr_entry_type = helper.function.type.GetFunctionArgumentTypes() - if ptr_self_type.GetPointeeType() == value_type: break - else: return - - self.fields = {member.name: index for index, member in enumerate(ptr_field_type.GetPointeeType().enum_members)} - self.entry_type = ptr_entry_type.GetPointeeType() - self.ptrs = self.value.GetChildMemberWithName('ptrs') - self.len = self.value.GetChildMemberWithName('len').unsigned - self.capacity = self.value.GetChildMemberWithName('capacity').unsigned - except: pass - def has_children(self): return True - def num_children(self): return self.len - def get_child_index(self, name): - try: return int(name.removeprefix('[').removesuffix(']')) - except: return -1 - def get_child_at_index(self, index): - try: - if index not in range(self.len): return None - data = lldb.SBData() - for field in self.entry_type.fields: - field_type = field.type.GetPointeeType() - data.Append(self.ptrs.child[self.fields[field.name.removesuffix('_ptr')]].CreateChildAtOffset(field.name, index * field_type.size, field_type).address_of.data) - return self.ptrs.CreateValueFromData('[%d]' % index, data, self.entry_type) - except: return None - -class std_HashMapUnmanaged_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.capacity = 0 - self.indices = tuple() - - self.metadata = self.value.GetChildMemberWithName('metadata') - if not self.metadata.unsigned: return - - value_type = self.value.type - for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): - ptr_self_type, ptr_hdr_type, ptr_entry_type = helper.function.type.GetFunctionArgumentTypes() - if ptr_self_type.GetPointeeType() == value_type: break - else: return - self.entry_type = ptr_entry_type.GetPointeeType() - - hdr_type = ptr_hdr_type.GetPointeeType() - hdr = self.metadata.CreateValueFromAddress('header', self.metadata.deref.load_addr - hdr_type.size, hdr_type) - self.values = hdr.GetChildMemberWithName('values') - self.keys = hdr.GetChildMemberWithName('keys') - self.capacity = hdr.GetChildMemberWithName('capacity').unsigned - - self.indices = tuple(i for i, value in enumerate(self.metadata.GetPointeeData(0, self.capacity).sint8) if value < 0) - except: pass - def has_children(self): return True - def num_children(self): return len(self.indices) - def get_capacity(self): return self.capacity - def get_child_index(self, name): - try: return int(name.removeprefix('[').removesuffix(']')) - except: return -1 - def get_child_at_index(self, index): - try: - fields = {name: base.CreateChildAtOffset(name, self.indices[index] * pointee_type.size, pointee_type).address_of.data for name, base, pointee_type in ((name, base, base.type.GetPointeeType()) for name, base in (('key_ptr', self.keys), ('value_ptr', self.values)))} - data = lldb.SBData() - for field in self.entry_type.fields: data.Append(fields[field.name]) - return self.metadata.CreateValueFromData('[%d]' % index, data, self.entry_type) - except: return None -def std_HashMapUnmanaged_SummaryProvider(value, _=None): - synth = std_HashMapUnmanaged_SynthProvider(value.GetNonSyntheticValue(), _) - synth.update() - return 'len=%d capacity=%d' % (synth.num_children(), synth.get_capacity()) - -# formats a struct of fields of the form `name_ptr: *Type` by auto dereferencing its fields -class std_Entry_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.children = tuple(child.Clone(child.name.removesuffix('_ptr')) for child in self.value.children if child.type.GetPointeeType().size != 0) - self.indices = {child.name: i for i, child in enumerate(self.children)} - except: pass - def has_children(self): return self.num_children() != 0 - def num_children(self): return len(self.children) - def get_child_index(self, name): return self.indices.get(name) - def get_child_at_index(self, index): return self.children[index].deref if index in range(len(self.children)) else None - -# Define Zig Stage2 Compiler - -class TagAndPayload_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - self.tag = self.value.GetChildMemberWithName('tag') or self.value.GetChildMemberWithName('tag_ptr').deref.Clone('tag') - data = self.value.GetChildMemberWithName('data_ptr') or self.value.GetChildMemberWithName('data') - self.payload = data.GetChildMemberWithName('payload').GetChildMemberWithName(data.GetChildMemberWithName('tag').value) - except: pass - def has_children(self): return True - def num_children(self): return 2 - def get_child_index(self, name): - try: return ('tag', 'payload').index(name) - except: return -1 - def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None - -def InstRef_SummaryProvider(value, _=None): - return value if any(value.unsigned == member.unsigned for member in value.type.enum_members) else ( - 'InternPool.Index(%d)' % value.unsigned if value.unsigned < 0x80000000 else 'instructions[%d]' % (value.unsigned - 0x80000000)) - -def InstIndex_SummaryProvider(value, _=None): - return 'instructions[%d]' % value.unsigned - -class zig_DeclIndex_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - ip = InternPool_Find(self.value.thread) - if not ip: return - self.ptr = ip.GetChildMemberWithName('allocated_decls').GetChildAtIndex(self.value.unsigned).address_of.Clone('decl') - except: pass - def has_children(self): return True - def num_children(self): return 1 - def get_child_index(self, name): return 0 if name == 'decl' else -1 - def get_child_at_index(self, index): return self.ptr if index == 0 else None - -class Module_Namespace__Module_Namespace_Index_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - ip = InternPool_Find(self.value.thread) - if not ip: return - self.ptr = ip.GetChildMemberWithName('allocated_namespaces').GetChildAtIndex(self.value.unsigned).address_of.Clone('namespace') - except: pass - def has_children(self): return True - def num_children(self): return 1 - def get_child_index(self, name): return 0 if name == 'namespace' else -1 - def get_child_at_index(self, index): return self.ptr if index == 0 else None - -class TagOrPayloadPtr_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - value_type = self.value.type - for helper in self.value.target.FindFunctions('%s.dbHelper' % value_type.name, lldb.eFunctionNameTypeFull): - ptr_self_type, ptr_tag_to_payload_map_type = helper.function.type.GetFunctionArgumentTypes() - self_type = ptr_self_type.GetPointeeType() - if self_type == value_type: break - else: return - tag_to_payload_map = {field.name: field.type for field in ptr_tag_to_payload_map_type.GetPointeeType().fields} - - tag = self.value.GetChildMemberWithName('tag_if_small_enough') - if tag.unsigned < page_size: - self.tag = tag.Clone('tag') - self.payload = None - else: - ptr_otherwise = self.value.GetChildMemberWithName('ptr_otherwise') - self.tag = ptr_otherwise.GetChildMemberWithName('tag') - self.payload = ptr_otherwise.Cast(tag_to_payload_map[self.tag.value]).GetChildMemberWithName('data').Clone('payload') - except: pass - def has_children(self): return True - def num_children(self): return 1 + (self.payload is not None) - def get_child_index(self, name): - try: return ('tag', 'payload').index(name) - except: return -1 - def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None - -def Module_Decl_name(decl): - error = lldb.SBError() - return decl.process.ReadCStringFromMemory(decl.GetChildMemberWithName('name').deref.load_addr, 256, error) - -def Module_Namespace_RenderFullyQualifiedName(namespace): - parent = namespace.GetChildMemberWithName('parent') - if parent.unsigned < page_size: return zig_String_decode(namespace.GetChildMemberWithName('file_scope').GetChildMemberWithName('sub_file_path')).removesuffix('.zig').replace('/', '.') - return '.'.join((Module_Namespace_RenderFullyQualifiedName(parent), Module_Decl_name(namespace.GetChildMemberWithName('ty').GetChildMemberWithName('payload').GetChildMemberWithName('owner_decl').GetChildMemberWithName('decl')))) - -def Module_Decl_RenderFullyQualifiedName(decl): return '.'.join((Module_Namespace_RenderFullyQualifiedName(decl.GetChildMemberWithName('src_namespace')), Module_Decl_name(decl))) - -def OwnerDecl_RenderFullyQualifiedName(payload): return Module_Decl_RenderFullyQualifiedName(payload.GetChildMemberWithName('owner_decl').GetChildMemberWithName('decl')) - -def InternPool_Find(thread): - for frame in thread: - ip = frame.FindVariable('ip') or frame.FindVariable('intern_pool') - if ip: return ip - mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module') - if mod: - ip = mod.GetChildMemberWithName('intern_pool') - if ip: return ip - -class InternPool_Index_SynthProvider: - def __init__(self, value, _=None): self.value = value - def update(self): - try: - index_type = self.value.type - for helper in self.value.target.FindFunctions('%s.dbHelper' % index_type.name, lldb.eFunctionNameTypeFull): - ptr_self_type, ptr_tag_to_encoding_map_type = helper.function.type.GetFunctionArgumentTypes() - if ptr_self_type.GetPointeeType() == index_type: break - else: return - tag_to_encoding_map = {field.name: field.type for field in ptr_tag_to_encoding_map_type.GetPointeeType().fields} - - ip = InternPool_Find(self.value.thread) - if not ip: return - self.item = ip.GetChildMemberWithName('items').GetChildAtIndex(self.value.unsigned) - extra = ip.GetChildMemberWithName('extra').GetChildMemberWithName('items') - self.tag = self.item.GetChildMemberWithName('tag').Clone('tag') - self.data = None - self.trailing = None - data = self.item.GetChildMemberWithName('data') - encoding_type = tag_to_encoding_map[self.tag.value] - dynamic_values = {} - for encoding_field in encoding_type.fields: - if encoding_field.name == 'data': - if encoding_field.type.IsPointerType(): - extra_index = data.unsigned - self.data = extra.GetChildAtIndex(extra_index).address_of.Cast(encoding_field.type).deref.Clone('data') - extra_index += encoding_field.type.GetPointeeType().num_fields - else: - self.data = data.Cast(encoding_field.type).Clone('data') - elif encoding_field.name == 'trailing': - trailing_data = lldb.SBData() - for trailing_field in encoding_field.type.fields: - trailing_data.Append(extra.GetChildAtIndex(extra_index).address_of.data) - trailing_len = dynamic_values['trailing.%s.len' % trailing_field.name].unsigned - trailing_data.Append(lldb.SBData.CreateDataFromInt(trailing_len, trailing_data.GetAddressByteSize())) - extra_index += trailing_len - self.trailing = self.data.CreateValueFromData('trailing', trailing_data, encoding_field.type) - else: - for path in encoding_field.type.GetPointeeType().name.removeprefix('%s::' % encoding_type.name).removeprefix('%s.' % encoding_type.name).partition('__')[0].split(' orelse '): - if path.startswith('data.'): - root = self.data - path = path[len('data'):] - else: return - dynamic_value = root.GetValueForExpressionPath(path) - if dynamic_value: - dynamic_values[encoding_field.name] = dynamic_value - break - except: pass - def has_children(self): return True - def num_children(self): return 2 + (self.trailing is not None) - def get_child_index(self, name): - try: return ('tag', 'data', 'trailing').index(name) - except: return -1 - def get_child_at_index(self, index): return (self.tag, self.data, self.trailing)[index] if index in range(3) else None - -def InternPool_NullTerminatedString_SummaryProvider(value, _=None): - try: - ip = InternPool_Find(value.thread) - if not ip: return - items = ip.GetChildMemberWithName('string_bytes').GetChildMemberWithName('items') - b = bytearray() - i = 0 - while True: - x = items.GetChildAtIndex(value.unsigned + i).GetValueAsUnsigned() - if x == 0: break - b.append(x) - i += 1 - s = b.decode(encoding='utf8', errors='backslashreplace') - s1 = s if s.isprintable() else ''.join((c if c.isprintable() else '\\x%02x' % ord(c) for c in s)) - return '"%s"' % s1 - except: - pass - -def type_Type_pointer(payload): - pointee_type = payload.GetChildMemberWithName('pointee_type') - sentinel = payload.GetChildMemberWithName('sentinel').GetChildMemberWithName('child') - align = payload.GetChildMemberWithName('align').unsigned - addrspace = payload.GetChildMemberWithName('addrspace').value - bit_offset = payload.GetChildMemberWithName('bit_offset').unsigned - host_size = payload.GetChildMemberWithName('host_size').unsigned - vector_index = payload.GetChildMemberWithName('vector_index') - allowzero = payload.GetChildMemberWithName('allowzero').unsigned - const = not payload.GetChildMemberWithName('mutable').unsigned - volatile = payload.GetChildMemberWithName('volatile').unsigned - size = payload.GetChildMemberWithName('size').value - - if size == 'One': summary = '*' - elif size == 'Many': summary = '[*' - elif size == 'Slice': summary = '[' - elif size == 'C': summary = '[*c' - if sentinel: summary += ':%s' % value_Value_SummaryProvider(sentinel) - if size != 'One': summary += ']' - if allowzero: summary += 'allowzero ' - if align != 0 or host_size != 0 or vector_index.value != 'none': summary += 'align(%d%s%s) ' % (align, ':%d:%d' % (bit_offset, host_size) if bit_offset != 0 or host_size != 0 else '', ':?' if vector_index.value == 'runtime' else ':%d' % vector_index.unsigned if vector_index.value != 'none' else '') - if addrspace != 'generic': summary += 'addrspace(.%s) ' % addrspace - if const: summary += 'const ' - if volatile: summary += 'volatile ' - summary += type_Type_SummaryProvider(pointee_type) - return summary - -def type_Type_function(payload): - param_types = payload.GetChildMemberWithName('param_types').children - comptime_params = payload.GetChildMemberWithName('comptime_params').GetPointeeData(0, len(param_types)).uint8 - return_type = payload.GetChildMemberWithName('return_type') - alignment = payload.GetChildMemberWithName('alignment').unsigned - noalias_bits = payload.GetChildMemberWithName('noalias_bits').unsigned - cc = payload.GetChildMemberWithName('cc').value - is_var_args = payload.GetChildMemberWithName('is_var_args').unsigned - - return 'fn(%s)%s%s %s' % (', '.join(tuple(''.join(('comptime ' if comptime_param else '', 'noalias ' if noalias_bits & 1 << i else '', type_Type_SummaryProvider(param_type))) for i, (comptime_param, param_type) in enumerate(zip(comptime_params, param_types))) + (('...',) if is_var_args else ())), ' align(%d)' % alignment if alignment != 0 else '', ' callconv(.%s)' % cc if cc != 'Unspecified' else '', type_Type_SummaryProvider(return_type)) - -def type_Type_SummaryProvider(value, _=None): - tag = value.GetChildMemberWithName('tag').value - return type_tag_handlers.get(tag, lambda payload: tag)(value.GetChildMemberWithName('payload')) - -type_tag_handlers = { - 'atomic_order': lambda payload: 'std.builtin.AtomicOrder', - 'atomic_rmw_op': lambda payload: 'std.builtin.AtomicRmwOp', - 'calling_convention': lambda payload: 'std.builtin.CallingConvention', - 'address_space': lambda payload: 'std.builtin.AddressSpace', - 'float_mode': lambda payload: 'std.builtin.FloatMode', - 'reduce_op': lambda payload: 'std.builtin.ReduceOp', - 'modifier': lambda payload: 'std.builtin.CallModifier', - 'prefetch_options': lambda payload: 'std.builtin.PrefetchOptions', - 'export_options': lambda payload: 'std.builtin.ExportOptions', - 'extern_options': lambda payload: 'std.builtin.ExternOptions', - 'type_info': lambda payload: 'std.builtin.Type', - - 'enum_literal': lambda payload: '@TypeOf(.enum_literal)', - 'null': lambda payload: '@TypeOf(null)', - 'undefined': lambda payload: '@TypeOf(undefined)', - 'empty_struct_literal': lambda payload: '@TypeOf(.{})', - - 'anyerror_void_error_union': lambda payload: 'anyerror!void', - 'slice_const_u8': lambda payload: '[]const u8', - 'slice_const_u8_sentinel_0': lambda payload: '[:0]const u8', - 'fn_noreturn_no_args': lambda payload: 'fn() noreturn', - 'fn_void_no_args': lambda payload: 'fn() void', - 'fn_naked_noreturn_no_args': lambda payload: 'fn() callconv(.Naked) noreturn', - 'fn_ccc_void_no_args': lambda payload: 'fn() callconv(.c) void', - 'single_const_pointer_to_comptime_int': lambda payload: '*const comptime_int', - 'manyptr_u8': lambda payload: '[*]u8', - 'manyptr_const_u8': lambda payload: '[*]const u8', - 'manyptr_const_u8_sentinel_0': lambda payload: '[*:0]const u8', - - 'function': type_Type_function, - 'error_union': lambda payload: '%s!%s' % (type_Type_SummaryProvider(payload.GetChildMemberWithName('error_set')), type_Type_SummaryProvider(payload.GetChildMemberWithName('payload'))), - 'array_u8': lambda payload: '[%d]u8' % payload.unsigned, - 'array_u8_sentinel_0': lambda payload: '[%d:0]u8' % payload.unsigned, - 'vector': lambda payload: '@Vector(%d, %s)' % (payload.GetChildMemberWithName('len').unsigned, type_Type_SummaryProvider(payload.GetChildMemberWithName('elem_type'))), - 'array': lambda payload: '[%d]%s' % (payload.GetChildMemberWithName('len').unsigned, type_Type_SummaryProvider(payload.GetChildMemberWithName('elem_type'))), - 'array_sentinel': lambda payload: '[%d:%s]%s' % (payload.GetChildMemberWithName('len').unsigned, value_Value_SummaryProvider(payload.GetChildMemberWithName('sentinel')), type_Type_SummaryProvider(payload.GetChildMemberWithName('elem_type'))), - 'tuple': lambda payload: 'tuple{%s}' % ', '.join(('comptime %%s = %s' % value_Value_SummaryProvider(value) if value.GetChildMemberWithName('tag').value != 'unreachable_value' else '%s') % type_Type_SummaryProvider(type) for type, value in zip(payload.GetChildMemberWithName('types').children, payload.GetChildMemberWithName('values').children)), - 'anon_struct': lambda payload: 'struct{%s}' % ', '.join(('comptime %%s: %%s = %s' % value_Value_SummaryProvider(value) if value.GetChildMemberWithName('tag').value != 'unreachable_value' else '%s: %s') % (zig_String_AsIdentifier(name, zig_IsFieldName), type_Type_SummaryProvider(type)) for name, type, value in zip(payload.GetChildMemberWithName('names').children, payload.GetChildMemberWithName('types').children, payload.GetChildMemberWithName('values').children)), - 'pointer': type_Type_pointer, - 'single_const_pointer': lambda payload: '*const %s' % type_Type_SummaryProvider(payload), - 'single_mut_pointer': lambda payload: '*%s' % type_Type_SummaryProvider(payload), - 'many_const_pointer': lambda payload: '[*]const %s' % type_Type_SummaryProvider(payload), - 'many_mut_pointer': lambda payload: '[*]%s' % type_Type_SummaryProvider(payload), - 'c_const_pointer': lambda payload: '[*c]const %s' % type_Type_SummaryProvider(payload), - 'c_mut_pointer': lambda payload: '[*c]%s' % type_Type_SummaryProvider(payload), - 'slice_const': lambda payload: '[]const %s' % type_Type_SummaryProvider(payload), - 'mut_slice': lambda payload: '[]%s' % type_Type_SummaryProvider(payload), - 'int_signed': lambda payload: 'i%d' % payload.unsigned, - 'int_unsigned': lambda payload: 'u%d' % payload.unsigned, - 'optional': lambda payload: '?%s' % type_Type_SummaryProvider(payload), - 'optional_single_mut_pointer': lambda payload: '?*%s' % type_Type_SummaryProvider(payload), - 'optional_single_const_pointer': lambda payload: '?*const %s' % type_Type_SummaryProvider(payload), - 'anyframe_T': lambda payload: 'anyframe->%s' % type_Type_SummaryProvider(payload), - 'error_set': lambda payload: type_tag_handlers['error_set_merged'](payload.GetChildMemberWithName('names')), - 'error_set_single': lambda payload: 'error{%s}' % zig_String_AsIdentifier(payload, zig_IsFieldName), - 'error_set_merged': lambda payload: 'error{%s}' % ','.join(zig_String_AsIdentifier(child.GetChildMemberWithName('key'), zig_IsFieldName) for child in payload.GetChildMemberWithName('entries').children), - 'error_set_inferred': lambda payload: '@typeInfo(@typeInfo(@TypeOf(%s)).@"fn".return_type.?).error_union.error_set' % OwnerDecl_RenderFullyQualifiedName(payload.GetChildMemberWithName('func')), - - 'enum_full': OwnerDecl_RenderFullyQualifiedName, - 'enum_nonexhaustive': OwnerDecl_RenderFullyQualifiedName, - 'enum_numbered': OwnerDecl_RenderFullyQualifiedName, - 'enum_simple': OwnerDecl_RenderFullyQualifiedName, - 'struct': OwnerDecl_RenderFullyQualifiedName, - 'union': OwnerDecl_RenderFullyQualifiedName, - 'union_safety_tagged': OwnerDecl_RenderFullyQualifiedName, - 'union_tagged': OwnerDecl_RenderFullyQualifiedName, - 'opaque': OwnerDecl_RenderFullyQualifiedName, -} - -def value_Value_str_lit(payload): - for frame in payload.thread: - mod = frame.FindVariable('zcu') or frame.FindVariable('mod') or frame.FindVariable('module') - if mod: break - else: return - return '"%s"' % zig_String_decode(mod.GetChildMemberWithName('string_literal_bytes').GetChildMemberWithName('items'), payload.GetChildMemberWithName('index').unsigned, payload.GetChildMemberWithName('len').unsigned) - -def value_Value_SummaryProvider(value, _=None): - tag = value.GetChildMemberWithName('tag').value - return value_tag_handlers.get(tag, lambda payload: tag.removesuffix('_type'))(value.GetChildMemberWithName('payload')) - -value_tag_handlers = { - 'undef': lambda payload: 'undefined', - 'zero': lambda payload: '0', - 'one': lambda payload: '1', - 'void_value': lambda payload: '{}', - 'unreachable_value': lambda payload: 'unreachable', - 'null_value': lambda payload: 'null', - 'bool_true': lambda payload: 'true', - 'bool_false': lambda payload: 'false', - - 'empty_struct_value': lambda payload: '.{}', - 'empty_array': lambda payload: '.{}', - - 'ty': type_Type_SummaryProvider, - 'int_type': lambda payload: '%c%d' % (payload.GetChildMemberWithName('bits').unsigned, 's' if payload.GetChildMemberWithName('signed').unsigned == 1 else 'u'), - 'int_u64': lambda payload: '%d' % payload.unsigned, - 'int_i64': lambda payload: '%d' % payload.signed, - 'int_big_positive': lambda payload: sum(child.unsigned << i * child.type.size * 8 for i, child in enumerate(payload.children)), - 'int_big_negative': lambda payload: '-%s' % value_tag_handlers['int_big_positive'](payload), - 'function': OwnerDecl_RenderFullyQualifiedName, - 'extern_fn': OwnerDecl_RenderFullyQualifiedName, - 'variable': lambda payload: value_Value_SummaryProvider(payload.GetChildMemberWithName('decl').GetChildMemberWithName('val')), - 'runtime_value': value_Value_SummaryProvider, - 'decl_ref': lambda payload: value_Value_SummaryProvider(payload.GetChildMemberWithName('decl').GetChildMemberWithName('val')), - 'decl_ref_mut': lambda payload: value_Value_SummaryProvider(payload.GetChildMemberWithName('decl_index').GetChildMemberWithName('decl').GetChildMemberWithName('val')), - 'comptime_field_ptr': lambda payload: '&%s' % value_Value_SummaryProvider(payload.GetChildMemberWithName('field_val')), - 'elem_ptr': lambda payload: '(%s)[%d]' % (value_Value_SummaryProvider(payload.GetChildMemberWithName('array_ptr')), payload.GetChildMemberWithName('index').unsigned), - 'field_ptr': lambda payload: '(%s).field[%d]' % (value_Value_SummaryProvider(payload.GetChildMemberWithName('container_ptr')), payload.GetChildMemberWithName('field_index').unsigned), - 'bytes': lambda payload: '"%s"' % zig_String_decode(payload), - 'str_lit': value_Value_str_lit, - 'repeated': lambda payload: '.{%s} ** _' % value_Value_SummaryProvider(payload), - 'empty_array_sentinel': lambda payload: '.{%s}' % value_Value_SummaryProvider(payload), - 'slice': lambda payload: '(%s)[0..%s]' % tuple(value_Value_SummaryProvider(payload.GetChildMemberWithName(name)) for name in ('ptr', 'len')), - 'float_16': lambda payload: payload.value, - 'float_32': lambda payload: payload.value, - 'float_64': lambda payload: payload.value, - 'float_80': lambda payload: payload.value, - 'float_128': lambda payload: payload.value, - 'enum_literal': lambda payload: '.%s' % zig_String_AsIdentifier(payload, zig_IsFieldName), - 'enum_field_index': lambda payload: 'field[%d]' % payload.unsigned, - 'error': lambda payload: 'error.%s' % zig_String_AsIdentifier(payload.GetChildMemberWithName('name'), zig_IsFieldName), - 'eu_payload': value_Value_SummaryProvider, - 'eu_payload_ptr': lambda payload: '&((%s).* catch unreachable)' % value_Value_SummaryProvider(payload.GetChildMemberWithName('container_ptr')), - 'opt_payload': value_Value_SummaryProvider, - 'opt_payload_ptr': lambda payload: '&(%s).*.?' % value_Value_SummaryProvider(payload.GetChildMemberWithName('container_ptr')), - 'aggregate': lambda payload: '.{%s}' % ', '.join(map(value_Value_SummaryProvider, payload.children)), - 'union': lambda payload: '.{.%s = %s}' % tuple(value_Value_SummaryProvider(payload.GetChildMemberWithName(name)) for name in ('tag', 'val')), - - 'lazy_align': lambda payload: '@alignOf(%s)' % type_Type_SummaryProvider(payload), - 'lazy_size': lambda payload: '@sizeOf(%s)' % type_Type_SummaryProvider(payload), -} - -# Initialize - -def add(debugger, *, category, regex=False, type, identifier=None, synth=False, inline_children=False, expand=False, summary=False): - prefix = '.'.join((__name__, (identifier or type).replace('.', '_').replace(':', '_'))) - if summary: debugger.HandleCommand('type summary add --category %s%s%s "%s"' % (category, ' --inline-children' if inline_children else ''.join((' --expand' if expand else '', ' --python-function %s_SummaryProvider' % prefix if summary == True else ' --summary-string "%s"' % summary)), ' --regex' if regex else '', type)) - if synth: debugger.HandleCommand('type synthetic add --category %s%s --python-class %s_SynthProvider "%s"' % (category, ' --regex' if regex else '', prefix, type)) - -def MultiArrayList_Entry(type): return 'multi_array_list\\.MultiArrayList\\(%s\\)\\.Entry__struct_[1-9][0-9]*$' % type - -def __lldb_init_module(debugger, _=None): - # Initialize Zig Categories - debugger.HandleCommand('type category define --language c99 zig.lang zig.std') - - # Initialize Zig Language - add(debugger, category='zig.lang', regex=True, type='^\\[\\]', identifier='zig_Slice', synth=True, expand=True, summary='len=${svar%#}') - add(debugger, category='zig.lang', type='[]u8', identifier='zig_String', summary=True) - add(debugger, category='zig.lang', regex=True, type='^\\?', identifier='zig_Optional', synth=True, summary=True) - add(debugger, category='zig.lang', regex=True, type='^(error{.*}|anyerror)!', identifier='zig_ErrorUnion', synth=True, inline_children=True, summary=True) - - # Initialize Zig Standard Library - add(debugger, category='zig.std', type='mem.Allocator', summary='${var.ptr}') - add(debugger, category='zig.std', regex=True, type='^segmented_list\\.SegmentedList\\(.*\\)$', identifier='std_SegmentedList', synth=True, expand=True, summary='len=${var.len}') - add(debugger, category='zig.std', regex=True, type='multi_array_list\\.MultiArrayList\\(.*\\)$', identifier='std_MultiArrayList', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}') - add(debugger, category='zig.std', regex=True, type='multi_array_list\\.MultiArrayList\\(.*\\)\\.Slice$', identifier='std_MultiArrayList_Slice', synth=True, expand=True, summary='len=${var.len} capacity=${var.capacity}') - add(debugger, category='zig.std', regex=True, type=MultiArrayList_Entry('.*'), identifier='std_Entry', synth=True, inline_children=True, summary=True) - add(debugger, category='zig.std', regex=True, type='^hash_map\\.HashMapUnmanaged\\(.*\\)$', identifier='std_HashMapUnmanaged', synth=True, expand=True, summary=True) - add(debugger, category='zig.std', regex=True, type='^hash_map\\.HashMapUnmanaged\\(.*\\)\\.Entry$', identifier = 'std_Entry', synth=True, inline_children=True, summary=True) - - # Initialize Zig Stage2 Compiler - add(debugger, category='zig.stage2', type='Zir.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) - add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Zir\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) - add(debugger, category='zig.stage2', regex=True, type='^Zir\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) - add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Ref', identifier='InstRef', summary=True) - add(debugger, category='zig.stage2', type='Zir.Inst::Zir.Inst.Index', identifier='InstIndex', summary=True) - add(debugger, category='zig.stage2', type='Air.Inst', identifier='TagAndPayload', synth=True, inline_children=True, summary=True) - add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Ref', identifier='InstRef', summary=True) - add(debugger, category='zig.stage2', type='Air.Inst::Air.Inst.Index', identifier='InstIndex', summary=True) - add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True) - add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True) - add(debugger, category='zig.stage2', type='zig.DeclIndex', synth=True) - add(debugger, category='zig.stage2', type='Module.Namespace::Module.Namespace.Index', synth=True) - add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True) - add(debugger, category='zig.stage2', type='InternPool.Index', synth=True) - add(debugger, category='zig.stage2', type='InternPool.NullTerminatedString', summary=True) - add(debugger, category='zig.stage2', type='InternPool.Key', identifier='zig_TaggedUnion', synth=True) - add(debugger, category='zig.stage2', type='InternPool.Key.Int.Storage', identifier='zig_TaggedUnion', synth=True) - add(debugger, category='zig.stage2', type='InternPool.Key.ErrorUnion.Value', identifier='zig_TaggedUnion', synth=True) - add(debugger, category='zig.stage2', type='InternPool.Key.Float.Storage', identifier='zig_TaggedUnion', synth=True) - add(debugger, category='zig.stage2', type='InternPool.Key.Ptr.Addr', identifier='zig_TaggedUnion', synth=True) - add(debugger, category='zig.stage2', type='InternPool.Key.Aggregate.Storage', identifier='zig_TaggedUnion', synth=True) - add(debugger, category='zig.stage2', type='arch.x86_64.CodeGen.MCValue', identifier='zig_TaggedUnion', synth=True, inline_children=True, summary=True) diff --git a/misctools/machbench.zig b/misctools/machbench.zig deleted file mode 100644 index 18146b81065b..000000000000 --- a/misctools/machbench.zig +++ /dev/null @@ -1,135 +0,0 @@ -// most of this file is copy pasted from other files in misctools -const std = @import("std"); -const bun = @import("bun"); -const string = []const u8; -const Output = bun.Output; -const Global = bun.Global; -const Environment = bun.Environment; -const strings = bun.strings; -const MutableString = bun.MutableString; -const stringZ = [:0]const u8; -const default_allocator = bun.default_allocator; -const clap = @import("../src/deps/zig-clap/clap.zig"); - -const URL = @import("../src/url.zig").URL; -const Headers = bun.http.Headers; -const Method = @import("../src/http/Method.zig").Method; -const ColonListType = @import("../src/cli/colon_list_type.zig").ColonListType; -const HeadersTuple = ColonListType(string, noop_resolver); -const path_handler = @import("../src/resolver/resolve_path.zig"); -const NetworkThread = bun.http.NetworkThread; -const HTTP = bun.http; -fn noop_resolver(in: string) !string { - return in; -} - -var waker: bun.Async.Waker = undefined; - -fn spamMe(count: usize) void { - Output.Source.configureNamedThread("1"); - defer Output.flush(); - var timer = std.time.Timer.start() catch unreachable; - - var i: usize = 0; - while (i < count) : (i += 1) { - waker.wake() catch unreachable; - } - Output.prettyErrorln("[EVFILT_MACHPORT] Sent {any}", .{std.fmt.fmtDuration(timer.read())}); -} -const thread_count = 1; -pub fn machMain(runs: usize) anyerror!void { - defer Output.flush(); - waker = try bun.Async.Waker.init(bun.default_allocator); - - var args = try std.process.argsAlloc(bun.default_allocator); - const count = std.fmt.parseInt(usize, args[args.len - 1], 10) catch 1024; - var elapsed: u64 = 0; - - var remaining_runs: usize = runs; - while (remaining_runs > 0) : (remaining_runs -= 1) { - var threads: [thread_count]std.Thread = undefined; - var j: usize = 0; - while (j < thread_count) : (j += 1) { - threads[j] = try std.Thread.spawn(.{}, spamMe, .{count}); - } - - var timer = try std.time.Timer.start(); - var i: usize = 0; - while (i < count * thread_count) : (i += 1) { - i += try waker.wait(); - } - - j = 0; - while (j < thread_count) : (j += 1) { - threads[j].join(); - } - elapsed += timer.read(); - } - - Output.prettyErrorln("[EVFILT_MACHPORT] Recv {any}", .{std.fmt.fmtDuration(elapsed)}); -} -var user_waker: bun.Async.UserFilterWaker = undefined; - -fn spamMeUserFilter(count: usize) void { - Output.Source.configureNamedThread("2"); - defer Output.flush(); - var timer = std.time.Timer.start() catch unreachable; - var i: usize = 0; - while (i < count * thread_count) : (i += 1) { - user_waker.wake() catch unreachable; - } - - Output.prettyErrorln("[EVFILT_USER] Sent {any}", .{std.fmt.fmtDuration(timer.read())}); -} -pub fn userMain(runs: usize) anyerror!void { - defer Output.flush(); - user_waker = try bun.Async.UserFilterWaker.init(bun.default_allocator); - - var args = try std.process.argsAlloc(bun.default_allocator); - const count = std.fmt.parseInt(usize, args[args.len - 1], 10) catch 1024; - var remaining_runs = runs; - var elapsed: u64 = 0; - - while (remaining_runs > 0) : (remaining_runs -= 1) { - var threads: [thread_count]std.Thread = undefined; - var j: usize = 0; - while (j < thread_count) : (j += 1) { - threads[j] = try std.Thread.spawn(.{}, spamMeUserFilter, .{count}); - } - - var timer = try std.time.Timer.start(); - var i: usize = 0; - while (i < count) { - i += try user_waker.wait(); - } - - j = 0; - while (j < thread_count) : (j += 1) { - threads[j].join(); - } - elapsed += timer.read(); - } - - Output.prettyErrorln("[EVFILT_USER] Recv {any}", .{std.fmt.fmtDuration(elapsed)}); - Output.flush(); -} - -pub fn main() anyerror!void { - var stdout_ = std.io.getStdOut(); - var stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); - - var args = try std.process.argsAlloc(bun.default_allocator); - const count = std.fmt.parseInt(usize, args[args.len - 1], 10) catch 1024; - Output.prettyErrorln("For {d} messages and {d} threads:", .{ count, thread_count }); - Output.flush(); - defer Output.flush(); - const runs = if (std.posix.getenv("RUNS")) |run_count| try std.fmt.parseInt(usize, run_count, 10) else 1; - - if (std.posix.getenv("NO_MACH") == null) - try machMain(runs); - - if (std.posix.getenv("NO_USER") == null) - try userMain(runs); -} diff --git a/misctools/readlink-getfd.zig b/misctools/readlink-getfd.zig deleted file mode 100644 index 6321f6c14956..000000000000 --- a/misctools/readlink-getfd.zig +++ /dev/null @@ -1,65 +0,0 @@ -const std = @import("std"); - -const path_handler = @import("../src/resolver/resolve_path.zig"); -const bun = @import("bun"); -const string = []const u8; -const Output = bun.Output; -const Global = bun.Global; -const Environment = bun.Environment; -const strings = bun.strings; -const MutableString = bun.MutableString; -const stringZ = [:0]const u8; -const default_allocator = bun.default_allocator; - -// zig build-exe -Doptimize=ReleaseFast --main-pkg-path ../ ./readlink-getfd.zig -pub fn main() anyerror!void { - var stdout_ = std.io.getStdOut(); - var stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); - defer Output.flush(); - - var args_buffer: [8192 * 2]u8 = undefined; - var fixed_buffer = std.heap.FixedBufferAllocator.init(&args_buffer); - var allocator = fixed_buffer.allocator(); - - var args = std.mem.bytesAsSlice([]u8, try std.process.argsAlloc(allocator)); - - const to_resolve = args[args.len - 1]; - const cwd = try bun.getcwdAlloc(allocator); - var path: []u8 = undefined; - var out_buffer: bun.PathBuffer = undefined; - - var j: usize = 0; - while (j < 1000) : (j += 1) { - var parts = [1][]const u8{to_resolve}; - var joined_buf: bun.PathBuffer = undefined; - var joined = path_handler.joinAbsStringBuf( - cwd, - &joined_buf, - &parts, - .loose, - ); - joined_buf[joined.len] = 0; - const os = std.posix; - const joined_z: [:0]const u8 = joined_buf[0..joined.len :0]; - const O_PATH = if (@hasDecl(bun.O, "PATH")) bun.O.PATH else 0; - - var file = std.posix.openZ(joined_z, O_PATH | bun.O.CLOEXEC, 0) catch |err| { - switch (err) { - error.NotDir, error.FileNotFound => { - Output.prettyError("404 Not Found: \"{s}\"", .{joined_z}); - Global.exit(1); - }, - else => { - return err; - }, - } - }; - - path = try std.os.getFdPath(file.handle, &out_buffer); - file.close(); - } - - Output.print("{s}", .{path}); -} diff --git a/misctools/readlink-realpath.zig b/misctools/readlink-realpath.zig deleted file mode 100644 index 0cc049683991..000000000000 --- a/misctools/readlink-realpath.zig +++ /dev/null @@ -1,38 +0,0 @@ -const std = @import("std"); - -const path_handler = @import("../src/resolver/resolve_path.zig"); -const bun = @import("bun"); -const string = []const u8; -const Output = bun.Output; -const Global = bun.Global; -const Environment = bun.Environment; -const strings = bun.strings; -const MutableString = bun.MutableString; -const stringZ = [:0]const u8; -const default_allocator = bun.default_allocator; - -// zig build-exe -Doptimize=ReleaseFast --main-pkg-path ../ ./readlink-getfd.zig -pub fn main() anyerror!void { - var stdout_ = std.io.getStdOut(); - var stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); - defer Output.flush(); - - var args_buffer: [8192 * 2]u8 = undefined; - var fixed_buffer = std.heap.FixedBufferAllocator.init(&args_buffer); - var allocator = fixed_buffer.allocator(); - - var args = std.mem.bytesAsSlice([]u8, try std.process.argsAlloc(allocator)); - - const to_resolve = args[args.len - 1]; - var out_buffer: bun.PathBuffer = undefined; - var path: []u8 = undefined; - - var j: usize = 0; - while (j < 1000) : (j += 1) { - path = try std.posix.realpathZ(to_resolve, &out_buffer); - } - - Output.print("{s}", .{path}); -} diff --git a/misctools/tgz.zig b/misctools/tgz.zig deleted file mode 100644 index cee3b45f5a40..000000000000 --- a/misctools/tgz.zig +++ /dev/null @@ -1,95 +0,0 @@ -const std = @import("std"); - -const path_handler = @import("../src/resolver/resolve_path.zig"); -const bun = @import("bun"); -const string = []const u8; -const Output = bun.Output; -const Global = bun.Global; -const Environment = bun.Environment; -const strings = bun.strings; -const MutableString = bun.MutableString; -const stringZ = [:0]const u8; -const default_allocator = bun.default_allocator; - -const Archive = @import("../src/libarchive/libarchive.zig").Archive; -const Zlib = @import("../src/zlib.zig"); - -const RecognizedExtensions = std.ComptimeStringMap(void, .{ - .{ ".tgz", void{} }, - .{ ".tar", void{} }, - .{ ".gz", void{} }, -}); - -var buf: [32 * 1024 * 1024]u8 = undefined; - -// zig build-exe -Doptimize=ReleaseFast --main-pkg-path ../ ./tgz.zig ../src/deps/zlib/libz.a ../src/deps/libarchive.a -lc -liconv -// zig build-exe -Doptimize=ReleaseFast --main-pkg-path ../ ./tgz.zig ../src/deps/zlib/libz.a ../src/deps/libarchive.a -lc -liconv -pub fn main() anyerror!void { - var stdout_ = std.io.getStdOut(); - var stderr_ = std.io.getStdErr(); - var output_source = Output.Source.init(stdout_, stderr_); - Output.Source.set(&output_source); - defer Output.flush(); - var args = try std.process.argsAlloc(std.heap.c_allocator); - if (args.len < 2) { - Output.prettyErrorln("usage: tgz ./tar.gz", .{}); - Global.exit(1); - } - - var tarball_path_buf: bun.PathBuffer = undefined; - var basename = std.fs.path.basename(bun.asByteSlice(args[args.len - 1])); - while (RecognizedExtensions.has(std.fs.path.extension(basename))) { - basename = basename[0 .. basename.len - std.fs.path.extension(basename).len]; - } - - var parts = [_][]const u8{ - bun.asByteSlice(args[args.len - 1]), - }; - - const tarball_path = path_handler.joinAbsStringBuf(try bun.getcwdAlloc(std.heap.c_allocator), &tarball_path_buf, &parts, .auto); - Output.prettyErrorln("Tarball Path: {s}", .{tarball_path}); - var folder = basename; - - // var dir = try std.fs.cwd().makeOpenPath(folder, .{ .iterate = true }); - - var tarball = try std.fs.cwd().openFile(tarball_path, .{ .mode = .read_only }); - - var tarball_buf_list = std.ArrayListUnmanaged(u8){}; - - var file_size = try tarball.getEndPos(); - var file_buf: []u8 = undefined; - var file_buf_cap: usize = 0; - - if (file_size < buf.len) { - file_buf = buf[0..try tarball.readAll(&buf)]; - file_buf_cap = buf.len; - } else { - file_buf = try tarball.readToEndAlloc( - std.heap.c_allocator, - file_size, - ); - file_buf_cap = file_buf.len; - } - - if (std.mem.eql(u8, std.fs.path.extension(tarball_path), ".gz") or std.mem.eql(u8, std.fs.path.extension(tarball_path), ".tgz")) { - tarball_buf_list = try std.ArrayListUnmanaged(u8).initCapacity(std.heap.c_allocator, 1024); - var gunzip = try Zlib.ZlibReaderArrayList.init(file_buf, &tarball_buf_list, std.heap.c_allocator); - try gunzip.readAll(); - gunzip.deinit(); - Output.prettyErrorln("Decompressed {d} -> {d}\n", .{ file_buf.len, tarball_buf_list.items.len }); - } else { - tarball_buf_list = std.ArrayListUnmanaged(u8){ .capacity = file_buf.len, .items = file_buf }; - } - - _ = try Archive.extractToDisk( - file_buf, - folder, - null, - void, - void{}, - .{ - .depth_to_skip = 1, - .close_handles = false, - }, - ); -} diff --git a/package.json b/package.json index abd28164496e..9ca95609b3bd 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,6 @@ "build:local": "bun scripts/build.ts --profile=debug-local --build-dir=build/debug-local", "build:release:local": "bun scripts/build.ts --profile=release-local --build-dir=build/release-local", "run:linux": "docker run --rm -v \"$PWD:/root/bun/\" -w /root/bun ghcr.io/oven-sh/bun-development-docker-image", - "css-properties": "bun run src/css/properties/generate_properties.ts", "uv-posix-stubs": "bun run src/jsc/bindings/libuv/generate_uv_posix_stubs.ts", "bump": "bun ./scripts/bump.ts", "jsc:build": "bun scripts/build.ts --profile=release-local --build-dir=build/release-local --target=WebKit", @@ -69,7 +68,6 @@ "test": "node scripts/runner.node.mjs --exec-path ./build/debug/bun-debug", "testleak": "BUN_DESTRUCT_VM_ON_EXIT=1 ASAN_OPTIONS=detect_leaks=1 LSAN_OPTIONS=malloc_context_size=100:print_suppressions=1:suppressions=$npm_config_local_prefix/test/leaksan.supp ./build/debug/bun-debug", "test:release": "node scripts/runner.node.mjs --exec-path ./build/release/bun", - "banned": "bun test test/internal/ban-words.test.ts", "rust:check": "cargo check --workspace --keep-going", "rust:check-all": "bun scripts/rust-check-all.ts", "rust:clippy": "cargo clippy --workspace --no-deps --keep-going", diff --git a/packages/bun-usockets/src/crypto/openssl.c b/packages/bun-usockets/src/crypto/openssl.c index 5b17b6f73062..9d736d00fc54 100644 --- a/packages/bun-usockets/src/crypto/openssl.c +++ b/packages/bun-usockets/src/crypto/openssl.c @@ -358,7 +358,7 @@ static void ssl_flush_pending_session(struct us_socket_t *s) { } } -/* Defined in Zig (`SSLContextCache.zig`): tombstones the cache entry on +/* Defined in `src/runtime/api/bun/SSLContextCache.rs`: tombstones the cache entry on * SSL_CTX refcount→0 so the per-VM weak SSL_CTX cache learns the pointer is * dead without holding a ref of its own. */ extern void bun_ssl_ctx_cache_on_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, diff --git a/packages/bun-usockets/src/eventing/epoll_kqueue.c b/packages/bun-usockets/src/eventing/epoll_kqueue.c index 93a470eaa453..8dfdcc39a67a 100644 --- a/packages/bun-usockets/src/eventing/epoll_kqueue.c +++ b/packages/bun-usockets/src/eventing/epoll_kqueue.c @@ -364,7 +364,7 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout us_internal_loop_pre(loop); /* loop_pre runs lsquic_engine_process_conns and stores the soonest - * earliest_adv_tick. The JS event loop folds this in via Timer.zig; other + * earliest_adv_tick. The JS event loop folds this in via src/runtime/timer/mod.rs; other * callers of us_loop_run_bun_tick (HTTP thread) pass NULL, so fold it * here so QUIC retransmit/idle timers fire without other I/O waking us. */ struct timespec quic_ts; diff --git a/packages/bun-usockets/src/internal/internal.h b/packages/bun-usockets/src/internal/internal.h index 782af0cce9b7..a3a7617017e5 100644 --- a/packages/bun-usockets/src/internal/internal.h +++ b/packages/bun-usockets/src/internal/internal.h @@ -113,9 +113,9 @@ struct addrinfo_result { int error; }; -/* Dispatch — defined out-of-library (Zig: src/deps/uws/dispatch.zig). loop.c +/* Dispatch — defined out-of-library (src/runtime/socket/uws_dispatch.rs). loop.c * never reads s->group->vtable directly; it calls these and the closed-world - * switch on s->kind decides whether to direct-call into Zig/C++ or fall back + * switch on s->kind decides whether to direct-call into Rust/C++ or fall back * to the vtable. Signatures track the vtable entries (us_dispatch_handshake * drops the trailing custom_data — dispatch always passes NULL). */ extern struct us_socket_t *us_dispatch_open(us_socket_r s, int is_client, char *ip, int ip_length); diff --git a/packages/bun-usockets/src/internal/loop_data.h b/packages/bun-usockets/src/internal/loop_data.h index 801649b2d1f8..4294a6636be4 100644 --- a/packages/bun-usockets/src/internal/loop_data.h +++ b/packages/bun-usockets/src/internal/loop_data.h @@ -32,7 +32,7 @@ typedef void* zig_mutex_t; #error "Unsupported platform" #endif -// IMPORTANT: When changing this, don't forget to update the zig version in uws.zig as well! +// IMPORTANT: When changing this, don't forget to update the Rust mirror in src/uws_sys/InternalLoopData.rs as well! struct us_quic_socket_context_s; struct us_internal_loop_data_t { diff --git a/packages/bun-usockets/src/quic.c b/packages/bun-usockets/src/quic.c index c4ef024805fd..0c33fe798519 100644 --- a/packages/bun-usockets/src/quic.c +++ b/packages/bun-usockets/src/quic.c @@ -162,7 +162,7 @@ void us_quic_loop_process(struct us_loop_t *loop) { } } /* Relative µs from now (≤0 means "tick due"). On epoll/kqueue, - * getTimeout() in Timer.zig folds this into the epoll_pwait2 timeout — + * getTimeout() in src/runtime/timer/mod.rs folds this into the epoll_pwait2 timeout — * no timerfd. On libuv there's no equivalent hook into the poll * timeout, so arm a fallthrough uv_timer instead. */ loop->data.quic_next_tick_us = have_tick ? (min_diff < 0 ? 0 : min_diff) : -1; diff --git a/packages/bun-uws/src/App.h b/packages/bun-uws/src/App.h index 8bb7b0361410..5209ab836cdc 100644 --- a/packages/bun-uws/src/App.h +++ b/packages/bun-uws/src/App.h @@ -107,7 +107,7 @@ struct TemplatedApp { HttpRouter::RouterData> *router; }; std::vector pendingServerNames; - /* No raw us_listen_socket_t* cache here. server.zig's non-abrupt stop calls + /* No raw us_listen_socket_t* cache here. src/runtime/server/mod.rs's non-abrupt stop calls * us_listen_socket_close(ls) directly; the listener is queued for free in * loop_post, so any vector we kept would dangle by the time the deferred * App::close() task runs. The group's intrusive head_listen_sockets list is diff --git a/packages/bun-uws/src/HttpContext.h b/packages/bun-uws/src/HttpContext.h index 1ec2ef6f9ed1..75248bed3f5f 100644 --- a/packages/bun-uws/src/HttpContext.h +++ b/packages/bun-uws/src/HttpContext.h @@ -124,8 +124,8 @@ struct HttpContext { /* Minimum allowed receive throughput per second (clients uploading less than 16kB/sec get dropped) */ static constexpr int HTTP_RECEIVE_THROUGHPUT_BYTES = 16 * 1024; - /* Not constexpr — the ordinals are linked from Zig (`SocketKind.zig` - * @export) so a reorder there can't silently mis-route us. Only ever read + /* Not constexpr — the ordinals are linked from `src/uws_sys/SocketKind.rs` + * so a reorder there can't silently mis-route us. Only ever read * at runtime (listen/adopt). */ static unsigned char socketKind() { return SSL ? US_SOCKET_KIND_UWS_HTTP_TLS : US_SOCKET_KIND_UWS_HTTP; } diff --git a/packages/bun-uws/src/SocketKinds.h b/packages/bun-uws/src/SocketKinds.h index 922e4e27edb9..d577aebc3f52 100644 --- a/packages/bun-uws/src/SocketKinds.h +++ b/packages/bun-uws/src/SocketKinds.h @@ -1,6 +1,6 @@ #pragma once -/* `src/deps/uws/SocketKind.zig` is the source of truth for these ordinals. - * The Zig side `@export`s them so the dispatch ABI can't silently drift if +/* `src/uws_sys/SocketKind.rs` is the source of truth for these ordinals. + * The Rust side exports them as `#[no_mangle]` statics so the dispatch ABI can't silently drift if * the enum is reordered — C++ links against the actual values instead of * hand-mirrored literals. */ extern "C" const unsigned char BUN_SOCKET_KIND_DYNAMIC; diff --git a/packages/bun-uws/src/WebSocketContext.h b/packages/bun-uws/src/WebSocketContext.h index fa249218efb0..db7c934a8728 100644 --- a/packages/bun-uws/src/WebSocketContext.h +++ b/packages/bun-uws/src/WebSocketContext.h @@ -50,8 +50,8 @@ struct WebSocketContext { } public: - /* Not constexpr — the ordinals are linked from Zig (`SocketKind.zig` - * @export) so a reorder there can't silently mis-route us. */ + /* Not constexpr — the ordinals are linked from `src/uws_sys/SocketKind.rs` + * so a reorder there can't silently mis-route us. */ static unsigned char socketKind() { return SSL ? US_SOCKET_KIND_UWS_WS_TLS : US_SOCKET_KIND_UWS_WS; } us_socket_group_t *getSocketGroup() { diff --git a/scripts/build/CLAUDE.md b/scripts/build/CLAUDE.md index 86b89f9e38c9..581d51797c58 100644 --- a/scripts/build/CLAUDE.md +++ b/scripts/build/CLAUDE.md @@ -143,7 +143,7 @@ Tables: `cpuTargetFlags` (`-march`/`-mcpu`/`-mtune` — also forwarded to local 2. `resolveConfig(partial, toolchain)` — produce the flat `Config`. Detect host, derive all target booleans, compute paths, read package.json version + git sha. 3. `validateBunConfig(cfg)` + `checkWorkarounds(cfg)` — fail early with clear errors. - `generateCargoConfig(cfg)` — write the repo-root `.cargo/config.toml` (git-ignored) with the per-target `linker = ` from the discovered `cfg.hostCxx`. Advisory only for `bun bd` (the ninja cargo edge sets the linker via env); it's there for `cargo build`/`cargo check`/rust-analyzer run directly. -4. `globAllSources()` — one filesystem snapshot of all `.cpp`/`.c`/`.zig`/codegen-input globs. +4. `globAllSources()` — one filesystem snapshot of all `.cpp`/`.c`/`.rs`/codegen-input globs. 5. `new Ninja({buildDir})` + `registerAllRules(n, cfg)` — register every rule template. 6. `emitGeneratorRule(n, cfg, partial)` — persist `configure.json`, emit `regen` rule so editing any build script triggers reconfigure. 7. `emitBun(n, cfg, sources)` — assemble the build graph (see Phase 2). diff --git a/scripts/build/codegen.ts b/scripts/build/codegen.ts index 49c57c61e462..47e1db8faaaf 100644 --- a/scripts/build/codegen.ts +++ b/scripts/build/codegen.ts @@ -21,7 +21,6 @@ * - bindgenv2 emits Generated.h per type (list-outputs skips .h) * - generate-node-errors.ts emits ErrorCode.d.ts (not declared) * - bundle-modules.ts emits eval/ subdir, BunBuiltinNames+extras.h, etc. - * - cppbind.ts emits cpp.source-links * * It WORKS because: * 1. The declared .cpp outputs guarantee the step runs before compile @@ -45,22 +44,6 @@ import { writeIfChanged } from "./fs.ts"; import type { Ninja } from "./ninja.ts"; import { quote, quoteArgs } from "./shell.ts"; -/** - * Codegen outputs that land in `src/` instead of `codegenDir`. The zig - * compiler refuses to import files outside its source tree, so these two - * generated `.zig` files live in `src/jsc/bindings/` (gitignored). - * - * Consumers of `sources.zig` (the `src/**\/*.zig` glob) must filter these - * out — they're OUTPUTS of codegen, not inputs. - * - * Paths are relative to repo root. This list is the single source of truth; - * `globAllSources()` does NOT hardcode these. - */ -export const zigFilesGeneratedIntoSrc = [ - "src/jsc/bindings/GeneratedBindings.zig", - "src/jsc/bindings/GeneratedJS2Native.zig", -] as const; - // The individual emit functions take these four params. Bundled to keep // signatures short. interface Ctx { @@ -132,7 +115,7 @@ export function registerCodegenRules(n: Ninja, cfg: Config): void { // ship with the build host's platform baked in. // // restat = 1 because most scripts use writeIfNotChanged(). Scripts that - // don't (generate-jssink, ci_info) always write → restat is a no-op for + // don't (generate-jssink) always write → restat is a no-op for // them, no harm. const env = hostWin ? `set TARGET_PLATFORM=${platform}&& set TARGET_ARCH=${arch}&& ` @@ -210,10 +193,10 @@ export interface CodegenOutputs { /** All codegen outputs — use for phony target `codegen`. */ all: string[]; - /** Outputs that zig `@embedFile`s or imports. */ + /** Outputs the cargo step depends on (generated .rs that gets `include!`d). */ rustInputs: string[]; - /** Outputs that zig needs to exist but doesn't embed (debug bake runtime). */ + /** Outputs the cargo step needs to exist but doesn't embed (debug bake runtime). */ rustOrderOnly: string[]; /** Generated .cpp files. Compiled alongside handwritten C++ in bun.ts. */ @@ -245,9 +228,6 @@ export interface CodegenOutputs { /** The bindgenv2 .cpp outputs (compiled separately from handwritten C++). */ bindgenV2Cpp: string[]; - /** The bindgenv2 .zig outputs (legacy artifacts, retained for reference). */ - bindgenV2Zig: string[]; - /** * Stamp output from `bun install` at repo root. * The esbuild tool and the cppbind lezer parser live here. Any @@ -280,7 +260,6 @@ export function emitCodegen(n: Ninja, cfg: Config, sources: Sources): CodegenOut cppHeaders: [], cppAll: [], bindgenV2Cpp: [], - bindgenV2Zig: [], rootInstall, }; @@ -302,7 +281,6 @@ export function emitCodegen(n: Ninja, cfg: Config, sources: Sources): CodegenOut emitGeneratedClasses(ctx); emitHostExports(ctx); emitCppBind(ctx); - emitCiInfo(ctx); emitJsModules(ctx); emitBakeCodegen(ctx); emitBindgenV2(ctx); @@ -584,11 +562,7 @@ function emitErrorCode({ n, cfg, o, dirStamp }: Ctx): void { resolve(cfg.cwd, "src", "jsc", "bindings", "ErrorCode.h"), ]; - const outputs = [ - resolve(cfg.codegenDir, "ErrorCode+List.h"), - resolve(cfg.codegenDir, "ErrorCode+Data.h"), - resolve(cfg.codegenDir, "ErrorCode.zig"), - ]; + const outputs = [resolve(cfg.codegenDir, "ErrorCode+List.h"), resolve(cfg.codegenDir, "ErrorCode+Data.h")]; n.build({ outputs, @@ -597,7 +571,7 @@ function emitErrorCode({ n, cfg, o, dirStamp }: Ctx): void { orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: "ErrorCode.{zig,h}", + desc: "ErrorCode+*.h", args: shJoin(cfg, ["run", script, cfg.codegenDir]), }, }); @@ -617,7 +591,6 @@ function emitGeneratedClasses({ n, cfg, sources, o, dirStamp }: Ctx): void { resolve(cfg.codegenDir, "ZigGeneratedClasses+DOMClientIsoSubspaces.h"), resolve(cfg.codegenDir, "ZigGeneratedClasses+DOMIsoSubspaces.h"), resolve(cfg.codegenDir, "ZigGeneratedClasses+lazyStructureImpl.h"), - resolve(cfg.codegenDir, "ZigGeneratedClasses.zig"), resolve(cfg.codegenDir, "ZigGeneratedClasses.lut.txt"), // Rust sibling: include!()'d by src/runtime/generated_classes.rs. Must be // a declared output so the cargo edge (which lists this in rustInputs) @@ -633,7 +606,7 @@ function emitGeneratedClasses({ n, cfg, sources, o, dirStamp }: Ctx): void { orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: "ZigGeneratedClasses.{zig,cpp,h}", + desc: "ZigGeneratedClasses.{cpp,h,rs}", args: shJoin(cfg, ["run", script, ...sources.zigGeneratedClasses, cfg.codegenDir]), }, }); @@ -677,15 +650,14 @@ function emitHostExports({ n, cfg, sources, o, dirStamp }: Ctx): void { o.all.push(output); // bun_runtime/build.rs panics if this file is absent, so the rust_build edge - // must wait on it — `rustInputs` is the implicit-dep list both zig and the - // cargo edge consume. + // must wait on it — `rustInputs` is the implicit-dep list the + // cargo edge consumes. o.rustInputs.push(output); } function emitCppBind({ n, cfg, sources, o, dirStamp }: Ctx): void { const script = resolve(cfg.cwd, "src", "codegen", "cppbind.ts"); - const output = resolve(cfg.codegenDir, "cpp.zig"); const outputRs = resolve(cfg.codegenDir, "cpp.rs"); // Write the .cpp file list for cppbind to scan. Build system owns the @@ -703,7 +675,7 @@ function emitCppBind({ n, cfg, sources, o, dirStamp }: Ctx): void { writeIfChanged(cxxSourcesFile, cxxSourcesLines.join("\n") + "\n"); n.build({ - outputs: [output, outputRs], + outputs: [outputRs], rule: "codegen", inputs: [script], // cppbind scans ALL .cpp files for [[ZIG_EXPORT]] annotations. Every @@ -723,39 +695,16 @@ function emitCppBind({ n, cfg, sources, o, dirStamp }: Ctx): void { orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: "cpp.{zig,rs} (cppbind)", + desc: "cpp.rs (cppbind)", // cppbind.ts takes: . No `run` — // direct script invocation (`${BUN_EXECUTABLE} ${script} ...`). args: shJoin(cfg, [script, resolve(cfg.cwd, "src"), cfg.codegenDir, cxxSourcesFile]), }, }); - o.all.push(output, outputRs); + o.all.push(outputRs); // bun_jsc `include!`s cpp.rs — the cargo edge must order after this. - o.rustInputs.push(output, outputRs); -} - -function emitCiInfo({ n, cfg, o, dirStamp }: Ctx): void { - const script = resolve(cfg.cwd, "src", "codegen", "ci_info.ts"); - const output = resolve(cfg.codegenDir, "ci_info.zig"); - - // CMake lists JavaScriptCodegenSources as deps here, but ci_info.ts doesn't - // read any of those files — it's a pure static data generator. The CMake - // dep list is wrong (copy-paste from bundle-modules). We use just the script. - n.build({ - outputs: [output], - rule: "codegen", - inputs: [script], - orderOnlyInputs: [dirStamp], - vars: { - cwd: cfg.cwd, - desc: "ci_info.zig", - args: shJoin(cfg, [script, output]), - }, - }); - - o.all.push(output); - o.rustInputs.push(output); + o.rustInputs.push(outputRs); } function emitJsModules({ n, cfg, sources, o, dirStamp }: Ctx): void { @@ -768,9 +717,6 @@ function emitJsModules({ n, cfg, sources, o, dirStamp }: Ctx): void { // stale error numbers in the JS bundles while the C++ enum regenerates. const errorCodeInput = resolve(cfg.cwd, "src", "jsc", "bindings", "ErrorCode.ts"); - // Written into src/ (not codegenDir) — see zigFilesGeneratedIntoSrc at top. - const js2nativeZig = resolve(cfg.cwd, zigFilesGeneratedIntoSrc[1]); - const outputs = [ resolve(cfg.codegenDir, "WebCoreJSBuiltins.cpp"), resolve(cfg.codegenDir, "WebCoreJSBuiltins.h"), @@ -781,7 +727,6 @@ function emitJsModules({ n, cfg, sources, o, dirStamp }: Ctx): void { resolve(cfg.codegenDir, "NativeModuleImpl.h"), resolve(cfg.codegenDir, "SyntheticModuleType.h"), resolve(cfg.codegenDir, "GeneratedJS2Native.h"), - js2nativeZig, // Rust sibling: include!()'d by src/runtime/generated_js2native.rs. Must be // a declared output so the cargo edge re-invokes when bundle-modules.ts / // generate-js2native.ts changes — the includer shim's mtime never moves. @@ -885,8 +830,7 @@ function emitBindgenV2({ n, cfg, sources, o, dirStamp }: Ctx): void { assert(allOutputs.length > 0, "bindgenv2 list-outputs returned no files"); const cppOutputs = allOutputs.filter(p => p.endsWith(".cpp")); - const zigOutputs = allOutputs.filter(p => p.endsWith(".zig")); - const other = allOutputs.filter(p => !p.endsWith(".cpp") && !p.endsWith(".zig")); + const other = allOutputs.filter(p => !p.endsWith(".cpp")); assert(other.length === 0, `bindgenv2 emitted unexpected output type: ${other.join(", ")}`); n.build({ @@ -909,35 +853,30 @@ function emitBindgenV2({ n, cfg, sources, o, dirStamp }: Ctx): void { o.all.push(...allOutputs); o.bindgenV2Cpp.push(...cppOutputs); - o.bindgenV2Zig.push(...zigOutputs); - o.rustInputs.push(...zigOutputs); } function emitBindgen({ n, cfg, sources, o, dirStamp }: Ctx): void { const script = resolve(cfg.cwd, "src", "codegen", "bindgen.ts"); - // Written into src/ (not codegenDir) — see zigFilesGeneratedIntoSrc at top. - const zigOut = resolve(cfg.cwd, zigFilesGeneratedIntoSrc[0]); const cppOut = resolve(cfg.codegenDir, "GeneratedBindings.cpp"); // bindgen.ts scans src/ for .bind.ts files itself — this list is only for // ninja dependency tracking. New .bind.ts files need a reconfigure to be // picked up (next glob gets them). n.build({ - outputs: [cppOut, zigOut], + outputs: [cppOut], rule: "codegen", inputs: [script, ...sources.bindgen], orderOnlyInputs: [dirStamp], vars: { cwd: cfg.cwd, - desc: ".bind.ts → GeneratedBindings.{cpp,zig}", + desc: ".bind.ts → GeneratedBindings.cpp", args: shJoin(cfg, ["run", script, debugFlag(cfg), `--codegen-root=${cfg.codegenDir}`]), }, }); - o.all.push(cppOut, zigOut); + o.all.push(cppOut); o.cppSources.push(cppOut); - o.rustInputs.push(zigOut); } function emitJsSink({ n, cfg, o, dirStamp }: Ctx): void { diff --git a/scripts/build/deps/libarchive.ts b/scripts/build/deps/libarchive.ts index cfe0a475a7fa..0c507dc82872 100644 --- a/scripts/build/deps/libarchive.ts +++ b/scripts/build/deps/libarchive.ts @@ -106,7 +106,7 @@ export const libarchive: Dependency = { // Propagate ARCHIVE_RETRY from the client read callback up through // the gzip filter and tar reader so the worker-thread extract loop // in `bun install` can yield and resume as HTTP chunks arrive. See - // src/install/TarballStream.zig. + // src/install/TarballStream.rs. "patches/libarchive/nonblocking-read.patch", // Windows: cache get_current_codepage()/get_current_oemcp() after the // first call instead of querying setlocale(LC_CTYPE, NULL) once per diff --git a/scripts/build/deps/zstd.ts b/scripts/build/deps/zstd.ts index d7d3cb148c74..8bf87f035627 100644 --- a/scripts/build/deps/zstd.ts +++ b/scripts/build/deps/zstd.ts @@ -50,7 +50,7 @@ export const zstd: Dependency = { // Upstream's if(MSVC) block sets these for the static target. // ZSTD_HEAPMODE=0 makes the one-shot ZSTD_decompress() (used by - // src/zstd/zstd.zig) stack-allocate its DCtx instead of malloc/free + // src/zstd/lib.rs) stack-allocate its DCtx instead of malloc/free // per call; the source default is 1. if (cfg.windows) { defines.ZSTD_HEAPMODE = 0; diff --git a/scripts/build/rust.ts b/scripts/build/rust.ts index f9f8087789a1..bd004e0c976c 100644 --- a/scripts/build/rust.ts +++ b/scripts/build/rust.ts @@ -417,10 +417,8 @@ export function emitRust(n: Ninja, cfg: Config, inputs: RustBuildInputs): string if ((cfg.linux && cfg.abi !== "android") || cfg.freebsd) { rustflags.push("-Crelocation-model=static"); } - // Keep frame pointers — matches Zig's `omit_frame_pointer = false` - // (build.zig:319,841) and the C++ side's `-fno-omit-frame-pointer` / `/Oy-` - // (flags.ts:293-301). Needed so profilers and crash backtraces walk Rust - // frames the same as the Zig binary did. + // Keep frame pointers — matches the C++ side's `-fno-omit-frame-pointer` / `/Oy-` + // (flags.ts:293-301). Needed so profilers and crash backtraces can walk Rust frames. rustflags.push("-Cforce-frame-pointers=yes"); // Parallel frontend: rustc's default is single-threaded for parse / macro // expansion / typeck / borrowck, so the critical-path crate (`bun_runtime`) @@ -755,10 +753,7 @@ export function emitRust(n: Ninja, cfg: Config, inputs: RustBuildInputs): string if (rustflags.length > 0) env.CARGO_ENCODED_RUSTFLAGS = rustflags.join("\x1f"); // ─── Windows .bin/ shim PE ─── - // Replaces Zig's `mod.addAnonymousImport("bun_shim_impl.exe", ...)` (build.zig - // built `src/install/windows-shim/bun_shim_impl.zig` as a freestanding - // ReleaseFast PE and wired the artifact into `@embedFile`). The Rust port - // dropped emitZig entirely, so without this step `include_bytes!` embeds the + // Builds `src/install/windows-shim/bun_shim_impl.rs` as a freestanding release PE and wires the artifact into `include_bytes!`. Without this step `include_bytes!` embeds the // 0-byte placeholder and `bun install` writes empty `.exe`s into // `node_modules/.bin/`. // diff --git a/scripts/cleartrace-impl.js b/scripts/cleartrace-impl.js deleted file mode 100644 index 6ec4910ca6fa..000000000000 --- a/scripts/cleartrace-impl.js +++ /dev/null @@ -1,54 +0,0 @@ -import { createInterface } from "node:readline"; - -const rl = createInterface({ - input: process.stdin, - output: process.stdout, - terminal: false, -}); - -const ignore = [ - " print__anon_", - " printError__anon_", - " printErrorln__anon_", - " prettyWithPrinter__anon_", - " prettyErrorLn__anon_", - " err [inlined]", - " createErrorInstance__anon_", - " allocPrint__anon_", - " createFormat__anon_", - " fmt__anon_", - " toInvalidArguments__anon_", - " throwInvalidArguments__anon_", - " printStringPretty__anon_", - " throwErrInvalidArgType", - " validateObject__", - " allocPrint ", - " addWarningFmt_", - "logger.zig", // maybe? - "output.zig", // might be overly optimistic - "vendor/zig/lib/std", - "ErrorCode.zig", -]; - -let skipNext = false; -rl.on("line", line => { - if (skipNext) { - skipNext = false; - return; - } - if (line.includes(": error: ")) { - console.log("\x1b[31m" + line.replace(/^vendor\/zig\/lib\/std\/Io\/Writer\.zig:\d+:\d+: /, "") + "\x1b[0m"); - } else if (line.includes(": note: ")) { - console.log("\x1b[36m" + line + "\x1b[0m"); - } else if (line.includes('@compileError("')) { - skipNext = true; - } else if (ignore.some(q => line.includes(q) && !line.includes(" format:"))) { - console.log("\x1b[2m" + line + "\x1b[0m"); - } else { - console.log(line); - } -}); - -rl.on("close", () => { - process.exit(0); -}); diff --git a/scripts/cleartrace.ts b/scripts/cleartrace.ts deleted file mode 100644 index 24f823dcbfa2..000000000000 --- a/scripts/cleartrace.ts +++ /dev/null @@ -1,46 +0,0 @@ -// `fish -c "bun run watch 2>&1 | bun scripts/cleartrace"` - -import { createInterface } from "node:readline"; - -const rl = createInterface({ - input: process.stdin, - output: process.stdout, - terminal: false, -}); - -let chunk: string[] = []; -rl.on("line", line => { - chunk.push(line); -}); -let timeout: NodeJS.Timeout | null = null; -async function doNow() { - if (timeout != null) { - clearTimeout(timeout); - timeout = null; - } - const eatChunk = chunk; - chunk = []; - if (eatChunk.length > 0) { - const proc = Bun.spawn({ - cmd: ["bun", "scripts/cleartrace-impl.js"], - stdio: ["pipe", "inherit", "inherit"], - }); - proc.stdin.write(eatChunk.join("\n")); - proc.stdin.end(); - await proc.exited; - } - enqueue(); -} -let ceaseTimeout = false; -function enqueue() { - if (ceaseTimeout) return; - timeout = setTimeout(() => { - timeout = null; - doNow(); - }, 100); -} -enqueue(); - -rl.on("close", () => { - ceaseTimeout = true; -}); diff --git a/scripts/generate-perf-trace-events.sh b/scripts/generate-perf-trace-events.sh index c477bfde2859..2ce956c60880 100755 --- a/scripts/generate-perf-trace-events.sh +++ b/scripts/generate-perf-trace-events.sh @@ -1,31 +1,111 @@ #!/usr/bin/env bash -# This file is not run often, so we don't need to make it part of the build system. -# We do this because the event names have to be compile-time constants. - - -export TRACE_EVENTS=$(rg 'bun\.perf\.trace\("([^"]*)"\)' -t zig --json \ - | jq -r 'select(.type == "match")' \ - | jq -r '.data.submatches[].match.text' \ - | cut -d'"' -f2 \ - | sort \ - | uniq) - -echo "// Generated with scripts/generate-perf-trace-events.sh" > src/jsc/bindings/generated_perf_trace_events.h -echo "// clang-format off" >> src/jsc/bindings/generated_perf_trace_events.h -echo "#define FOR_EACH_TRACE_EVENT(macro) \\" >> src/jsc/bindings/generated_perf_trace_events.h -i=0 -for event in $TRACE_EVENTS; do - echo " macro($event, $((i++))) \\" >> src/jsc/bindings/generated_perf_trace_events.h -done -echo " // end" >> src/jsc/bindings/generated_perf_trace_events.h +# Regenerate the perf-trace event list from Rust call sites. +# +# Scans for both call shapes: +# - bun_core::perf::trace("Event.name") (string-literal form) +# - bun_perf::trace(PerfEvent::VariantName) (enum form, any qualifier) +# +# and emits: +# - src/jsc/bindings/generated_perf_trace_events.h (X-macro, sorted, 0-indexed) +# - src/perf/generated_perf_trace_events.rs (#[repr(i32)] PerfEvent enum) +# +# Not run during the build; re-run manually when adding new trace() calls. + +set -euo pipefail +cd "$(dirname "$0")/.." + +# rg exits 1 on zero matches; each form is allowed to be empty so long as the +# combined set isn't. -I/--no-filename: rg prints path prefixes when searching +# a directory and we only want the captured group. +LITERAL_EVENTS=$(rg 'bun_core::perf::trace\("([^"]+)"\)' -t rust -I -o -r '$1' src/ | sort -u || true) + +# Enum form: accept any of PerfEvent::X, bun_perf::PerfEvent::X, ::bun_perf::PerfEvent::X. +ENUM_VARIANTS=$(rg '(?:::)?bun_perf::trace\((?:::)?(?:bun_perf::)?PerfEvent::([A-Za-z0-9_]+)\)' \ + -t rust -I -o -r '$1' src/ | sort -u || true) -echo "Generated src/jsc/bindings/generated_perf_trace_events.h" +# Build "dotted\tvariant" pairs. For literal-form callers the variant name is +# derived from the literal (non-alnum stripped, first of each segment +# uppercased). For enum-form callers the variant is what the caller wrote and +# the dotted name is looked up in the current as_cstr() table so re-running +# preserves existing names; rustfmt wraps long arms across lines so match with -U. +PAIRS="" -echo "// Generated with scripts/generate-perf-trace-events.sh" > src/perf/generated_perf_trace_events.zig -echo "pub const PerfEvent = enum(i32) {" >> src/perf/generated_perf_trace_events.zig -for event in $TRACE_EVENTS; do - echo " @\"$event\"," >> src/perf/generated_perf_trace_events.zig +while IFS= read -r ev; do + [ -z "$ev" ] && continue + variant=$(echo "$ev" | perl -pe 's/(^|[^A-Za-z0-9])([a-z])/$1\u$2/g; s/[^A-Za-z0-9]//g') + PAIRS="$PAIRS"$'\n'"$ev"$'\t'"$variant" +done <<< "$LITERAL_EVENTS" + +for v in $ENUM_VARIANTS; do + name=$(rg -U "PerfEvent::${v}\b\s*=>\s*\{?\s*c\"([^\"]+)\"" \ + src/perf/generated_perf_trace_events.rs -o -r '$1' || true) + if [ -z "$name" ]; then + # New variant without a cstr mapping yet: synthesize Foo.Bar from FooBar. + name=$(echo "$v" | sed -E 's/([a-z])([A-Z])/\1.\2/g; s/^_//') + fi + PAIRS="$PAIRS"$'\n'"$name"$'\t'"$v" done -echo "};" >> src/perf/generated_perf_trace_events.zig -echo "Generated src/perf/generated_perf_trace_events.zig" \ No newline at end of file +# Sort by dotted name (stable ids across runs); dedup by dotted name first, +# then by derived variant (two literals like "X.foo" and "X::foo" collapse). +# `awk NF` drops blank lines without the exit-1-on-no-match behaviour of grep. +PAIRS=$(echo "$PAIRS" | awk 'NF' | sort -t$'\t' -k1,1 -u | awk -F'\t' '!seen[$2]++') + +if [ -z "$PAIRS" ]; then + echo "error: no perf::trace() call sites found under src/" >&2 + exit 1 +fi + +H_OUT=src/jsc/bindings/generated_perf_trace_events.h +{ + echo "// Generated with scripts/generate-perf-trace-events.sh" + echo "// clang-format off" + echo "#define FOR_EACH_TRACE_EVENT(macro) \\" + i=0 + while IFS=$'\t' read -r dotted variant; do + echo " macro($dotted, $i) \\" + i=$((i + 1)) + done <<< "$PAIRS" + echo " // end" +} > "$H_OUT" +echo "Generated $H_OUT" + +RS_OUT=src/perf/generated_perf_trace_events.rs +{ + echo "// Generated with scripts/generate-perf-trace-events.sh" + echo "//" + echo "// Discriminants match the ids in src/jsc/bindings/generated_perf_trace_events.h" + echo "// (the Darwin signpost path reads the event by integer id)." + echo + echo "#![allow(non_camel_case_types)]" + echo + echo "use core::ffi::CStr;" + echo + echo "#[repr(i32)]" + echo "#[derive(Copy, Clone, Eq, PartialEq)]" + echo "pub enum PerfEvent {" + i=0 + while IFS=$'\t' read -r dotted variant; do + echo " $variant = $i," + i=$((i + 1)) + done <<< "$PAIRS" + echo "}" + echo + echo "impl PerfEvent {" + echo " pub fn as_cstr(self) -> &'static CStr {" + echo " match self {" + while IFS=$'\t' read -r dotted variant; do + echo " PerfEvent::$variant => c\"$dotted\"," + done <<< "$PAIRS" + echo " }" + echo " }" + echo "}" + echo + echo "impl From for &'static str {" + echo " fn from(e: PerfEvent) -> &'static str {" + echo " e.as_cstr().to_str().unwrap()" + echo " }" + echo "}" +} > "$RS_OUT" +rustfmt "$RS_OUT" 2>/dev/null || true +echo "Generated $RS_OUT" diff --git a/scripts/glob-sources.ts b/scripts/glob-sources.ts index 1f794a29580a..aaca9a81249d 100644 --- a/scripts/glob-sources.ts +++ b/scripts/glob-sources.ts @@ -58,7 +58,9 @@ const patterns = { }, /** server-rendering runtime bundled into binary */ bakeRuntime: { - paths: ["src/runtime/bake/*.ts", "src/runtime/bake/*/*.{ts,css}"], + // dev_server/mod.rs is read by bake-codegen.ts to derive the + // MessageId/IncomingMessageId const-enums in generated.ts. + paths: ["src/runtime/bake/*.ts", "src/runtime/bake/*/*.{ts,css}", "src/runtime/bake/dev_server/mod.rs"], exclude: ["src/runtime/bake/generated.ts"], }, /** legacy bindgen input */ @@ -73,19 +75,6 @@ const patterns = { bindgenV2Internal: { paths: ["src/codegen/bindgenv2/**/*.ts"], }, - /** - * NOT filtered; includes codegen-written files (see bun.ts). - * - * `src/cli/**` is excluded: it is a committed symlink → `runtime/cli` - * which `node:fs.globSync` follows on POSIX (double-counts every file) - * but cannot traverse on Windows agents where git materialises the link - * as a text file. Excluding the alias keeps the file set platform-stable - * for ban-words count pinning. - */ - zig: { - paths: ["src/**/*.zig"], - exclude: ["src/cli/**"], - }, /** * all `*.rs` + workspace manifests — implicit inputs to the cargo step. * `rust-toolchain.toml` is included so a nightly bump invalidates the diff --git a/scripts/longest.js b/scripts/longest.js deleted file mode 100644 index df78b0e85eb5..000000000000 --- a/scripts/longest.js +++ /dev/null @@ -1,125 +0,0 @@ -const fs = require("fs"); -const path = require("path"); - -// Regex patterns for different types of top-level declarations -const DECLARATION_PATTERN = - // pub? (export|extern)? (const|fn|var) name - /^(pub\s+)?(export\s+|extern\s+)?(const|fn|var)\s+([a-zA-Z_][a-zA-Z0-9_]*)/; - -function findDeclarations(filePath) { - const content = fs.readFileSync(filePath, "utf8"); - const lines = content.split("\n"); - const declarations = []; - - // First pass: collect all declarations with their line numbers - for (let lineNum = 0; lineNum < lines.length; lineNum++) { - const line = lines[lineNum]; - - // Skip empty lines and comments - if (!line || line.trim().startsWith("//") || line.trim().startsWith("///")) { - continue; - } - - // Only process top-level declarations (no indentation) - if (line.startsWith(" ") || line.startsWith("\t")) { - continue; - } - - const trimmedLine = line.trim(); - - // Check each pattern - const match = trimmedLine.match(DECLARATION_PATTERN); - if (match) { - // Extract the name from the match - const name = match[match.length - 1]; // Last capture group is the name - - declarations.push({ - name, - match: match[0], - line: lineNum + 1, - type: getDeclarationType(match[0]), - fullLine: trimmedLine, - startLine: lineNum, - }); - } - } - - // Second pass: calculate sizes based on next declaration's start line - for (let i = 0; i < declarations.length; i++) { - const currentDecl = declarations[i]; - const nextDecl = declarations[i + 1]; - - if (nextDecl) { - // Size is from current declaration start to next declaration start - currentDecl.size = nextDecl.startLine - currentDecl.startLine; - } else { - // Last declaration: size is from current declaration start to end of file - currentDecl.size = lines.length - currentDecl.startLine; - } - } - - return declarations; -} - -function getDeclarationType(matchText) { - if (matchText.includes("const")) return "const"; - if (matchText.includes("fn")) return "fn"; - if (matchText.includes("var")) return "var"; - return "unknown"; -} - -function main() { - const args = process.argv.slice(2); - - if (args.length === 0) { - console.error("Usage: bun longest.js "); - console.error("Example: bun longest.js src/walker_skippable.zig"); - process.exit(1); - } - - const filePath = args[0]; - - if (!fs.existsSync(filePath)) { - console.error(`File not found: ${filePath}`); - process.exit(1); - } - - if (!filePath.endsWith(".zig")) { - console.error("Please provide a .zig file"); - process.exit(1); - } - - try { - const declarations = findDeclarations(filePath); - - if (declarations.length === 0) { - console.log("No top-level declarations found."); - return; - } - - console.log(`Found ${declarations.length} top-level declarations in ${filePath}:\n`); - - // Sort by declaration size (smallest first) - declarations.sort((a, b) => a.size - b.size); - - // Find the longest name for formatting - const maxNameLength = Math.max(...declarations.map(d => d.match.length)); - const maxTypeLength = Math.max(...declarations.map(d => d.type.length)); - - console.log(`${"Name".padEnd(maxNameLength + 2)} ${"Type".padEnd(maxTypeLength + 2)} ${"Num Lines".padEnd(6)}`); - console.log("-".repeat(maxNameLength + maxTypeLength + 15)); - - declarations.forEach(decl => { - console.log( - `${decl.match.padEnd(maxNameLength + 2)} ${decl.type.padEnd(maxTypeLength + 2)} ${decl.size.toString().padEnd(6)}`, - ); - }); - } catch (error) { - console.error("Error reading file:", error.message); - process.exit(1); - } -} - -if (require.main === module) { - main(); -} diff --git a/src/CLAUDE.md b/src/CLAUDE.md index 95e9613c9971..a4b87a0d99c2 100644 --- a/src/CLAUDE.md +++ b/src/CLAUDE.md @@ -12,10 +12,6 @@ bun_bin` (driven by `scripts/build/rust.ts`). Key crates: - `bun_js_parser`, `bun_js_printer`, `bun_resolver`, `bun_bundler`, `bun_install`, `bun_collections`, `bun_threading`, `bun_alloc` — the rest of the pipeline - `bun_bin` (`src/bun_bin/`) — the staticlib root that `cargo build` links -You will see `.zig` siblings next to many `.rs` files — those are the original -implementation kept as a porting reference for _behavior_; they are not -compiled and are not where new code goes. - Conventions: - `cargo check -p ` for fast iteration; `bun bd` builds and links everything. @@ -66,10 +62,10 @@ Key types and functions: - Open flags: `bun_sys::O::RDONLY`, `O::WRONLY | O::CREAT | O::TRUNC`, etc. `bun_sys::Error` carries `errno`, `syscall: Tag`, `path: Box<[u8]>`. Convert -to a JS exception via `bun_jsc::ErrorJsc::to_js`: +to a JS exception via `bun_sys_jsc::ErrorJsc::to_js`: ```rust -use bun_jsc::ErrorJsc; +use bun_sys_jsc::ErrorJsc; match File::openat(Fd::cwd(), path, O::RDONLY, 0) { Ok(f) => f, Err(err) => return Ok(err.to_js(global)?), diff --git a/src/analytics/analytics.zig b/src/analytics/analytics.zig deleted file mode 100644 index 88bd1f203775..000000000000 --- a/src/analytics/analytics.zig +++ /dev/null @@ -1,380 +0,0 @@ -/// Enables analytics. This is used by: -/// - crash_handler.zig's `report` function to anonymously report crashes -/// -/// Since this field can be .unknown, it makes more sense to call `isEnabled` -/// instead of processing this field directly. -pub var enabled: enum { yes, no, unknown } = .unknown; -pub var is_ci: enum { yes, no, unknown } = .unknown; - -pub fn isEnabled() bool { - return switch (enabled) { - .yes => true, - .no => false, - .unknown => { - enabled = detect: { - if (bun.env_var.DO_NOT_TRACK.get()) { - break :detect .no; - } - if (bun.env_var.HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET.get() != null) { - break :detect .no; - } - break :detect .yes; - }; - bun.assert(enabled == .yes or enabled == .no); - return enabled == .yes; - }, - }; -} - -/// This answers, "What parts of bun are people actually using?" -pub const Features = struct { - pub var builtin_modules = std.enums.EnumSet(bun.jsc.ModuleLoader.HardcodedModule).initEmpty(); - - pub var @"Bun.stderr": usize = 0; - pub var @"Bun.stdin": usize = 0; - pub var @"Bun.stdout": usize = 0; - pub var WebSocket: usize = 0; - pub var abort_signal: usize = 0; - pub var binlinks: usize = 0; - pub var bunfig: usize = 0; - pub var define: usize = 0; - pub var dotenv: usize = 0; - pub var debugger: usize = 0; - pub var external: usize = 0; - pub var extracted_packages: usize = 0; - pub var fetch: usize = 0; - pub var git_dependencies: usize = 0; - pub var html_rewriter: usize = 0; - /// TCP server from `Bun.listen` - pub var tcp_server: usize = 0; - /// TLS server from `Bun.listen` - pub var tls_server: usize = 0; - pub var http_server: usize = 0; - pub var https_server: usize = 0; - pub var http_client_proxy: usize = 0; - /// Set right before JSC::initialize is called - pub var jsc: usize = 0; - /// Set when bake.DevServer is initialized - pub var dev_server: usize = 0; - pub var lifecycle_scripts: usize = 0; - pub var loaders: usize = 0; - pub var lockfile_migration_from_package_lock: usize = 0; - pub var text_lockfile: usize = 0; - pub var isolated_bun_install: usize = 0; - pub var hoisted_bun_install: usize = 0; - pub var macros: usize = 0; - pub var no_avx2: usize = 0; - pub var no_avx: usize = 0; - pub var shell: usize = 0; - pub var spawn: usize = 0; - pub var standalone_executable: usize = 0; - pub var standalone_shell: usize = 0; - /// Set when invoking a todo panic - pub var todo_panic: usize = 0; - pub var transpiler_cache: usize = 0; - pub var tsconfig: usize = 0; - pub var tsconfig_paths: usize = 0; - pub var virtual_modules: usize = 0; - pub var workers_spawned: usize = 0; - pub var workers_terminated: usize = 0; - pub var napi_module_register: usize = 0; - pub var process_dlopen: usize = 0; - pub var postgres_connections: usize = 0; - pub var s3: usize = 0; - pub var valkey: usize = 0; - pub var csrf_verify: usize = 0; - pub var csrf_generate: usize = 0; - pub var unsupported_uv_function: usize = 0; - pub var exited: usize = 0; - pub var yarn_migration: usize = 0; - pub var pnpm_migration: usize = 0; - pub var yaml_parse: usize = 0; - pub var cpu_profile: usize = 0; - pub var heap_snapshot: usize = 0; - pub var webview_chrome: usize = 0; - pub var webview_webkit: usize = 0; - - comptime { - @export(&napi_module_register, .{ .name = "Bun__napi_module_register_count" }); - @export(&process_dlopen, .{ .name = "Bun__process_dlopen_count" }); - @export(&heap_snapshot, .{ .name = "Bun__Feature__heap_snapshot" }); - @export(&webview_chrome, .{ .name = "Bun__Feature__webview_chrome" }); - @export(&webview_webkit, .{ .name = "Bun__Feature__webview_webkit" }); - } - - pub fn formatter() Formatter { - return Formatter{}; - } - - pub const Formatter = struct { - pub fn format(_: Formatter, writer: *std.Io.Writer) !void { - const fields = comptime brk: { - const info: std.builtin.Type = @typeInfo(Features); - var buffer: [info.@"struct".decls.len][]const u8 = .{""} ** info.@"struct".decls.len; - var count: usize = 0; - for (info.@"struct".decls) |decl| { - var f = &@field(Features, decl.name); - _ = &f; - const Field = @TypeOf(f); - const FieldT: std.builtin.Type = @typeInfo(Field); - if (FieldT.pointer.child != usize) continue; - buffer[count] = decl.name; - count += 1; - } - - break :brk buffer[0..count]; - }; - - var is_first_feature = true; - inline for (fields) |field| { - const count = @field(Features, field); - if (count > 0) { - if (is_first_feature) { - try writer.writeAll("Features: "); - is_first_feature = false; - } - try writer.writeAll(field); - if (count > 1) { - try writer.print("({d}) ", .{count}); - } else { - try writer.writeAll(" "); - } - } - } - if (!is_first_feature) { - try writer.writeAll("\n"); - } - - var builtins = builtin_modules.iterator(); - if (builtins.next()) |first| { - try writer.writeAll("Builtins: \""); - try writer.writeAll(@tagName(first)); - try writer.writeAll("\" "); - - while (builtins.next()) |key| { - try writer.writeAll("\""); - try writer.writeAll(@tagName(key)); - try writer.writeAll("\" "); - } - - try writer.writeAll("\n"); - } - } - }; -}; - -pub fn validateFeatureName(name: []const u8) void { - if (name.len > 64) @compileError("Invalid feature name: " ++ name); - for (name) |char| { - switch (char) { - 'a'...'z', 'A'...'Z', '0'...'9', '_', '.', ':', '-' => {}, - else => @compileError("Invalid feature name: " ++ name), - } - } -} - -pub const packed_features_list = brk: { - const decls = std.meta.declarations(Features); - var names: [decls.len][:0]const u8 = undefined; - var i = 0; - for (decls) |decl| { - if (@TypeOf(@field(Features, decl.name)) == usize) { - validateFeatureName(decl.name); - names[i] = decl.name; - i += 1; - } - } - break :brk names[0..i].*; -}; - -pub const PackedFeatures = @Type(.{ - .@"struct" = .{ - .layout = .@"packed", - .backing_integer = u64, - .fields = brk: { - var fields: [64]std.builtin.Type.StructField = undefined; - var i: usize = 0; - for (packed_features_list) |name| { - fields[i] = .{ - .name = name, - .type = bool, - .default_value_ptr = &false, - .is_comptime = false, - .alignment = 0, - }; - i += 1; - } - while (i < fields.len) : (i += 1) { - fields[i] = .{ - .name = std.fmt.comptimePrint("_{d}", .{i}), - .type = bool, - .default_value_ptr = &false, - .is_comptime = false, - .alignment = 0, - }; - } - break :brk &fields; - }, - .decls = &.{}, - .is_tuple = false, - }, -}); - -pub fn packedFeatures() PackedFeatures { - var bits = PackedFeatures{}; - inline for (packed_features_list) |name| { - if (@field(Features, name) > 0) { - @field(bits, name) = true; - } - } - return bits; -} - -pub const EventName = enum(u8) { - bundle_success, - bundle_fail, - bundle_start, - http_start, - http_build, -}; - -var random: std.rand.DefaultPrng = undefined; - -const platform_arch = if (Environment.isAarch64) analytics.Architecture.arm else analytics.Architecture.x64; - -// TODO: move this code somewhere more appropriate, and remove it from "analytics" -// The following code is not currently even used for analytics, just feature-detection -// in order to determine if certain APIs are usable. -pub const GenerateHeader = struct { - pub const GeneratePlatform = struct { - var osversion_name: [32]u8 = undefined; - fn forMac() analytics.Platform { - @memset(&osversion_name, 0); - - var platform = analytics.Platform{ .os = analytics.OperatingSystem.macos, .version = &[_]u8{}, .arch = platform_arch }; - var len = osversion_name.len - 1; - // this previously used "kern.osrelease", which was the darwin xnu kernel version - // That is less useful than "kern.osproductversion", which is the macOS version - if (std.c.sysctlbyname("kern.osproductversion", &osversion_name, &len, null, 0) == -1) return platform; - - platform.version = bun.sliceTo(&osversion_name, 0); - return platform; - } - - pub var linux_os_name: std.c.utsname = undefined; - var platform_: analytics.Platform = undefined; - pub const Platform = analytics.Platform; - var linux_kernel_version: Semver.Version = undefined; - var run_once = std.once(struct { - fn run() void { - if (comptime Environment.isMac) { - platform_ = forMac(); - } else if (comptime Environment.isLinux) { - platform_ = forLinux(); - - const release = bun.sliceTo(&linux_os_name.release, 0); - const sliced_string = Semver.SlicedString.init(release, release); - const result = Semver.Version.parse(sliced_string); - linux_kernel_version = result.version.min(); - } else if (comptime Environment.isFreeBSD) { - platform_ = forFreeBSD(); - } else if (Environment.isWindows) { - platform_ = Platform{ - .os = analytics.OperatingSystem.windows, - .version = &[_]u8{}, - .arch = platform_arch, - }; - } - } - }.run); - - pub fn forOS() analytics.Platform { - run_once.call(); - return platform_; - } - - // On macOS 13, tests that use sendmsg_x or recvmsg_x hang. - var use_msgx_on_macos_14_or_later: bool = undefined; - var detectUseMsgXOnMacOS14OrLater_once = std.once(detectUseMsgXOnMacOS14OrLater); - fn detectUseMsgXOnMacOS14OrLater() void { - const version = Semver.Version.parseUTF8(forOS().version); - use_msgx_on_macos_14_or_later = version.valid and version.version.max().major >= 14; - } - pub export fn Bun__doesMacOSVersionSupportSendRecvMsgX() i32 { - if (comptime !Environment.isMac) { - // this should not be used on non-mac platforms. - return 0; - } - - detectUseMsgXOnMacOS14OrLater_once.call(); - return @intFromBool(use_msgx_on_macos_14_or_later); - } - - pub fn kernelVersion() Semver.Version { - if (comptime !Environment.isLinux) { - @compileError("This function is only implemented on Linux"); - } - _ = forOS(); - - return linux_kernel_version; - } - - export fn Bun__isEpollPwait2SupportedOnLinuxKernel() i32 { - if (comptime !Environment.isLinux) { - return 0; - } - - // https://man.archlinux.org/man/epoll_pwait2.2.en#HISTORY - const min_epoll_pwait2 = Semver.Version{ - .major = 5, - .minor = 11, - .patch = 0, - }; - - return switch (kernelVersion().order(min_epoll_pwait2, "", "")) { - .gt => 1, - .eq => 1, - .lt => 0, - }; - } - - fn forLinux() analytics.Platform { - linux_os_name = std.mem.zeroes(@TypeOf(linux_os_name)); - - _ = std.c.uname(&linux_os_name); - - // Confusingly, the "release" tends to contain the kernel version much more frequently than the "version" field. - const release = bun.sliceTo(&linux_os_name.release, 0); - - if (comptime Environment.isAndroid) { - return analytics.Platform{ .os = analytics.OperatingSystem.android, .version = release, .arch = platform_arch }; - } - - // Linux DESKTOP-P4LCIEM 5.10.16.3-microsoft-standard-WSL2 #1 SMP Fri Apr 2 22:23:49 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux - if (std.mem.indexOf(u8, release, "microsoft") != null) { - return analytics.Platform{ .os = analytics.OperatingSystem.wsl, .version = release, .arch = platform_arch }; - } - - return analytics.Platform{ .os = analytics.OperatingSystem.linux, .version = release, .arch = platform_arch }; - } - - // Zig std's `std.c.utsname` has no FreeBSD branch; use translate-c's. - var freebsd_os_name: if (Environment.isFreeBSD) bun.c.struct_utsname else void = undefined; - fn forFreeBSD() analytics.Platform { - freebsd_os_name = std.mem.zeroes(@TypeOf(freebsd_os_name)); - _ = bun.c.uname(&freebsd_os_name); - return analytics.Platform{ - .os = analytics.OperatingSystem.freebsd, - .version = bun.sliceTo(&freebsd_os_name.release, 0), - .arch = platform_arch, - }; - } - }; -}; - -const std = @import("std"); -const analytics = @import("./schema.zig").analytics; - -const bun = @import("bun"); -const Environment = bun.Environment; -const Semver = bun.Semver; diff --git a/src/analytics/schema.zig b/src/analytics/schema.zig deleted file mode 100644 index 95dfa2661e84..000000000000 --- a/src/analytics/schema.zig +++ /dev/null @@ -1,526 +0,0 @@ -pub const Reader = struct { - const Self = @This(); - pub const ReadError = error{EOF}; - - buf: []u8, - remain: []u8, - allocator: std.mem.Allocator, - - pub fn init(buf: []u8, allocator: std.mem.Allocator) Reader { - return Reader{ - .buf = buf, - .remain = buf, - .allocator = allocator, - }; - } - - pub fn read(this: *Self, count: usize) ![]u8 { - const read_count = @min(count, this.remain.len); - if (read_count < count) { - return error.EOF; - } - - const slice = this.remain[0..read_count]; - - this.remain = this.remain[read_count..]; - - return slice; - } - - pub inline fn readAs(this: *Self, comptime T: type) !T { - if (!std.meta.hasUniqueRepresentation(T)) { - @compileError(@typeName(T) ++ " must have unique representation."); - } - - return std.mem.bytesAsValue(T, try this.read(@sizeOf(T))); - } - - pub inline fn readByte(this: *Self) !u8 { - return (try this.read(1))[0]; - } - - pub fn readEnum(this: *Self, comptime Enum: type) !Enum { - const E = error{ - /// An integer was read, but it did not match any of the tags in the supplied enum. - InvalidValue, - }; - const type_info = @typeInfo(Enum).Enum; - const tag = try this.readInt(type_info.tag_type); - - inline for (std.meta.fields(Enum)) |field| { - if (tag == field.value) { - return @field(Enum, field.name); - } - } - - return E.InvalidValue; - } - - pub fn readArray(this: *Self, comptime T: type) ![]const T { - const length = try this.readInt(u32); - if (length == 0) { - return &([_]T{}); - } - - switch (T) { - u8 => { - return try this.read(length); - }, - u16, u32, i8, i16, i32 => { - return std.mem.readIntSliceNative(T, this.read(length * @sizeOf(T))); - }, - [:0]const u8, []const u8 => { - const array = try this.allocator.alloc(T, length); - for (array) |*a| a.* = try this.readArray(u8); - return array; - }, - else => { - switch (comptime @typeInfo(T)) { - .Struct => |Struct| { - switch (Struct.layout) { - .Packed => { - const sizeof = @sizeOf(T); - const slice = try this.read(sizeof * length); - return std.mem.bytesAsSlice(T, slice); - }, - else => {}, - } - }, - .Enum => |type_info| { - const enum_values = try this.read(length * @sizeOf(type_info.tag_type)); - return @as([*]T, @ptrCast(enum_values.ptr))[0..length]; - }, - else => {}, - } - - const array = try this.allocator.alloc(T, length); - for (array) |*v| v.* = try this.readValue(T); - return array; - }, - } - } - - pub inline fn readByteArray(this: *Self) ![]u8 { - const length = try this.readInt(u32); - if (length == 0) { - return &([_]u8{}); - } - - return try this.read(@as(usize, length)); - } - - pub inline fn readInt(this: *Self, comptime T: type) !T { - const slice = try this.read(@sizeOf(T)); - - return std.mem.readIntSliceNative(T, slice); - } - - pub inline fn readBool(this: *Self) !bool { - return (try this.readByte()) > 0; - } - - pub inline fn readValue(this: *Self, comptime T: type) !T { - switch (comptime T) { - bool => { - return try this.readBool(); - }, - u8 => { - return try this.readByte(); - }, - [*:0]const u8, [:0]const u8, []const u8 => { - return try this.readArray(u8); - }, - - []const [:0]const u8, []const [*:0]const u8, []const []const u8 => { - return try this.readArray([]const u8); - }, - []u8, [:0]u8, [*:0]u8 => { - return try this.readArray([]u8); - }, - u16, u32, i8, i16, i32 => { - return std.mem.readIntSliceNative(T, try this.read(@sizeOf(T))); - }, - else => { - switch (comptime @typeInfo(T)) { - .Struct => |Struct| { - switch (Struct.layout) { - .Packed => { - const sizeof = @sizeOf(T); - var slice = try this.read(sizeof); - return @as(*align(1) T, @ptrCast(slice[0..sizeof])).*; - }, - else => {}, - } - }, - .Enum => { - return try this.readEnum(T); - }, - else => {}, - } - - return try T.decode(this); - }, - } - - @compileError("Invalid type passed to readValue"); - } -}; - -pub fn Writer(comptime WritableStream: type) type { - return struct { - const Self = @This(); - writable: WritableStream, - - pub fn init(writable: WritableStream) Self { - return Self{ .writable = writable }; - } - - pub inline fn write(this: *Self, bytes: anytype) !void { - _ = try this.writable.write(bytes); - } - - pub inline fn writeByte(this: *Self, byte: u8) !void { - _ = try this.writable.write(&[1]u8{byte}); - } - - pub inline fn writeInt(this: *Self, int: anytype) !void { - try this.write(std.mem.asBytes(&int)); - } - - pub inline fn writeFieldID(this: *Self, comptime id: comptime_int) !void { - try this.writeByte(id); - } - - pub inline fn writeEnum(this: *Self, val: anytype) !void { - try this.writeInt(@intFromEnum(val)); - } - - pub fn writeValue(this: *Self, comptime SliceType: type, slice: SliceType) !void { - switch (SliceType) { - []u16, - []u32, - []i16, - []i32, - []i8, - []const u16, - []const u32, - []const i16, - []const i32, - []const i8, - [:0]u16, - [:0]u32, - [:0]i16, - [:0]i32, - [:0]i8, - [:0]const u16, - [:0]const u32, - [:0]const i16, - [:0]const i32, - [:0]const i8, - [*:0]u16, - [*:0]u32, - [*:0]i16, - [*:0]i32, - [*:0]i8, - [*:0]const u16, - [*:0]const u32, - [*:0]const i16, - [*:0]const i32, - [*:0]const i8, - => { - try this.writeArray(SliceType, slice); - }, - - []u8, - []const u8, - [:0]u8, - [:0]const u8, - [*:0]u8, - [*:0]const u8, - => { - try this.writeArray(u8, slice); - }, - - u8 => { - try this.write(slice); - }, - u16, u32, i16, i32, i8 => { - try this.write(std.mem.asBytes(slice)); - }, - - else => { - try slice.encode(this); - }, - } - } - - pub fn writeArray(this: *Self, comptime T: type, slice: anytype) !void { - try this.writeInt(@as(u32, @truncate(slice.len))); - - switch (T) { - u8 => { - try this.write(slice); - }, - u16, u32, i16, i32, i8 => { - try this.write(std.mem.asBytes(slice)); - }, - [:0]u8, - []u8, - []u16, - []u32, - []i16, - []i32, - []i8, - []const u8, - [:0]const u8, - []const u16, - []const u32, - []const i16, - []const i32, - []const i8, - [:0]u16, - [:0]u32, - [:0]i16, - [:0]i32, - [:0]i8, - [:0]const u16, - [:0]const u32, - [:0]const i16, - [:0]const i32, - [:0]const i8, - [*:0]u16, - [*:0]u32, - [*:0]i16, - [*:0]i32, - [*:0]i8, - [*:0]const u16, - [*:0]const u32, - [*:0]const i16, - [*:0]const i32, - [*:0]const i8, - => { - for (slice) |num_slice| { - try this.writeArray(std.meta.Child(@TypeOf(num_slice)), num_slice); - } - }, - else => { - for (slice) |val| { - try val.encode(this); - } - }, - } - } - - pub inline fn endMessage(this: *Self) !void { - try this.writeByte(0); - } - }; -} - -pub const ByteWriter = Writer(*std.io.FixedBufferStream([]u8)); -pub const FileWriter = Writer(std.fs.File); - -pub const analytics = struct { - pub const OperatingSystem = enum(u8) { - _none, - /// linux - linux, - - /// macos - macos, - - /// windows - windows, - - /// wsl - wsl, - - /// android - android, - - /// freebsd - freebsd, - - _, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - }; - - pub const Architecture = enum(u8) { - _none, - /// x64 - x64, - - /// arm - arm, - - _, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - }; - - pub const Platform = struct { - /// os - os: OperatingSystem, - - /// arch - arch: Architecture, - - /// version - version: []const u8, - - pub fn decode(reader: anytype) anyerror!Platform { - var this = std.mem.zeroes(Platform); - - this.os = try reader.readValue(OperatingSystem); - this.arch = try reader.readValue(Architecture); - this.version = try reader.readArray(u8); - return this; - } - - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.os); - try writer.writeEnum(this.arch); - try writer.writeArray(u8, this.version); - } - }; - - pub const EventKind = enum(u32) { - _none, - /// bundle_success - bundle_success, - - /// bundle_fail - bundle_fail, - - /// http_start - http_start, - - /// http_build - http_build, - - /// bundle_start - bundle_start, - - _, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - }; - - pub const Uint64 = packed struct { - /// first - first: u32 = 0, - - /// second - second: u32 = 0, - - pub fn decode(reader: anytype) anyerror!Uint64 { - var this = std.mem.zeroes(Uint64); - - this.first = try reader.readValue(u32); - this.second = try reader.readValue(u32); - return this; - } - - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.first); - try writer.writeInt(this.second); - } - }; - - pub const EventListHeader = struct { - /// machine_id - machine_id: Uint64, - - /// session_id - session_id: u32 = 0, - - /// platform - platform: Platform, - - /// build_id - build_id: u32 = 0, - - /// project_id - project_id: Uint64, - - /// session_length - session_length: u32 = 0, - - /// feature_usage - feature_usage: u32 = 0, - - pub fn decode(reader: anytype) anyerror!EventListHeader { - var this = std.mem.zeroes(EventListHeader); - - this.machine_id = try reader.readValue(Uint64); - this.session_id = try reader.readValue(u32); - this.platform = try reader.readValue(Platform); - this.build_id = try reader.readValue(u32); - this.project_id = try reader.readValue(Uint64); - this.session_length = try reader.readValue(u32); - this.feature_usage = try reader.readValue(u32); - return this; - } - - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(@TypeOf(this.machine_id), this.machine_id); - try writer.writeInt(this.session_id); - try writer.writeValue(@TypeOf(this.platform), this.platform); - try writer.writeInt(this.build_id); - try writer.writeValue(@TypeOf(this.project_id), this.project_id); - try writer.writeInt(this.session_length); - try writer.writeInt(this.feature_usage); - } - }; - - pub const EventHeader = struct { - /// timestamp - timestamp: Uint64, - - /// kind - kind: EventKind, - - pub fn decode(reader: anytype) anyerror!EventHeader { - var this = std.mem.zeroes(EventHeader); - - this.timestamp = try reader.readValue(Uint64); - this.kind = try reader.readValue(EventKind); - return this; - } - - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(@TypeOf(this.timestamp), this.timestamp); - try writer.writeEnum(this.kind); - } - }; - - pub const EventList = struct { - /// header - header: EventListHeader, - - /// event_count - event_count: u32 = 0, - - pub fn decode(reader: anytype) anyerror!EventList { - var this = std.mem.zeroes(EventList); - - this.header = try reader.readValue(EventListHeader); - this.event_count = try reader.readValue(u32); - return this; - } - - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(@TypeOf(this.header), this.header); - try writer.writeInt(this.event_count); - } - }; -}; - -const std = @import("std"); diff --git a/src/ast/ast.zig b/src/ast/ast.zig deleted file mode 100644 index a7d51017160a..000000000000 --- a/src/ast/ast.zig +++ /dev/null @@ -1,143 +0,0 @@ -pub const TopLevelSymbolToParts = std.ArrayHashMapUnmanaged(Ref, BabyList(u32), Ref.ArrayHashCtx, false); - -approximate_newline_count: usize = 0, -has_lazy_export: bool = false, -runtime_imports: Runtime.Imports = .{}, - -nested_scope_slot_counts: SlotCounts = SlotCounts{}, - -runtime_import_record_id: ?u32 = null, -needs_runtime: bool = false, -// This is a list of CommonJS features. When a file uses CommonJS features, -// it's not a candidate for "flat bundling" and must be wrapped in its own -// closure. -has_top_level_return: bool = false, -uses_exports_ref: bool = false, -uses_module_ref: bool = false, -uses_require_ref: bool = false, -commonjs_module_exports_assigned_deoptimized: bool = false, - -force_cjs_to_esm: bool = false, -exports_kind: ExportsKind = ExportsKind.none, - -// This is a list of ES6 features. They are ranges instead of booleans so -// that they can be used in log messages. Check to see if "Len > 0". -import_keyword: logger.Range = logger.Range.None, // Does not include TypeScript-specific syntax or "import()" -export_keyword: logger.Range = logger.Range.None, // Does not include TypeScript-specific syntax -top_level_await_keyword: logger.Range = logger.Range.None, - -/// These are stored at the AST level instead of on individual AST nodes so -/// they can be manipulated efficiently without a full AST traversal -import_records: ImportRecord.List = .{}, - -hashbang: string = "", -directive: ?string = null, -parts: Part.List = Part.List{}, -// This list may be mutated later, so we should store the capacity -symbols: Symbol.List = Symbol.List{}, -module_scope: Scope = Scope{}, -char_freq: ?CharFreq = null, -exports_ref: Ref = Ref.None, -module_ref: Ref = Ref.None, -/// When using format .bake_internal_dev, this is the HMR variable instead -/// of the wrapper. This is because that format does not store module -/// wrappers in a variable. -wrapper_ref: Ref = Ref.None, -require_ref: Ref = Ref.None, - -// These are used when bundling. They are filled in during the parser pass -// since we already have to traverse the AST then anyway and the parser pass -// is conveniently fully parallelized. -named_imports: NamedImports = .{}, -named_exports: NamedExports = .{}, -export_star_import_records: []u32 = &([_]u32{}), - -// allocator: std.mem.Allocator, -top_level_symbols_to_parts: TopLevelSymbolToParts = .{}, - -commonjs_named_exports: CommonJSNamedExports = .{}, - -redirect_import_record_index: ?u32 = null, - -/// Only populated when bundling -target: bun.options.Target = .browser, -// const_values: ConstValuesMap = .{}, -ts_enums: TsEnumsMap = .{}, - -/// Not to be confused with `commonjs_named_exports` -/// This is a list of named exports that may exist in a CommonJS module -/// We use this with `commonjs_at_runtime` to re-export CommonJS -has_commonjs_export_names: bool = false, -has_import_meta: bool = false, -import_meta_ref: Ref = Ref.None, - -pub const CommonJSNamedExport = struct { - loc_ref: LocRef, - needs_decl: bool = true, -}; -pub const CommonJSNamedExports = bun.StringArrayHashMapUnmanaged(CommonJSNamedExport); - -pub const NamedImports = std.ArrayHashMapUnmanaged(Ref, NamedImport, RefHashCtx, true); -pub const NamedExports = bun.StringArrayHashMapUnmanaged(NamedExport); -pub const ConstValuesMap = std.ArrayHashMapUnmanaged(Ref, Expr, RefHashCtx, false); -pub const TsEnumsMap = std.ArrayHashMapUnmanaged(Ref, bun.StringHashMapUnmanaged(InlinedEnumValue), RefHashCtx, false); - -pub fn fromParts(parts: []Part) Ast { - return Ast{ - .parts = Part.List.fromOwnedSlice(parts), - .runtime_imports = .{}, - }; -} - -pub fn initTest(parts: []const Part) Ast { - return Ast{ - .parts = Part.List.fromBorrowedSliceDangerous(parts), - .runtime_imports = .{}, - }; -} - -pub const empty = Ast{ .parts = Part.List{}, .runtime_imports = .{} }; - -pub fn toJSON(self: *const Ast, _: std.mem.Allocator, stream: anytype) !void { - const opts = std.json.StringifyOptions{ .whitespace = std.json.StringifyOptions.Whitespace{ - .separator = true, - } }; - try std.json.stringify(self.parts, opts, stream); -} - -/// Do not call this if it wasn't globally allocated! -pub fn deinit(this: *Ast) void { - // TODO: assert mimalloc-owned memory - this.parts.deinit(bun.default_allocator); - this.symbols.deinit(bun.default_allocator); - this.import_records.deinit(bun.default_allocator); -} - -pub const Class = G.Class; - -const string = []const u8; - -const std = @import("std"); -const Runtime = @import("../runtime.zig").Runtime; - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const ImportRecord = bun.ImportRecord; -const logger = bun.logger; - -const js_ast = bun.ast; -const Ast = js_ast.Ast; -const CharFreq = js_ast.CharFreq; -const ExportsKind = js_ast.ExportsKind; -const Expr = js_ast.Expr; -const G = js_ast.G; -const InlinedEnumValue = js_ast.InlinedEnumValue; -const LocRef = js_ast.LocRef; -const NamedExport = js_ast.NamedExport; -const NamedImport = js_ast.NamedImport; -const Part = js_ast.Part; -const Ref = js_ast.Ref; -const RefHashCtx = js_ast.RefHashCtx; -const Scope = js_ast.Scope; -const SlotCounts = js_ast.SlotCounts; -const Symbol = js_ast.Symbol; diff --git a/src/ast/ast_memory_allocator.zig b/src/ast/ast_memory_allocator.zig deleted file mode 100644 index 2724e8d5a25d..000000000000 --- a/src/ast/ast_memory_allocator.zig +++ /dev/null @@ -1,94 +0,0 @@ -const SFA = std.heap.StackFallbackAllocator(@min(8192, std.heap.page_size_min)); - -stack_allocator: SFA = undefined, -bump_allocator: std.mem.Allocator = undefined, -allocator: std.mem.Allocator, -previous: ?*ASTMemoryAllocator = null, - -pub fn enter(this: *ASTMemoryAllocator, allocator: std.mem.Allocator) ASTMemoryAllocator.Scope { - this.allocator = allocator; - this.stack_allocator = SFA{ - .buffer = undefined, - .fallback_allocator = allocator, - .fixed_buffer_allocator = undefined, - }; - this.bump_allocator = this.stack_allocator.get(); - this.previous = null; - var ast_scope = ASTMemoryAllocator.Scope{ - .current = this, - .previous = Stmt.Data.Store.memory_allocator, - }; - ast_scope.enter(); - return ast_scope; -} -pub const Scope = struct { - current: ?*ASTMemoryAllocator = null, - previous: ?*ASTMemoryAllocator = null, - - pub fn enter(this: *@This()) void { - bun.debugAssert(Expr.Data.Store.memory_allocator == Stmt.Data.Store.memory_allocator); - - this.previous = Expr.Data.Store.memory_allocator; - - const current = this.current; - - Expr.Data.Store.memory_allocator = current; - Stmt.Data.Store.memory_allocator = current; - - if (current == null) { - Stmt.Data.Store.begin(); - Expr.Data.Store.begin(); - } - } - - pub fn exit(this: *const @This()) void { - Expr.Data.Store.memory_allocator = this.previous; - Stmt.Data.Store.memory_allocator = this.previous; - } -}; - -pub fn reset(this: *ASTMemoryAllocator) void { - this.stack_allocator = SFA{ - .buffer = undefined, - .fallback_allocator = this.allocator, - .fixed_buffer_allocator = undefined, - }; - this.bump_allocator = this.stack_allocator.get(); -} - -pub fn push(this: *ASTMemoryAllocator) void { - Stmt.Data.Store.memory_allocator = this; - Expr.Data.Store.memory_allocator = this; -} - -pub fn pop(this: *ASTMemoryAllocator) void { - const prev = this.previous; - bun.assert(prev != this); - Stmt.Data.Store.memory_allocator = prev; - Expr.Data.Store.memory_allocator = prev; - this.previous = null; -} - -pub fn append(this: *ASTMemoryAllocator, comptime ValueType: type, value: anytype) *ValueType { - const ptr = this.bump_allocator.create(ValueType) catch unreachable; - ptr.* = value; - return ptr; -} - -/// Initialize ASTMemoryAllocator as `undefined`, and call this. -pub fn initWithoutStack(this: *ASTMemoryAllocator, arena: std.mem.Allocator) void { - this.stack_allocator = SFA{ - .buffer = undefined, - .fallback_allocator = arena, - .fixed_buffer_allocator = .init(&.{}), - }; - this.bump_allocator = this.stack_allocator.get(); -} - -const bun = @import("bun"); -const std = @import("std"); - -const js_ast = bun.ast; -const ASTMemoryAllocator = js_ast.ASTMemoryAllocator; -const Expr = js_ast.Expr; -const Stmt = js_ast.Stmt; diff --git a/src/ast/b.zig b/src/ast/b.zig deleted file mode 100644 index d31d90be5166..000000000000 --- a/src/ast/b.zig +++ /dev/null @@ -1,104 +0,0 @@ -/// B is for Binding! Bindings are on the left side of variable -/// declarations (s_local), which is how destructuring assignments -/// are represented in memory. Consider a basic example. -/// -/// let hello = world; -/// ^ ^ -/// | E.Identifier -/// B.Identifier -/// -/// Bindings can be nested -/// -/// B.Array -/// | B.Identifier -/// | | -/// let { foo: [ bar ] } = ... -/// ---------------- -/// B.Object -pub const B = union(Binding.Tag) { - // let x = ... - b_identifier: *B.Identifier, - // let [a, b] = ... - b_array: *B.Array, - // let { a, b: c } = ... - b_object: *B.Object, - // this is used to represent array holes - b_missing: B.Missing, - - pub const Identifier = struct { - ref: Ref, - }; - - pub const Property = struct { - flags: Flags.Property.Set = Flags.Property.None, - key: ExprNodeIndex, - value: Binding, - default_value: ?Expr = null, - }; - - pub const Object = struct { - properties: []B.Property, - is_single_line: bool = false, - - pub const Property = B.Property; - }; - - pub const Array = struct { - items: []ArrayBinding, - has_spread: bool = false, - is_single_line: bool = false, - - pub const Item = ArrayBinding; - }; - - pub const Missing = struct {}; - - /// This hash function is currently only used for React Fast Refresh transform. - /// This doesn't include the `is_single_line` properties, as they only affect whitespace. - pub fn writeToHasher(b: B, hasher: anytype, symbol_table: anytype) void { - switch (b) { - .b_identifier => |id| { - const original_name = id.ref.getSymbol(symbol_table).original_name; - writeAnyToHasher(hasher, .{ std.meta.activeTag(b), original_name.len }); - }, - .b_array => |array| { - writeAnyToHasher(hasher, .{ std.meta.activeTag(b), array.has_spread, array.items.len }); - for (array.items) |item| { - writeAnyToHasher(hasher, .{item.default_value != null}); - if (item.default_value) |default| { - default.data.writeToHasher(hasher, symbol_table); - } - item.binding.data.writeToHasher(hasher, symbol_table); - } - }, - .b_object => |object| { - writeAnyToHasher(hasher, .{ std.meta.activeTag(b), object.properties.len }); - for (object.properties) |property| { - writeAnyToHasher(hasher, .{ property.default_value != null, property.flags }); - if (property.default_value) |default| { - default.data.writeToHasher(hasher, symbol_table); - } - property.key.data.writeToHasher(hasher, symbol_table); - property.value.data.writeToHasher(hasher, symbol_table); - } - }, - .b_missing => {}, - } - } -}; - -pub const Class = G.Class; - -const std = @import("std"); - -const bun = @import("bun"); -const writeAnyToHasher = bun.writeAnyToHasher; - -const js_ast = bun.ast; -const ArrayBinding = js_ast.ArrayBinding; -const Binding = js_ast.Binding; -const Expr = js_ast.Expr; -const ExprNodeIndex = js_ast.ExprNodeIndex; -const Flags = js_ast.Flags; -const G = js_ast.G; -const Ref = js_ast.Ref; diff --git a/src/ast/base.zig b/src/ast/base.zig deleted file mode 100644 index 54016e188b2b..000000000000 --- a/src/ast/base.zig +++ /dev/null @@ -1,235 +0,0 @@ -// TODO: figure out if we actually need this - -pub const RefHashCtx = struct { - pub fn hash(_: @This(), key: Ref) u32 { - return key.hash(); - } - - pub fn eql(_: @This(), ref: Ref, b: Ref, _: usize) bool { - return ref.asU64() == b.asU64(); - } -}; - -pub const RefCtx = struct { - pub fn hash(_: @This(), key: Ref) u64 { - return key.hash64(); - } - - pub fn eql(_: @This(), ref: Ref, b: Ref) bool { - return ref.asU64() == b.asU64(); - } -}; - -/// In some parts of Bun, we have many different IDs pointing to different things. -/// It's easy for them to get mixed up, so we use this type to make sure we don't. -pub const Index = packed struct(u32) { - value: Int, - - pub fn set(this: *Index, val: Int) void { - this.value = val; - } - - /// if you are within the parser, use p.isSourceRuntime() instead, as the - /// runtime index (0) is used as the id for single-file transforms. - pub inline fn isRuntime(this: Index) bool { - return this.value == (comptime runtime.value); - } - - pub const invalid = Index{ .value = std.math.maxInt(Int) }; - pub const runtime = Index{ .value = 0 }; - - pub const bake_server_data = Index{ .value = 1 }; - pub const bake_client_data = Index{ .value = 2 }; - - pub const Int = u32; - - pub inline fn source(num: anytype) Index { - return .{ .value = @as(Int, @truncate(num)) }; - } - - pub inline fn part(num: anytype) Index { - return .{ .value = @as(Int, @truncate(num)) }; - } - - pub fn init(num: anytype) Index { - const NumType = @TypeOf(num); - if (comptime @typeInfo(NumType) == .pointer) { - return init(num.*); - } - - if (comptime bun.Environment.allow_assert) { - return .{ - .value = @as(Int, @intCast(num)), - }; - } - - return .{ - .value = @as(Int, @intCast(num)), - }; - } - - pub inline fn isValid(this: Index) bool { - return this.value != invalid.value; - } - - pub inline fn isInvalid(this: Index) bool { - return !this.isValid(); - } - - pub inline fn get(this: Index) Int { - return this.value; - } -}; - -/// -- original comment from esbuild -- -/// -/// Files are parsed in parallel for speed. We want to allow each parser to -/// generate symbol IDs that won't conflict with each other. We also want to be -/// able to quickly merge symbol tables from all files into one giant symbol -/// table. -/// -/// We can accomplish both goals by giving each symbol ID two parts: a source -/// index that is unique to the parser goroutine, and an inner index that -/// increments as the parser generates new symbol IDs. Then a symbol map can -/// be an array of arrays indexed first by source index, then by inner index. -/// The maps can be merged quickly by creating a single outer array containing -/// all inner arrays from all parsed files. -pub const Ref = packed struct(u64) { - pub const Int = u31; - - inner_index: Int = 0, - - tag: enum(u2) { - invalid, - allocated_name, - source_contents_slice, - symbol, - }, - - source_index: Int = 0, - - /// Represents a null state without using an extra bit - pub const None = Ref{ .inner_index = 0, .source_index = 0, .tag = .invalid }; - - comptime { - bun.assert(None.isEmpty()); - } - - pub inline fn isEmpty(this: Ref) bool { - return this.asU64() == 0; - } - - pub const ArrayHashCtx = RefHashCtx; - pub const HashCtx = RefCtx; - - pub fn isSourceIndexNull(this: anytype) bool { - return this == std.math.maxInt(Int); - } - - pub fn isSymbol(this: Ref) bool { - return this.tag == .symbol; - } - - pub fn format(ref: Ref, writer: *std.Io.Writer) !void { - try writer.print( - "Ref[inner={d}, src={d}, .{s}]", - .{ - ref.innerIndex(), - ref.sourceIndex(), - @tagName(ref.tag), - }, - ); - } - - pub fn dump(ref: Ref, symbol_table: anytype) std.fmt.Alt(DumpImplData, dumpImpl) { - return .{ .data = .{ - .ref = ref, - .symbol = ref.getSymbol(symbol_table), - } }; - } - - const DumpImplData = struct { ref: Ref, symbol: *ast.Symbol }; - fn dumpImpl(data: DumpImplData, writer: *std.Io.Writer) !void { - try writer.print( - "Ref[inner={d}, src={d}, .{s}; original_name={s}, uses={d}]", - .{ - data.ref.inner_index, - data.ref.source_index, - @tagName(data.ref.tag), - data.symbol.original_name, - data.symbol.use_count_estimate, - }, - ); - } - - pub fn isValid(this: Ref) bool { - return this.tag != .invalid; - } - - pub inline fn sourceIndex(this: Ref) Int { - return this.source_index; - } - - pub inline fn innerIndex(this: Ref) Int { - return this.inner_index; - } - - pub inline fn isSourceContentsSlice(this: Ref) bool { - return this.tag == .source_contents_slice; - } - - pub fn init(inner_index: Int, source_index: u32, is_source_contents_slice: bool) Ref { - return .{ - .inner_index = inner_index, - .source_index = @intCast(source_index), - .tag = if (is_source_contents_slice) .source_contents_slice else .allocated_name, - }; - } - - pub fn initSourceEnd(old: Ref) Ref { - bun.assert(old.tag != .invalid); - return init(old.inner_index, old.source_index, old.tag == .source_contents_slice); - } - - pub fn hash(key: Ref) u32 { - return @truncate(key.hash64()); - } - - pub inline fn asU64(key: Ref) u64 { - return @bitCast(key); - } - - pub inline fn hash64(key: Ref) u64 { - return bun.hash(&@as([8]u8, @bitCast(key.asU64()))); - } - - pub fn eql(ref: Ref, other: Ref) bool { - return ref.asU64() == other.asU64(); - } - - pub const isNull = isEmpty; // deprecated - - pub fn jsonStringify(self: *const Ref, writer: anytype) !void { - return try writer.write([2]u32{ self.sourceIndex(), self.innerIndex() }); - } - - pub fn getSymbol(ref: Ref, symbol_table: anytype) *ast.Symbol { - // Different parts of the bundler use different formats of the symbol table - // In the parser you only have one array, and .sourceIndex() is ignored. - // In the bundler, you have a 2D array where both parts of the ref are used. - const resolved_symbol_table = switch (@TypeOf(symbol_table)) { - *const std.array_list.Managed(ast.Symbol) => symbol_table.items, - *std.array_list.Managed(ast.Symbol) => symbol_table.items, - []ast.Symbol => symbol_table, - *ast.Symbol.Map => return symbol_table.get(ref) orelse - unreachable, // ref must exist within symbol table - else => |T| @compileError("Unsupported type to Ref.getSymbol: " ++ @typeName(T)), - }; - return &resolved_symbol_table[ref.innerIndex()]; - } -}; - -const std = @import("std"); - -const bun = @import("bun"); -const ast = bun.ast; diff --git a/src/ast/binding.zig b/src/ast/binding.zig deleted file mode 100644 index 349bd2ae99e8..000000000000 --- a/src/ast/binding.zig +++ /dev/null @@ -1,171 +0,0 @@ -loc: logger.Loc, -data: B, - -const Serializable = struct { - type: Tag, - object: string, - value: B, - loc: logger.Loc, -}; - -pub fn jsonStringify(self: *const @This(), writer: anytype) !void { - return try writer.write(Serializable{ .type = std.meta.activeTag(self.data), .object = "binding", .value = self.data, .loc = self.loc }); -} - -pub fn ToExpr(comptime expr_type: type, comptime func_type: anytype) type { - const ExprType = expr_type; - return struct { - context: *ExprType, - allocator: std.mem.Allocator, - pub const Context = @This(); - - pub fn wrapIdentifier(ctx: *const Context, loc: logger.Loc, ref: Ref) Expr { - return func_type(ctx.context, loc, ref); - } - - pub fn init(context: *ExprType) Context { - return Context{ .context = context, .allocator = context.allocator }; - } - }; -} - -pub fn toExpr(binding: *const Binding, wrapper: anytype) Expr { - const loc = binding.loc; - - switch (binding.data) { - .b_missing => { - return Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = loc }; - }, - .b_identifier => |b| { - return wrapper.wrapIdentifier(loc, b.ref); - }, - .b_array => |b| { - var exprs = wrapper.allocator.alloc(Expr, b.items.len) catch unreachable; - var i: usize = 0; - while (i < exprs.len) : (i += 1) { - const item = b.items[i]; - exprs[i] = convert: { - const expr = toExpr(&item.binding, wrapper); - if (b.has_spread and i == exprs.len - 1) { - break :convert Expr.init(E.Spread, E.Spread{ .value = expr }, expr.loc); - } else if (item.default_value) |default| { - break :convert Expr.assign(expr, default); - } else { - break :convert expr; - } - }; - } - - return Expr.init( - E.Array, - E.Array{ - .items = ExprNodeList.fromOwnedSlice(exprs), - .is_single_line = b.is_single_line, - }, - loc, - ); - }, - .b_object => |b| { - const properties = wrapper - .allocator - .alloc(G.Property, b.properties.len) catch unreachable; - for (properties, b.properties) |*property, item| { - property.* = .{ - .flags = item.flags, - .key = item.key, - .kind = if (item.flags.contains(.is_spread)) - .spread - else - .normal, - .value = toExpr(&item.value, wrapper), - .initializer = item.default_value, - }; - } - return Expr.init( - E.Object, - E.Object{ - .properties = G.Property.List.fromOwnedSlice(properties), - .is_single_line = b.is_single_line, - }, - loc, - ); - }, - } -} - -pub const Tag = enum(u5) { - b_identifier, - b_array, - b_object, - b_missing, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } -}; - -pub var icount: usize = 0; - -pub fn init(t: anytype, loc: logger.Loc) Binding { - icount += 1; - switch (@TypeOf(t)) { - *B.Identifier => { - return Binding{ .loc = loc, .data = B{ .b_identifier = t } }; - }, - *B.Array => { - return Binding{ .loc = loc, .data = B{ .b_array = t } }; - }, - *B.Object => { - return Binding{ .loc = loc, .data = B{ .b_object = t } }; - }, - B.Missing => { - return Binding{ .loc = loc, .data = B{ .b_missing = t } }; - }, - else => { - @compileError("Invalid type passed to Binding.init"); - }, - } -} - -pub fn alloc(allocator: std.mem.Allocator, t: anytype, loc: logger.Loc) Binding { - icount += 1; - switch (@TypeOf(t)) { - B.Identifier => { - const data = allocator.create(B.Identifier) catch unreachable; - data.* = t; - return Binding{ .loc = loc, .data = B{ .b_identifier = data } }; - }, - B.Array => { - const data = allocator.create(B.Array) catch unreachable; - data.* = t; - return Binding{ .loc = loc, .data = B{ .b_array = data } }; - }, - B.Object => { - const data = allocator.create(B.Object) catch unreachable; - data.* = t; - return Binding{ .loc = loc, .data = B{ .b_object = data } }; - }, - B.Missing => { - return Binding{ .loc = loc, .data = B{ .b_missing = .{} } }; - }, - else => { - @compileError("Invalid type passed to Binding.alloc"); - }, - } -} - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const logger = bun.logger; - -const js_ast = bun.ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const ExprNodeList = js_ast.ExprNodeList; -const G = js_ast.G; -const Ref = js_ast.Ref; diff --git a/src/ast/char_freq.zig b/src/ast/char_freq.zig deleted file mode 100644 index 815450f4db59..000000000000 --- a/src/ast/char_freq.zig +++ /dev/null @@ -1,137 +0,0 @@ -pub const char_freq_count = 64; -pub const CharAndCount = struct { - char: u8 = 0, - count: i32 = 0, - index: usize = 0, - - pub const Array = [char_freq_count]CharAndCount; - - pub fn lessThan(_: void, a: CharAndCount, b: CharAndCount) bool { - if (a.count != b.count) { - return a.count > b.count; - } - - if (a.index != b.index) { - return a.index < b.index; - } - - return a.char < b.char; - } -}; - -const Vector = @Vector(char_freq_count, i32); -const Buffer = [char_freq_count]i32; - -freqs: Buffer align(1) = undefined, - -const scan_big_chunk_size = 32; -pub fn scan(this: *CharFreq, text: string, delta: i32) void { - if (delta == 0) - return; - - if (text.len < scan_big_chunk_size) { - scanSmall(&this.freqs, text, delta); - } else { - scanBig(&this.freqs, text, delta); - } -} - -fn scanBig(out: *align(1) Buffer, text: string, delta: i32) void { - // https://zig.godbolt.org/z/P5dPojWGK - var freqs = out.*; - defer out.* = freqs; - var deltas: [256]i32 = [_]i32{0} ** 256; - var remain = text; - - bun.assert(remain.len >= scan_big_chunk_size); - - const unrolled = remain.len - (remain.len % scan_big_chunk_size); - const remain_end = remain.ptr + unrolled; - var unrolled_ptr = remain.ptr; - remain = remain[unrolled..]; - - while (unrolled_ptr != remain_end) : (unrolled_ptr += scan_big_chunk_size) { - const chunk = unrolled_ptr[0..scan_big_chunk_size].*; - inline for (0..scan_big_chunk_size) |i| { - deltas[@as(usize, chunk[i])] += delta; - } - } - - for (remain) |c| { - deltas[@as(usize, c)] += delta; - } - - freqs[0..26].* = deltas['a' .. 'a' + 26].*; - freqs[26 .. 26 * 2].* = deltas['A' .. 'A' + 26].*; - freqs[26 * 2 .. 62].* = deltas['0' .. '0' + 10].*; - freqs[62] = deltas['_']; - freqs[63] = deltas['$']; -} - -fn scanSmall(out: *align(1) Buffer, text: string, delta: i32) void { - var freqs: [char_freq_count]i32 = out.*; - defer out.* = freqs; - - for (text) |c| { - const i: usize = switch (c) { - 'a'...'z' => @as(usize, @intCast(c)) - 'a', - 'A'...'Z' => @as(usize, @intCast(c)) - ('A' - 26), - '0'...'9' => @as(usize, @intCast(c)) + (53 - '0'), - '_' => 62, - '$' => 63, - else => continue, - }; - freqs[i] += delta; - } -} - -pub fn include(this: *CharFreq, other: CharFreq) void { - // https://zig.godbolt.org/z/Mq8eK6K9s - const left: @Vector(char_freq_count, i32) = this.freqs; - const right: @Vector(char_freq_count, i32) = other.freqs; - - this.freqs = left + right; -} - -pub fn compile(this: *const CharFreq, allocator: std.mem.Allocator) NameMinifier { - const array: CharAndCount.Array = brk: { - var _array: CharAndCount.Array = undefined; - - for (&_array, NameMinifier.default_tail, this.freqs, 0..) |*dest, char, freq, i| { - dest.* = CharAndCount{ - .char = char, - .index = i, - .count = freq, - }; - } - - std.sort.pdq(CharAndCount, &_array, {}, CharAndCount.lessThan); - - break :brk _array; - }; - - var minifier = NameMinifier.init(allocator); - minifier.head.ensureTotalCapacityPrecise(NameMinifier.default_head.len) catch unreachable; - minifier.tail.ensureTotalCapacityPrecise(NameMinifier.default_tail.len) catch unreachable; - // TODO: investigate counting number of < 0 and > 0 and pre-allocating - for (array) |item| { - if (item.char < '0' or item.char > '9') { - minifier.head.append(item.char) catch unreachable; - } - minifier.tail.append(item.char) catch unreachable; - } - - return minifier; -} - -pub const Class = G.Class; - -const string = []const u8; - -const bun = @import("bun"); -const std = @import("std"); - -const js_ast = bun.ast; -const CharFreq = js_ast.CharFreq; -const G = js_ast.G; -const NameMinifier = js_ast.NameMinifier; diff --git a/src/ast/e.zig b/src/ast/e.zig deleted file mode 100644 index ba20dd7e2ba9..000000000000 --- a/src/ast/e.zig +++ /dev/null @@ -1,1470 +0,0 @@ -/// This represents an internal property name that can be mangled. The symbol -/// referenced by this expression should be a "SymbolMangledProp" symbol. -pub const NameOfSymbol = struct { - ref: Ref = Ref.None, - - /// If true, a preceding comment contains "@__KEY__" - /// - /// Currently not used - has_property_key_comment: bool = false, -}; - -pub const Array = struct { - items: ExprNodeList = ExprNodeList{}, - comma_after_spread: ?logger.Loc = null, - is_single_line: bool = false, - is_parenthesized: bool = false, - was_originally_macro: bool = false, - close_bracket_loc: logger.Loc = logger.Loc.Empty, - - pub fn push(this: *Array, allocator: std.mem.Allocator, item: Expr) !void { - try this.items.append(allocator, item); - } - - pub inline fn slice(this: Array) []Expr { - return this.items.slice(); - } - - pub fn inlineSpreadOfArrayLiterals( - this: *Array, - allocator: std.mem.Allocator, - estimated_count: usize, - ) !ExprNodeList { - var out: bun.BabyList(Expr) = try .initCapacity( - allocator, - // This over-allocates a little but it's fine - estimated_count + @as(usize, this.items.len), - ); - out.expandToCapacity(); - var remain = out.slice(); - for (this.items.slice()) |item| { - switch (item.data) { - .e_spread => |val| { - if (val.value.data == .e_array) { - for (val.value.data.e_array.items.slice()) |inner_item| { - if (inner_item.data == .e_missing) { - remain[0] = Expr.init(E.Undefined, .{}, inner_item.loc); - remain = remain[1..]; - } else { - remain[0] = inner_item; - remain = remain[1..]; - } - } - - // skip empty arrays - // don't include the inlined spread. - continue; - } - // non-arrays are kept in - }, - else => {}, - } - - remain[0] = item; - remain = remain[1..]; - } - - out.shrinkRetainingCapacity(out.len - remain.len); - return out; - } - - pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").arrayToJS; - - /// Assumes each item in the array is a string - pub fn alphabetizeStrings(this: *Array) void { - if (comptime Environment.allow_assert) { - for (this.items.slice()) |item| { - bun.assert(item.data == .e_string); - } - } - std.sort.pdq(Expr, this.items.slice(), {}, Sorter.isLessThan); - } - - const Sorter = struct { - pub fn isLessThan(ctx: void, lhs: Expr, rhs: Expr) bool { - return strings.cmpStringsAsc(ctx, lhs.data.e_string.data, rhs.data.e_string.data); - } - }; -}; - -pub const Unary = struct { - op: Op.Code, - value: ExprNodeIndex, - flags: Unary.Flags = .{}, - - pub const Flags = packed struct(u8) { - /// The expression "typeof (0, x)" must not become "typeof x" if "x" - /// is unbound because that could suppress a ReferenceError from "x". - /// - /// Also if we know a typeof operator was originally an identifier, then - /// we know that this typeof operator always has no side effects (even if - /// we consider the identifier by itself to have a side effect). - /// - /// Note that there *is* actually a case where "typeof x" can throw an error: - /// when "x" is being referenced inside of its TDZ (temporal dead zone). TDZ - /// checks are not yet handled correctly by Bun, so this possibility is - /// currently ignored. - was_originally_typeof_identifier: bool = false, - - /// Similarly the expression "delete (0, x)" must not become "delete x" - /// because that syntax is invalid in strict mode. We also need to make sure - /// we don't accidentally change the return value: - /// - /// Returns false: - /// "var a; delete (a)" - /// "var a = Object.freeze({b: 1}); delete (a.b)" - /// "var a = Object.freeze({b: 1}); delete (a?.b)" - /// "var a = Object.freeze({b: 1}); delete (a['b'])" - /// "var a = Object.freeze({b: 1}); delete (a?.['b'])" - /// - /// Returns true: - /// "var a; delete (0, a)" - /// "var a = Object.freeze({b: 1}); delete (true && a.b)" - /// "var a = Object.freeze({b: 1}); delete (false || a?.b)" - /// "var a = Object.freeze({b: 1}); delete (null ?? a?.['b'])" - /// - /// "var a = Object.freeze({b: 1}); delete (true ? a['b'] : a['b'])" - was_originally_delete_of_identifier_or_property_access: bool = false, - _: u6 = 0, - }; -}; - -pub const Binary = struct { - left: ExprNodeIndex, - right: ExprNodeIndex, - op: Op.Code, -}; - -pub const Boolean = struct { - value: bool, - pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").boolToJS; -}; -pub const Super = struct {}; -pub const Null = struct {}; -pub const This = struct {}; -pub const Undefined = struct {}; -pub const New = struct { - target: ExprNodeIndex, - args: ExprNodeList = ExprNodeList{}, - - // True if there is a comment containing "@__PURE__" or "#__PURE__" preceding - // this call expression. See the comment inside ECall for more details. - can_be_unwrapped_if_unused: CallUnwrap = .never, - - close_parens_loc: logger.Loc, -}; -pub const NewTarget = struct { - range: logger.Range, -}; -pub const ImportMeta = struct {}; -pub const ImportMetaMain = struct { - /// If we want to print `!import.meta.main`, set this flag to true - /// instead of wrapping in a unary not. This way, the printer can easily - /// print `require.main != module` instead of `!(require.main == module)` - inverted: bool = false, -}; - -pub const Special = union(enum) { - /// emits `exports` or `module.exports` depending on `commonjs_named_exports_deoptimized` - module_exports, - /// `import.meta.hot` - hot_enabled, - /// Acts as .e_undefined, but allows property accesses to the rest of the HMR API. - hot_disabled, - /// `import.meta.hot.data` when HMR is enabled. Not reachable when it is disabled. - hot_data, - /// `import.meta.hot.accept` when HMR is enabled. Truthy. - hot_accept, - /// Converted from `hot_accept` in P.zig's handleImportMetaHotAcceptCall - /// when passed strings. Printed as `hmr.acceptSpecifiers` - hot_accept_visited, - /// Prints the resolved specifier string for an import record. - resolved_specifier_string: ImportRecord.Index, -}; - -pub const Call = struct { - // Node: - target: ExprNodeIndex, - args: ExprNodeList = ExprNodeList{}, - optional_chain: ?OptionalChain = null, - is_direct_eval: bool = false, - close_paren_loc: logger.Loc = logger.Loc.Empty, - - // True if there is a comment containing "@__PURE__" or "#__PURE__" preceding - // this call expression. This is an annotation used for tree shaking, and - // means that the call can be removed if it's unused. It does not mean the - // call is pure (e.g. it may still return something different if called twice). - // - // Note that the arguments are not considered to be part of the call. If the - // call itself is removed due to this annotation, the arguments must remain - // if they have side effects. - can_be_unwrapped_if_unused: CallUnwrap = .never, - - // Used when printing to generate the source prop on the fly - was_jsx_element: bool = false, - - pub fn hasSameFlagsAs(a: *Call, b: *Call) bool { - return (a.optional_chain == b.optional_chain and - a.is_direct_eval == b.is_direct_eval and - a.can_be_unwrapped_if_unused == b.can_be_unwrapped_if_unused); - } -}; - -pub const CallUnwrap = enum(u2) { - never, - if_unused, - if_unused_and_toString_safe, -}; - -pub const Dot = struct { - // target is Node - target: ExprNodeIndex, - name: string, - name_loc: logger.Loc, - optional_chain: ?OptionalChain = null, - - // If true, this property access is known to be free of side-effects. That - // means it can be removed if the resulting value isn't used. - can_be_removed_if_unused: bool = false, - - // If true, this property access is a function that, when called, can be - // unwrapped if the resulting value is unused. Unwrapping means discarding - // the call target but keeping any arguments with side effects. - call_can_be_unwrapped_if_unused: CallUnwrap = .never, - - pub fn hasSameFlagsAs(a: *Dot, b: *Dot) bool { - return (a.optional_chain == b.optional_chain and - a.is_direct_eval == b.is_direct_eval and - a.can_be_removed_if_unused == b.can_be_removed_if_unused and a.call_can_be_unwrapped_if_unused == b.call_can_be_unwrapped_if_unused); - } -}; - -pub const Index = struct { - index: ExprNodeIndex, - target: ExprNodeIndex, - optional_chain: ?OptionalChain = null, - - pub fn hasSameFlagsAs(a: *E.Index, b: *E.Index) bool { - return (a.optional_chain == b.optional_chain); - } -}; - -pub const Arrow = struct { - args: []G.Arg = &[_]G.Arg{}, - body: G.FnBody, - - is_async: bool = false, - has_rest_arg: bool = false, - prefer_expr: bool = false, // Use shorthand if true and "Body" is a single return statement - - pub const noop_return_undefined: Arrow = .{ - .args = &.{}, - .body = .{ - .loc = .Empty, - .stmts = &.{}, - }, - }; -}; - -pub const Function = struct { func: G.Fn }; - -pub const Identifier = struct { - ref: Ref = Ref.None, - - // If we're inside a "with" statement, this identifier may be a property - // access. In that case it would be incorrect to remove this identifier since - // the property access may be a getter or setter with side effects. - must_keep_due_to_with_stmt: bool = false, - - // If true, this identifier is known to not have a side effect (i.e. to not - // throw an exception) when referenced. If false, this identifier may or - // not have side effects when referenced. This is used to allow the removal - // of known globals such as "Object" if they aren't used. - can_be_removed_if_unused: bool = false, - - // If true, this identifier represents a function that, when called, can be - // unwrapped if the resulting value is unused. Unwrapping means discarding - // the call target but keeping any arguments with side effects. - call_can_be_unwrapped_if_unused: bool = false, - - pub inline fn init(ref: Ref) Identifier { - return Identifier{ - .ref = ref, - .must_keep_due_to_with_stmt = false, - .can_be_removed_if_unused = false, - .call_can_be_unwrapped_if_unused = false, - }; - } -}; - -/// This is similar to an `Identifier` but it represents a reference to an ES6 -/// import item. -/// -/// Depending on how the code is linked, the file containing this EImportIdentifier -/// may or may not be in the same module group as the file it was imported from. -/// -/// If it's the same module group than we can just merge the import item symbol -/// with the corresponding symbol that was imported, effectively renaming them -/// to be the same thing and statically binding them together. -/// -/// But if it's a different module group, then the import must be dynamically -/// evaluated using a property access off the corresponding namespace symbol, -/// which represents the result of a require() call. -/// -/// It's stored as a separate type so it's not easy to confuse with a plain -/// identifier. For example, it'd be bad if code trying to convert "{x: x}" into -/// "{x}" shorthand syntax wasn't aware that the "x" in this case is actually -/// "{x: importedNamespace.x}". This separate type forces code to opt-in to -/// doing this instead of opt-out. -pub const ImportIdentifier = struct { - ref: Ref = Ref.None, - - /// If true, this was originally an identifier expression such as "foo". If - /// false, this could potentially have been a member access expression such - /// as "ns.foo" off of an imported namespace object. - was_originally_identifier: bool = false, -}; - -/// This is a dot expression on exports, such as `exports.`. It is given -/// it's own AST node to allow CommonJS unwrapping, in which this can just be -/// the identifier in the Ref -pub const CommonJSExportIdentifier = struct { - ref: Ref = Ref.None, - base: Base = .exports, - - /// The original variant of the dot expression must be known so that in the case that we - /// - fail to convert this to ESM - /// - ALSO see an assignment to `module.exports` (commonjs_module_exports_assigned_deoptimized) - /// It must be known if `exports` or `module.exports` was written in source - /// code, as the distinction will alter behavior. The fixup happens in the printer when - /// printing this node. - pub const Base = enum { - exports, - module_dot_exports, - }; -}; - -// This is similar to EIdentifier but it represents class-private fields and -// methods. It can be used where computed properties can be used, such as -// EIndex and Property. -pub const PrivateIdentifier = struct { - ref: Ref, -}; - -/// In development mode, the new JSX transform has a few special props -/// - `React.jsxDEV(type, arguments, key, isStaticChildren, source, self)` -/// - `arguments`: -/// ```{ ...props, children: children, }``` -/// - `source`: https://github.com/babel/babel/blob/ef87648f3f05ccc393f89dea7d4c7c57abf398ce/packages/babel-plugin-transform-react-jsx-source/src/index.js#L24-L48 -/// ```{ -/// fileName: string | null, -/// columnNumber: number | null, -/// lineNumber: number | null, -/// }``` -/// - `children`: -/// - static the function is React.jsxsDEV, "jsxs" instead of "jsx" -/// - one child? the function is React.jsxDEV, -/// - no children? the function is React.jsxDEV and children is an empty array. -/// `isStaticChildren`: https://github.com/facebook/react/blob/4ca62cac45c288878d2532e5056981d177f9fdac/packages/react/src/jsx/ReactJSXElementValidator.js#L369-L384 -/// This flag means children is an array of JSX Elements literals. -/// The documentation on this is sparse, but it appears that -/// React just calls Object.freeze on the children array. -/// Object.freeze, historically, is quite a bit slower[0] than just not doing that. -/// Given that...I am choosing to always pass "false" to this. -/// This also skips extra state that we'd need to track. -/// If React Fast Refresh ends up using this later, then we can revisit this decision. -/// [0]: https://github.com/automerge/automerge/issues/177 -pub const JSXElement = struct { - /// JSX tag name - ///
=> E.String.init("div") - /// => E.Identifier{.ref = symbolPointingToMyComponent } - /// null represents a fragment - tag: ?ExprNodeIndex = null, - - /// JSX props - properties: G.Property.List = G.Property.List{}, - - /// JSX element children
{this_is_a_child_element}
- children: ExprNodeList = ExprNodeList{}, - - // needed to make sure parse and visit happen in the same order - key_prop_index: i32 = -1, - - flags: Flags.JSXElement.Bitset = Flags.JSXElement.Bitset{}, - - close_tag_loc: logger.Loc = logger.Loc.Empty, - - pub const SpecialProp = enum { - __self, // old react transform used this as a prop - __source, - key, - ref, - any, - - pub const Map = ComptimeStringMap(SpecialProp, .{ - .{ "__self", .__self }, - .{ "__source", .__source }, - .{ "key", .key }, - .{ "ref", .ref }, - }); - }; -}; - -pub const Missing = struct { - pub fn jsonStringify(_: *const @This(), writer: anytype) !void { - return try writer.write(null); - } -}; - -pub const Number = struct { - value: f64, - - const double_digit = [_]string{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "100" }; - const neg_double_digit = [_]string{ "-0", "-1", "-2", "-3", "-4", "-5", "-6", "-7", "-8", "-9", "-10", "-11", "-12", "-13", "-14", "-15", "-16", "-17", "-18", "-19", "-20", "-21", "-22", "-23", "-24", "-25", "-26", "-27", "-28", "-29", "-30", "-31", "-32", "-33", "-34", "-35", "-36", "-37", "-38", "-39", "-40", "-41", "-42", "-43", "-44", "-45", "-46", "-47", "-48", "-49", "-50", "-51", "-52", "-53", "-54", "-55", "-56", "-57", "-58", "-59", "-60", "-61", "-62", "-63", "-64", "-65", "-66", "-67", "-68", "-69", "-70", "-71", "-72", "-73", "-74", "-75", "-76", "-77", "-78", "-79", "-80", "-81", "-82", "-83", "-84", "-85", "-86", "-87", "-88", "-89", "-90", "-91", "-92", "-93", "-94", "-95", "-96", "-97", "-98", "-99", "-100" }; - - /// String concatenation with numbers is required by the TypeScript compiler for - /// "constant expression" handling in enums. We can match the behavior of a JS VM - /// by calling out to the APIs in WebKit which are responsible for this operation. - /// - /// This can return `null` in wasm builds to avoid linking JSC - pub fn toString(this: Number, allocator: std.mem.Allocator) ?string { - return toStringFromF64(this.value, allocator); - } - - pub fn toStringFromF64(value: f64, allocator: std.mem.Allocator) ?string { - if (value == @trunc(value) and (value < std.math.maxInt(i32) and value > std.math.minInt(i32))) { - const int_value = @as(i64, @intFromFloat(value)); - const abs = @as(u64, @intCast(@abs(int_value))); - - // do not allocate for a small set of constant numbers: -100 through 100 - if (abs < double_digit.len) { - return if (int_value < 0) - neg_double_digit[abs] - else - double_digit[abs]; - } - - return std.fmt.allocPrint(allocator, "{d}", .{@as(i32, @intCast(int_value))}) catch return null; - } - - if (std.math.isNan(value)) { - return "NaN"; - } - - if (std.math.isNegativeInf(value)) { - return "-Infinity"; - } - - if (std.math.isInf(value)) { - return "Infinity"; - } - - if (Environment.isNative) { - var buf: [124]u8 = undefined; - return bun.handleOom(allocator.dupe(u8, bun.fmt.FormatDouble.dtoa(&buf, value))); - } else { - // do not attempt to implement the spec here, it would be error prone. - } - - return null; - } - - pub inline fn toU64(self: Number) u64 { - return self.to(u64); - } - - pub inline fn toUsize(self: Number) usize { - return self.to(usize); - } - - pub inline fn toU32(self: Number) u32 { - return self.to(u32); - } - - pub inline fn toU16(self: Number) u16 { - return self.to(u16); - } - - pub fn to(self: Number, comptime T: type) T { - return @as(T, @intFromFloat(@min(@max(@trunc(self.value), 0), comptime @min(std.math.floatMax(f64), @as(f64, @as(comptime_float, std.math.maxInt(T))))))); - } - - pub fn jsonStringify(self: *const Number, writer: anytype) !void { - return try writer.write(self.value); - } - - pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").numberToJS; -}; - -pub const BigInt = struct { - value: string, - - pub var empty = BigInt{ .value = "" }; - - pub fn jsonStringify(self: *const @This(), writer: anytype) !void { - return try writer.write(self.value); - } - - pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").bigIntToJS; -}; - -pub const Object = struct { - properties: G.Property.List = G.Property.List{}, - comma_after_spread: ?logger.Loc = null, - is_single_line: bool = false, - is_parenthesized: bool = false, - was_originally_macro: bool = false, - - close_brace_loc: logger.Loc = logger.Loc.Empty, - - // used in TOML parser to merge properties - pub const Rope = struct { - head: Expr, - next: ?*Rope = null, - pub fn append(this: *Rope, expr: Expr, allocator: std.mem.Allocator) OOM!*Rope { - if (this.next) |next| { - return try next.append(expr, allocator); - } - - const rope = try allocator.create(Rope); - rope.* = .{ .head = expr }; - this.next = rope; - return rope; - } - }; - - pub fn get(self: *const Object, key: string) ?Expr { - return if (asProperty(self, key)) |query| query.expr else @as(?Expr, null); - } - - pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").objectToJS; - - pub fn put(self: *Object, allocator: std.mem.Allocator, key: string, expr: Expr) !void { - if (asProperty(self, key)) |query| { - self.properties.ptr[query.i].value = expr; - } else { - try self.properties.append(allocator, .{ - .key = Expr.init(E.String, E.String.init(key), expr.loc), - .value = expr, - }); - } - } - - pub fn putString(self: *Object, allocator: std.mem.Allocator, key: string, value: string) !void { - return try put(self, allocator, key, Expr.init(E.String, E.String.init(value), logger.Loc.Empty)); - } - - pub const SetError = error{ OutOfMemory, Clobber }; - - pub fn set(self: *const Object, key: Expr, allocator: std.mem.Allocator, value: Expr) SetError!void { - if (self.hasProperty(key.data.e_string.data)) return error.Clobber; - try self.properties.append(allocator, .{ - .key = key, - .value = value, - }); - } - - pub const RopeQuery = struct { - expr: Expr, - rope: *const Rope, - }; - - // this is terribly, shamefully slow - pub fn setRope(self: *Object, rope: *const Rope, allocator: std.mem.Allocator, value: Expr) SetError!void { - if (self.get(rope.head.data.e_string.data)) |existing| { - switch (existing.data) { - .e_array => |array| { - if (rope.next == null) { - try array.push(allocator, value); - return; - } - - if (array.items.last()) |last| { - if (last.data != .e_object) { - return error.Clobber; - } - - try last.data.e_object.setRope(rope.next.?, allocator, value); - return; - } - - try array.push(allocator, value); - return; - }, - .e_object => |object| { - if (rope.next != null) { - try object.setRope(rope.next.?, allocator, value); - return; - } - - return error.Clobber; - }, - else => { - return error.Clobber; - }, - } - } - - var value_ = value; - if (rope.next) |next| { - var obj = Expr.init(E.Object, E.Object{ .properties = .{} }, rope.head.loc); - try obj.data.e_object.setRope(next, allocator, value); - value_ = obj; - } - - try self.properties.append(allocator, .{ - .key = rope.head, - .value = value_, - }); - } - - pub fn getOrPutObject(self: *Object, rope: *const Rope, allocator: std.mem.Allocator) SetError!Expr { - if (self.get(rope.head.data.e_string.data)) |existing| { - switch (existing.data) { - .e_array => |array| { - if (rope.next == null) { - return error.Clobber; - } - - if (array.items.last()) |last| { - if (last.data != .e_object) { - return error.Clobber; - } - - return try last.data.e_object.getOrPutObject(rope.next.?, allocator); - } - - return error.Clobber; - }, - .e_object => |object| { - if (rope.next != null) { - return try object.getOrPutObject(rope.next.?, allocator); - } - - // success - return existing; - }, - else => { - return error.Clobber; - }, - } - } - - if (rope.next) |next| { - var obj = Expr.init(E.Object, E.Object{ .properties = .{} }, rope.head.loc); - const out = try obj.data.e_object.getOrPutObject(next, allocator); - try self.properties.append(allocator, .{ - .key = rope.head, - .value = obj, - }); - return out; - } - - const out = Expr.init(E.Object, E.Object{}, rope.head.loc); - try self.properties.append(allocator, .{ - .key = rope.head, - .value = out, - }); - return out; - } - - pub fn getOrPutArray(self: *Object, rope: *const Rope, allocator: std.mem.Allocator) SetError!Expr { - if (self.get(rope.head.data.e_string.data)) |existing| { - switch (existing.data) { - .e_array => |array| { - if (rope.next == null) { - return existing; - } - - if (array.items.last()) |last| { - if (last.data != .e_object) { - return error.Clobber; - } - - return try last.data.e_object.getOrPutArray(rope.next.?, allocator); - } - - return error.Clobber; - }, - .e_object => |object| { - if (rope.next == null) { - return error.Clobber; - } - - return try object.getOrPutArray(rope.next.?, allocator); - }, - else => { - return error.Clobber; - }, - } - } - - if (rope.next) |next| { - var obj = Expr.init(E.Object, E.Object{ .properties = .{} }, rope.head.loc); - const out = try obj.data.e_object.getOrPutArray(next, allocator); - try self.properties.append(allocator, .{ - .key = rope.head, - .value = obj, - }); - return out; - } - - const out = Expr.init(E.Array, E.Array{}, rope.head.loc); - try self.properties.append(allocator, .{ - .key = rope.head, - .value = out, - }); - return out; - } - - pub fn hasProperty(obj: *const Object, name: string) bool { - for (obj.properties.slice()) |prop| { - const key = prop.key orelse continue; - if (key.data != .e_string) continue; - if (key.data.e_string.eql(string, name)) return true; - } - return false; - } - - pub fn asProperty(obj: *const Object, name: string) ?Expr.Query { - for (obj.properties.slice(), 0..) |prop, i| { - const value = prop.value orelse continue; - const key = prop.key orelse continue; - if (key.data != .e_string) continue; - const key_str = key.data.e_string; - if (key_str.eql(string, name)) { - return Expr.Query{ - .expr = value, - .loc = key.loc, - .i = @as(u32, @truncate(i)), - }; - } - } - - return null; - } - - /// Assumes each key in the property is a string - pub fn alphabetizeProperties(this: *Object) void { - if (comptime Environment.isDebug) { - for (this.properties.slice()) |prop| { - bun.assert(prop.key.?.data == .e_string); - } - } - std.sort.pdq(G.Property, this.properties.slice(), {}, Sorter.isLessThan); - } - - pub fn packageJSONSort(this: *Object) void { - std.sort.pdq(G.Property, this.properties.slice(), {}, PackageJSONSort.Fields.isLessThan); - } - - const PackageJSONSort = struct { - const Fields = enum(u8) { - name = 0, - version = 1, - author = 2, - repository = 3, - config = 4, - main = 5, - module = 6, - dependencies = 7, - devDependencies = 8, - optionalDependencies = 9, - peerDependencies = 10, - exports = 11, - __fake = 12, - - pub const Map = ComptimeStringMap(Fields, .{ - .{ "name", Fields.name }, - .{ "version", Fields.version }, - .{ "author", Fields.author }, - .{ "repository", Fields.repository }, - .{ "config", Fields.config }, - .{ "main", Fields.main }, - .{ "module", Fields.module }, - .{ "dependencies", Fields.dependencies }, - .{ "devDependencies", Fields.devDependencies }, - .{ "optionalDependencies", Fields.optionalDependencies }, - .{ "peerDependencies", Fields.peerDependencies }, - .{ "exports", Fields.exports }, - }); - - pub fn isLessThan(ctx: void, lhs: G.Property, rhs: G.Property) bool { - var lhs_key_size: u8 = @intFromEnum(Fields.__fake); - var rhs_key_size: u8 = @intFromEnum(Fields.__fake); - - if (lhs.key != null and lhs.key.?.data == .e_string) { - lhs_key_size = @intFromEnum(Map.get(lhs.key.?.data.e_string.data) orelse Fields.__fake); - } - - if (rhs.key != null and rhs.key.?.data == .e_string) { - rhs_key_size = @intFromEnum(Map.get(rhs.key.?.data.e_string.data) orelse Fields.__fake); - } - - return switch (std.math.order(lhs_key_size, rhs_key_size)) { - .lt => true, - .gt => false, - .eq => strings.cmpStringsAsc(ctx, lhs.key.?.data.e_string.data, rhs.key.?.data.e_string.data), - }; - } - }; - }; - - const Sorter = struct { - pub fn isLessThan(ctx: void, lhs: G.Property, rhs: G.Property) bool { - return strings.cmpStringsAsc(ctx, lhs.key.?.data.e_string.data, rhs.key.?.data.e_string.data); - } - }; -}; - -pub const Spread = struct { value: ExprNodeIndex }; - -/// JavaScript string literal type -pub const String = struct { - // A version of this where `utf8` and `value` are stored in a packed union, with len as a single u32 was attempted. - // It did not improve benchmarks. Neither did converting this from a heap-allocated type to a stack-allocated type. - // TODO: change this to *const anyopaque and change all uses to either .slice8() or .slice16() - data: []const u8 = "", - prefer_template: bool = false, - - // A very simple rope implementation - // We only use this for string folding, so this is kind of overkill - // We don't need to deal with substrings - next: ?*String = null, - end: ?*String = null, - rope_len: u32 = 0, - is_utf16: bool = false, - - pub fn isIdentifier(this: *String, allocator: std.mem.Allocator) bool { - if (!this.isUTF8()) { - return bun.js_lexer.isIdentifierUTF16(this.slice16()); - } - - return bun.js_lexer.isIdentifier(this.slice(allocator)); - } - - pub const class = E.String{ .data = "class" }; - - pub fn push(this: *String, other: *String) void { - bun.assert(this.isUTF8()); - bun.assert(other.isUTF8()); - - if (other.rope_len == 0) { - other.rope_len = @truncate(other.data.len); - } - - if (this.rope_len == 0) { - this.rope_len = @truncate(this.data.len); - } - - this.rope_len += other.rope_len; - if (this.next == null) { - this.next = other; - this.end = other; - } else { - var end = this.end.?; - while (end.next != null) end = end.end.?; - end.next = other; - this.end = other; - } - } - - /// Cloning the rope string is rarely needed, see `foldStringAddition`'s - /// comments and the 'edgecase/EnumInliningRopeStringPoison' test - pub fn cloneRopeNodes(s: String) String { - var root = s; - - if (root.next != null) { - var current: ?*String = &root; - while (true) { - const node = current.?; - if (node.next) |next| { - node.next = Expr.Data.Store.append(String, next.*); - current = node.next; - } else { - root.end = node; - break; - } - } - } - - return root; - } - - pub fn toUTF8(this: *String, allocator: std.mem.Allocator) !void { - if (!this.is_utf16) return; - this.data = try strings.toUTF8Alloc(allocator, this.slice16()); - this.is_utf16 = false; - } - - pub fn init(value: anytype) String { - const Value = @TypeOf(value); - if (Value == []u16 or Value == []const u16) { - return .{ - .data = @as([*]const u8, @ptrCast(value.ptr))[0..value.len], - .is_utf16 = true, - }; - } - - return .{ .data = value }; - } - - /// E.String containing non-ascii characters may not fully work. - /// https://github.com/oven-sh/bun/issues/11963 - /// More investigation is needed. - pub fn initReEncodeUTF8(utf8: []const u8, allocator: std.mem.Allocator) String { - return if (bun.strings.isAllASCII(utf8)) - init(utf8) - else - init(bun.handleOom(bun.strings.toUTF16AllocForReal(allocator, utf8, false, false))); - } - - pub fn slice8(this: *const String) []const u8 { - bun.assert(!this.is_utf16); - return this.data; - } - - pub fn slice16(this: *const String) []const u16 { - bun.assert(this.is_utf16); - return @as([*]const u16, @ptrCast(@alignCast(this.data.ptr)))[0..this.data.len]; - } - - pub fn resolveRopeIfNeeded(this: *String, allocator: std.mem.Allocator) void { - if (this.next == null or !this.isUTF8()) return; - var bytes = bun.handleOom(std.array_list.Managed(u8).initCapacity(allocator, this.rope_len)); - bytes.appendSliceAssumeCapacity(this.data); - var str = this.next; - while (str) |part| { - bun.handleOom(bytes.appendSlice(part.data)); - str = part.next; - } - this.data = bytes.items; - this.next = null; - } - - pub fn slice(this: *String, allocator: std.mem.Allocator) []const u8 { - this.resolveRopeIfNeeded(allocator); - return bun.handleOom(this.string(allocator)); - } - - fn stringCompareForJavaScript(comptime T: type, a: []const T, b: []const T) std.math.Order { - const a_slice = a[0..@min(a.len, b.len)]; - const b_slice = b[0..@min(a.len, b.len)]; - for (a_slice, b_slice) |a_char, b_char| { - const delta: i32 = @as(i32, a_char) - @as(i32, b_char); - if (delta != 0) { - return if (delta < 0) .lt else .gt; - } - } - return std.math.order(a.len, b.len); - } - - /// Compares two strings lexicographically for JavaScript semantics. - /// Both strings must share the same encoding (UTF-8 vs UTF-16). - pub inline fn order(this: *const String, other: *const String) std.math.Order { - bun.debugAssert(this.isUTF8() == other.isUTF8()); - - if (this.isUTF8()) { - return stringCompareForJavaScript(u8, this.data, other.data); - } else { - return stringCompareForJavaScript(u16, this.slice16(), other.slice16()); - } - } - - pub var empty = String{}; - pub var @"true" = String{ .data = "true" }; - pub var @"false" = String{ .data = "false" }; - pub var @"null" = String{ .data = "null" }; - pub var @"undefined" = String{ .data = "undefined" }; - - pub fn clone(str: *const String, allocator: std.mem.Allocator) !String { - return String{ - .data = try allocator.dupe(u8, str.data), - .prefer_template = str.prefer_template, - .is_utf16 = !str.isUTF8(), - }; - } - - pub fn cloneSliceIfNecessary(str: *const String, allocator: std.mem.Allocator) ![]const u8 { - if (str.isUTF8()) { - return allocator.dupe(u8, str.string(allocator) catch unreachable); - } - - return str.string(allocator); - } - - pub fn javascriptLength(s: *const String) ?u32 { - if (s.rope_len > 0) { - // We only support ascii ropes for now - return s.rope_len; - } - - if (s.isUTF8()) { - if (!strings.isAllASCII(s.data)) { - return null; - } - return @truncate(s.data.len); - } - - return @truncate(s.slice16().len); - } - - pub inline fn len(s: *const String) usize { - return if (s.rope_len > 0) s.rope_len else s.data.len; - } - - pub inline fn isUTF8(s: *const String) bool { - return !s.is_utf16; - } - - pub inline fn isBlank(s: *const String) bool { - return s.len() == 0; - } - - pub inline fn isPresent(s: *const String) bool { - return s.len() > 0; - } - - pub fn eql(s: *const String, comptime _t: type, other: anytype) bool { - if (s.isUTF8()) { - switch (_t) { - @This() => { - if (other.isUTF8()) { - return strings.eqlLong(s.data, other.data, true); - } else { - return strings.utf16EqlString(other.slice16(), s.data); - } - }, - []const u8 => { - return strings.eqlLong(s.data, other, true); - }, - []u16, []const u16 => { - return strings.utf16EqlString(other, s.data); - }, - else => { - @compileError("Invalid type"); - }, - } - } else { - switch (_t) { - @This() => { - if (other.isUTF8()) { - return strings.utf16EqlString(s.slice16(), other.data); - } else { - return std.mem.eql(u16, other.slice16(), s.slice16()); - } - }, - []const u8 => { - return strings.utf16EqlString(s.slice16(), other); - }, - []u16, []const u16 => { - return std.mem.eql(u16, other.slice16(), s.slice16()); - }, - else => { - @compileError("Invalid type"); - }, - } - } - } - - pub fn eqlComptime(s: *const String, comptime value: []const u8) bool { - if (!s.isUTF8()) { - bun.assertf(s.next == null, "transpiler: utf-16 string is a rope", .{}); // utf-16 strings are not ropes - return strings.eqlComptimeUTF16(s.slice16(), value); - } - if (s.next == null) { - // latin-1 or utf-8, non-rope - return strings.eqlComptime(s.data, value); - } - - // latin-1 or utf-8, rope - return eql8Rope(s, value); - } - fn eql8Rope(s: *const String, value: []const u8) bool { - bun.assertf(s.next != null and s.isUTF8(), "transpiler: bad call to eql8Rope", .{}); - if (s.rope_len != value.len) return false; - var i: usize = 0; - var next: ?*const String = s; - while (next) |current| : (next = current.next) { - if (!strings.eqlLong(current.data, value[i..][0..current.data.len], false)) return false; - i += current.data.len; - } - bun.assertf(i == value.len, "transpiler: rope string length mismatch 1", .{}); - bun.assertf(i == s.rope_len, "transpiler: rope string length mismatch 2", .{}); - return true; - } - - pub fn hasPrefixComptime(s: *const String, comptime value: anytype) bool { - if (s.data.len < value.len) - return false; - - return if (s.isUTF8()) - strings.eqlComptime(s.data[0..value.len], value) - else - strings.eqlComptimeUTF16(s.slice16()[0..value.len], value); - } - - pub fn string(s: *const String, allocator: std.mem.Allocator) OOM![]const u8 { - if (s.isUTF8()) { - return s.data; - } else { - return strings.toUTF8Alloc(allocator, s.slice16()); - } - } - - pub fn stringZ(s: *const String, allocator: std.mem.Allocator) OOM![:0]const u8 { - if (s.isUTF8()) { - return allocator.dupeZ(u8, s.data); - } else { - return strings.toUTF8AllocZ(allocator, s.slice16()); - } - } - - pub fn stringCloned(s: *const String, allocator: std.mem.Allocator) OOM![]const u8 { - if (s.isUTF8()) { - return allocator.dupe(u8, s.data); - } else { - return strings.toUTF8Alloc(allocator, s.slice16()); - } - } - - pub fn hash(s: *const String) u64 { - if (s.isBlank()) return 0; - - if (s.isUTF8()) { - // hash utf-8 - return bun.hash(s.data); - } else { - // hash utf-16 - return bun.hash(@as([*]const u8, @ptrCast(s.slice16().ptr))[0 .. s.slice16().len * 2]); - } - } - - pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").stringToJS; - - pub fn toZigString(s: *String, allocator: std.mem.Allocator) jsc.ZigString { - if (s.isUTF8()) { - return jsc.ZigString.fromUTF8(s.slice(allocator)); - } else { - return jsc.ZigString.initUTF16(s.slice16()); - } - } - - pub fn format(s: String, writer: *std.Io.Writer) !void { - try writer.writeAll("E.String"); - if (s.next == null) { - try writer.writeAll("("); - if (s.isUTF8()) { - try writer.print("\"{s}\"", .{s.data}); - } else { - try writer.print("\"{f}\"", .{bun.fmt.utf16(s.slice16())}); - } - try writer.writeAll(")"); - } else { - try writer.writeAll("(rope: ["); - var it: ?*const String = &s; - while (it) |part| { - if (part.isUTF8()) { - try writer.print("\"{s}\"", .{part.data}); - } else { - try writer.print("\"{f}\"", .{bun.fmt.utf16(part.slice16())}); - } - it = part.next; - if (it != null) try writer.writeAll(" "); - } - try writer.writeAll("])"); - } - } - - pub fn jsonStringify(s: *const String, writer: anytype) !void { - var buf = [_]u8{0} ** 4096; - var i: usize = 0; - for (s.slice16()) |char| { - buf[i] = @as(u8, @intCast(char)); - i += 1; - if (i >= 4096) { - break; - } - } - - return try writer.write(buf[0..i]); - } -}; - -// value is in the Node -pub const TemplatePart = struct { - value: ExprNodeIndex, - tail_loc: logger.Loc, - tail: Template.Contents, -}; - -pub const Template = struct { - tag: ?ExprNodeIndex = null, - parts: []TemplatePart = &.{}, - head: Contents, - - pub const Contents = union(Tag) { - cooked: E.String, - raw: string, - - const Tag = enum { - cooked, - raw, - }; - - pub fn isUTF8(contents: Contents) bool { - return contents == .cooked and contents.cooked.isUTF8(); - } - }; - - /// "`a${'b'}c`" => "`abc`" - pub fn fold( - this: *Template, - allocator: std.mem.Allocator, - loc: logger.Loc, - ) Expr { - if (this.tag != null or (this.head == .cooked and !this.head.cooked.isUTF8())) { - // we only fold utf-8/ascii for now - return Expr{ - .data = .{ .e_template = this }, - .loc = loc, - }; - } - - bun.assert(this.head == .cooked); - - if (this.parts.len == 0) { - return Expr.init(E.String, this.head.cooked, loc); - } - - var parts = std.array_list.Managed(TemplatePart).initCapacity(allocator, this.parts.len) catch unreachable; - var head = Expr.init(E.String, this.head.cooked, loc); - for (this.parts) |part_src| { - var part = part_src; - bun.assert(part.tail == .cooked); - - part.value = part.value.unwrapInlined(); - - switch (part.value.data) { - .e_number => { - if (part.value.data.e_number.toString(allocator)) |s| { - part.value = Expr.init(E.String, E.String.init(s), part.value.loc); - } - }, - .e_null => { - part.value = Expr.init(E.String, E.String.init("null"), part.value.loc); - }, - .e_boolean => { - part.value = Expr.init(E.String, E.String.init(if (part.value.data.e_boolean.value) - "true" - else - "false"), part.value.loc); - }, - .e_undefined => { - part.value = Expr.init(E.String, E.String.init("undefined"), part.value.loc); - }, - .e_big_int => |value| { - part.value = Expr.init(E.String, E.String.init(value.value), part.value.loc); - }, - else => {}, - } - - if (part.value.data == .e_string and part.tail.cooked.isUTF8() and part.value.data.e_string.isUTF8()) { - if (parts.items.len == 0) { - if (part.value.data.e_string.len() > 0) { - head.data.e_string.push(Expr.init(E.String, part.value.data.e_string.*, logger.Loc.Empty).data.e_string); - } - - if (part.tail.cooked.len() > 0) { - head.data.e_string.push(Expr.init(E.String, part.tail.cooked, part.tail_loc).data.e_string); - } - - continue; - } else { - var prev_part = &parts.items[parts.items.len - 1]; - bun.assert(prev_part.tail == .cooked); - - if (prev_part.tail.cooked.isUTF8()) { - if (part.value.data.e_string.len() > 0) { - prev_part.tail.cooked.push(Expr.init(E.String, part.value.data.e_string.*, logger.Loc.Empty).data.e_string); - } - - if (part.tail.cooked.len() > 0) { - prev_part.tail.cooked.push(Expr.init(E.String, part.tail.cooked, part.tail_loc).data.e_string); - } - } else { - parts.appendAssumeCapacity(part); - } - } - } else { - parts.appendAssumeCapacity(part); - } - } - - if (parts.items.len == 0) { - parts.deinit(); - head.data.e_string.resolveRopeIfNeeded(allocator); - return head; - } - - return Expr.init(E.Template, .{ - .tag = null, - .parts = parts.items, - .head = .{ .cooked = head.data.e_string.* }, - }, loc); - } -}; - -pub const RegExp = struct { - value: string, - - // This exists for JavaScript bindings - // The RegExp constructor expects flags as a second argument. - // We want to avoid re-lexing the flags, so we store them here. - // This is the index of the first character in a flag, not the "/" - // /foo/gim - // ^ - flags_offset: ?u16 = null, - - pub var empty = RegExp{ .value = "" }; - - pub fn pattern(this: RegExp) string { - - // rewind until we reach the /foo/gim - // ^ - // should only ever be a single character - // but we're being cautious - if (this.flags_offset) |i_| { - var i = i_; - while (i > 0 and this.value[i] != '/') { - i -= 1; - } - - return std.mem.trim(u8, this.value[0..i], "/"); - } - - return std.mem.trim(u8, this.value, "/"); - } - - pub fn flags(this: RegExp) string { - // rewind until we reach the /foo/gim - // ^ - // should only ever be a single character - // but we're being cautious - if (this.flags_offset) |i| { - return this.value[i..]; - } - - return ""; - } - - pub fn jsonStringify(self: *const RegExp, writer: anytype) !void { - return try writer.write(self.value); - } -}; - -pub const Await = struct { - value: ExprNodeIndex, -}; - -pub const Yield = struct { - value: ?ExprNodeIndex = null, - is_star: bool = false, -}; - -pub const If = struct { - test_: ExprNodeIndex, - yes: ExprNodeIndex, - no: ExprNodeIndex, -}; - -pub const RequireString = struct { - import_record_index: u32 = 0, - - unwrapped_id: u32 = std.math.maxInt(u32), -}; - -pub const RequireResolveString = struct { - import_record_index: u32, - - // close_paren_loc: logger.Loc = logger.Loc.Empty, -}; - -pub const InlinedEnum = struct { - value: ExprNodeIndex, - comment: string, -}; - -pub const Import = struct { - expr: ExprNodeIndex, - options: ExprNodeIndex = Expr.empty, - import_record_index: u32, - - /// TODO: - /// Comments inside "import()" expressions have special meaning for Webpack. - /// Preserving comments inside these expressions makes it possible to use - /// esbuild as a TypeScript-to-JavaScript frontend for Webpack to improve - /// performance. We intentionally do not interpret these comments in esbuild - /// because esbuild is not Webpack. But we do preserve them since doing so is - /// harmless, easy to maintain, and useful to people. See the Webpack docs for - /// more info: https://webpack.js.org/api/module-methods/#magic-comments. - // leading_interior_comments: []G.Comment = &([_]G.Comment{}), - - pub fn isImportRecordNull(this: *const Import) bool { - return this.import_record_index == std.math.maxInt(u32); - } - - pub fn importRecordLoader(import: *const Import) ?bun.options.Loader { - // This logic is duplicated in js_printer.zig fn parsePath() - const obj = import.options.data.as(.e_object) orelse - return null; - const with = obj.get("with") orelse obj.get("assert") orelse - return null; - const with_obj = with.data.as(.e_object) orelse - return null; - const str = (with_obj.get("type") orelse - return null).data.as(.e_string) orelse - return null; - - if (!str.is_utf16) if (bun.options.Loader.fromString(str.data)) |loader| { - if (loader == .sqlite) { - const embed = with_obj.get("embed") orelse return loader; - const embed_str = embed.data.as(.e_string) orelse return loader; - if (embed_str.eqlComptime("true")) { - return .sqlite_embedded; - } - } - return loader; - }; - - return null; - } -}; - -pub const Class = G.Class; - -const string = []const u8; -const stringZ = [:0]const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const ComptimeStringMap = bun.ComptimeStringMap; -const Environment = bun.Environment; -const ImportRecord = bun.ImportRecord; -const OOM = bun.OOM; -const jsc = bun.jsc; -const logger = bun.logger; -const strings = bun.strings; -const Loader = bun.options.Loader; - -const js_ast = bun.ast; -const E = js_ast.E; -const Expr = js_ast.Expr; -const ExprNodeIndex = js_ast.ExprNodeIndex; -const ExprNodeList = js_ast.ExprNodeList; -const Flags = js_ast.Flags; -const G = js_ast.G; -const Op = js_ast.Op; -const OptionalChain = js_ast.OptionalChain; -const Ref = js_ast.Ref; diff --git a/src/ast/expr.zig b/src/ast/expr.zig deleted file mode 100644 index e952fe0dc149..000000000000 --- a/src/ast/expr.zig +++ /dev/null @@ -1,3247 +0,0 @@ -loc: logger.Loc, -data: Data, - -pub const empty = Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = logger.Loc.Empty }; - -pub fn isAnonymousNamed(expr: Expr) bool { - return switch (expr.data) { - .e_arrow => true, - .e_function => |func| func.func.name == null, - .e_class => |class| class.class_name == null, - else => false, - }; -} - -pub fn clone(this: Expr, allocator: std.mem.Allocator) !Expr { - return .{ - .loc = this.loc, - .data = try this.data.clone(allocator), - }; -} - -pub fn deepClone(this: Expr, allocator: std.mem.Allocator) OOM!Expr { - return .{ - .loc = this.loc, - .data = try this.data.deepClone(allocator), - }; -} - -pub fn wrapInArrow(this: Expr, allocator: std.mem.Allocator) !Expr { - var stmts = try allocator.alloc(Stmt, 1); - stmts[0] = Stmt.alloc(S.Return, S.Return{ .value = this }, this.loc); - - return Expr.init(E.Arrow, E.Arrow{ - .args = &.{}, - .body = .{ - .loc = this.loc, - .stmts = stmts, - }, - }, this.loc); -} - -pub fn canBeInlinedFromPropertyAccess(this: Expr) bool { - return switch (this.data) { - // if the array has a spread we must keep it - // https://github.com/oven-sh/bun/issues/2594 - .e_spread => false, - - .e_missing => false, - else => true, - }; -} - -pub fn canBeConstValue(this: Expr) bool { - return this.data.canBeConstValue(); -} - -pub fn canBeMoved(expr: Expr) bool { - return expr.data.canBeMoved(); -} - -pub fn unwrapInlined(expr: Expr) Expr { - if (expr.data.as(.e_inlined_enum)) |inlined| return inlined.value; - return expr; -} - -pub fn fromBlob( - blob: *const jsc.WebCore.Blob, - allocator: std.mem.Allocator, - mime_type_: ?MimeType, - log: *logger.Log, - loc: logger.Loc, -) !Expr { - const bytes = blob.sharedView(); - - const mime_type = mime_type_ orelse MimeType.init(blob.content_type, null, null); - - if (mime_type.category == .json) { - const source = &logger.Source.initPathString("fetch.json", bytes); - var out_expr = JSONParser.parseForMacro(source, log, allocator) catch { - return error.MacroFailed; - }; - out_expr.loc = loc; - - switch (out_expr.data) { - .e_object => { - out_expr.data.e_object.was_originally_macro = true; - }, - .e_array => { - out_expr.data.e_array.was_originally_macro = true; - }, - else => {}, - } - - return out_expr; - } - - if (mime_type.category.isTextLike()) { - var output = MutableString.initEmpty(allocator); - try JSPrinter.quoteForJSON(bytes, &output, true); - var list = output.toOwnedSlice(); - // remove the quotes - if (list.len > 0) { - list = list[1 .. list.len - 1]; - } - return Expr.init(E.String, E.String.init(list), loc); - } - - return Expr.init( - E.String, - E.String{ - .data = try jsc.ZigString.init(bytes).toBase64DataURL(allocator), - }, - loc, - ); -} - -pub inline fn initIdentifier(ref: Ref, loc: logger.Loc) Expr { - return Expr{ - .loc = loc, - .data = .{ - .e_identifier = E.Identifier.init(ref), - }, - }; -} - -pub fn toEmpty(expr: Expr) Expr { - return Expr{ .data = .{ .e_missing = E.Missing{} }, .loc = expr.loc }; -} -pub fn isEmpty(expr: Expr) bool { - return expr.data == .e_missing; -} -pub const Query = struct { expr: Expr, loc: logger.Loc, i: u32 = 0 }; - -pub fn hasAnyPropertyNamed(expr: *const Expr, comptime names: []const string) bool { - if (expr.data != .e_object) return false; - const obj = expr.data.e_object; - if (obj.properties.len == 0) return false; - - for (obj.properties.slice()) |prop| { - if (prop.value == null) continue; - const key = prop.key orelse continue; - if (key.data != .e_string) continue; - const key_str = key.data.e_string; - if (strings.eqlAnyComptime(key_str.data, names)) return true; - } - - return false; -} - -pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").exprToJS; - -pub inline fn isArray(this: *const Expr) bool { - return this.data == .e_array; -} - -pub inline fn isObject(this: *const Expr) bool { - return this.data == .e_object; -} - -pub fn get(expr: *const Expr, name: string) ?Expr { - return if (asProperty(expr, name)) |query| query.expr else null; -} - -/// Only use this for pretty-printing JSON. Do not use in transpiler. -/// -/// This does not handle edgecases like `-1` or stringifying arbitrary property lookups. -pub fn getByIndex(expr: *const Expr, index: u32, index_str: string, allocator: std.mem.Allocator) ?Expr { - switch (expr.data) { - .e_array => |array| { - if (index >= array.items.len) return null; - return array.items.slice()[index]; - }, - .e_object => |object| { - for (object.properties.sliceConst()) |*prop| { - const key = &(prop.key orelse continue); - switch (key.data) { - .e_string => |str| { - if (str.eql(string, index_str)) { - return prop.value; - } - }, - .e_number => |num| { - if (num.toU32() == index) { - return prop.value; - } - }, - else => {}, - } - } - - return null; - }, - .e_string => |str| { - if (str.len() > index) { - var slice = str.slice(allocator); - // TODO: this is not correct since .length refers to UTF-16 code units and not UTF-8 bytes - // However, since this is only used in the JSON prettifier for `bun pm view`, it's not a blocker for shipping. - if (slice.len > index) { - return Expr.init(E.String, .{ .data = slice[index..][0..1] }, expr.loc); - } - } - }, - else => {}, - } - - return null; -} - -/// This supports lookups like: -/// - `foo` -/// - `foo.bar` -/// - `foo[123]` -/// - `foo[123].bar` -/// - `foo[123].bar[456]` -/// - `foo[123].bar[456].baz` -/// - `foo[123].bar[456].baz.qux` // etc. -/// -/// This is not intended for use by the transpiler, instead by pretty printing JSON. -pub fn getPathMayBeIndex(expr: *const Expr, name: string) ?Expr { - if (name.len == 0) { - return null; - } - - if (strings.indexOfAny(name, "[.")) |idx| { - switch (name[idx]) { - '[' => { - const end_idx = strings.indexOfChar(name, ']') orelse return null; - var base_expr = expr; - if (idx > 0) { - const key = name[0..idx]; - base_expr = &(base_expr.get(key) orelse return null); - } - - const index_str = name[idx + 1 .. end_idx]; - const index = std.fmt.parseInt(u32, index_str, 10) catch return null; - const rest = if (name.len > end_idx) name[end_idx + 1 ..] else ""; - const result = &(base_expr.getByIndex(index, index_str, bun.default_allocator) orelse return null); - if (rest.len > 0) return result.getPathMayBeIndex(rest); - return result.*; - }, - '.' => { - const key = name[0..idx]; - const sub_expr = &(expr.get(key) orelse return null); - const subpath = if (name.len > idx) name[idx + 1 ..] else ""; - if (subpath.len > 0) { - return sub_expr.getPathMayBeIndex(subpath); - } - - return sub_expr.*; - }, - else => unreachable, - } - } - - return expr.get(name); -} - -/// Don't use this if you care about performance. -/// -/// Sets the value of a property, creating it if it doesn't exist. -/// `expr` must be an object. -pub fn set(expr: *Expr, allocator: std.mem.Allocator, name: string, value: Expr) OOM!void { - bun.assertWithLocation(expr.isObject(), @src()); - for (0..expr.data.e_object.properties.len) |i| { - const prop = &expr.data.e_object.properties.ptr[i]; - const key = prop.key orelse continue; - if (key.data != .e_string) continue; - if (key.data.e_string.eql(string, name)) { - prop.value = value; - return; - } - } - - try expr.data.e_object.properties.append(allocator, .{ - .key = Expr.init(E.String, .{ .data = name }, logger.Loc.Empty), - .value = value, - }); -} - -/// Don't use this if you care about performance. -/// -/// Sets the value of a property to a string, creating it if it doesn't exist. -/// `expr` must be an object. -pub fn setString(expr: *Expr, allocator: std.mem.Allocator, name: string, value: string) OOM!void { - bun.assertWithLocation(expr.isObject(), @src()); - for (0..expr.data.e_object.properties.len) |i| { - const prop = &expr.data.e_object.properties.ptr[i]; - const key = prop.key orelse continue; - if (key.data != .e_string) continue; - if (key.data.e_string.eql(string, name)) { - prop.value = Expr.init(E.String, .{ .data = value }, logger.Loc.Empty); - return; - } - } - - try expr.data.e_object.properties.append(allocator, .{ - .key = Expr.init(E.String, .{ .data = name }, logger.Loc.Empty), - .value = Expr.init(E.String, .{ .data = value }, logger.Loc.Empty), - }); -} - -pub fn getObject(expr: *const Expr, name: string) ?Expr { - if (expr.asProperty(name)) |query| { - if (query.expr.isObject()) { - return query.expr; - } - } - return null; -} - -pub fn getBoolean(expr: *const Expr, name: string) ?bool { - if (expr.asProperty(name)) |query| { - switch (query.expr.data) { - .e_boolean, .e_branch_boolean => |b| return b.value, - else => {}, - } - } - return null; -} - -pub fn getString(expr: *const Expr, allocator: std.mem.Allocator, name: string) OOM!?struct { string, logger.Loc } { - if (asProperty(expr, name)) |q| { - if (q.expr.asString(allocator)) |str| { - return .{ - str, - q.expr.loc, - }; - } - } - return null; -} - -pub fn getNumber(expr: *const Expr, name: string) ?struct { f64, logger.Loc } { - if (asProperty(expr, name)) |q| { - if (q.expr.asNumber()) |num| { - return .{ - num, - q.expr.loc, - }; - } - } - return null; -} - -pub fn getStringCloned(expr: *const Expr, allocator: std.mem.Allocator, name: string) OOM!?string { - return if (asProperty(expr, name)) |q| q.expr.asStringCloned(allocator) else null; -} - -pub fn getStringClonedZ(expr: *const Expr, allocator: std.mem.Allocator, name: string) OOM!?stringZ { - return if (asProperty(expr, name)) |q| q.expr.asStringZ(allocator) else null; -} - -pub fn getArray(expr: *const Expr, name: string) ?ArrayIterator { - return if (asProperty(expr, name)) |q| q.expr.asArray() else null; -} - -pub fn getRope(self: *const Expr, rope: *const E.Object.Rope) ?E.Object.RopeQuery { - if (self.get(rope.head.data.e_string.data)) |existing| { - switch (existing.data) { - .e_array => |array| { - if (rope.next) |next| { - if (array.items.last()) |end| { - return end.getRope(next); - } - } - - return E.Object.RopeQuery{ - .expr = existing, - .rope = rope, - }; - }, - .e_object => { - if (rope.next) |next| { - if (existing.getRope(next)) |end| { - return end; - } - } - - return E.Object.RopeQuery{ - .expr = existing, - .rope = rope, - }; - }, - else => return E.Object.RopeQuery{ - .expr = existing, - .rope = rope, - }, - } - } - - return null; -} - -// Making this comptime bloats the binary and doesn't seem to impact runtime performance. -pub fn asProperty(expr: *const Expr, name: string) ?Query { - if (expr.data != .e_object) return null; - const obj = expr.data.e_object; - if (obj.properties.len == 0) return null; - - return obj.asProperty(name); -} - -pub fn asPropertyStringMap(expr: *const Expr, name: string, allocator: std.mem.Allocator) ?*bun.StringArrayHashMap(string) { - if (expr.data != .e_object) return null; - const obj_ = expr.data.e_object; - if (obj_.properties.len == 0) return null; - const query = obj_.asProperty(name) orelse return null; - if (query.expr.data != .e_object) return null; - - const obj = query.expr.data.e_object; - var count: usize = 0; - for (obj.properties.slice()) |prop| { - const key = prop.key.?.asString(allocator) orelse continue; - const value = prop.value.?.asString(allocator) orelse continue; - count += @as(usize, @intFromBool(key.len > 0 and value.len > 0)); - } - - if (count == 0) return null; - var map = bun.StringArrayHashMap(string).init(allocator); - map.ensureUnusedCapacity(count) catch return null; - - for (obj.properties.slice()) |prop| { - const key = prop.key.?.asString(allocator) orelse continue; - const value = prop.value.?.asString(allocator) orelse continue; - - if (!(key.len > 0 and value.len > 0)) continue; - - map.putAssumeCapacity(key, value); - } - - const ptr = allocator.create(bun.StringArrayHashMap(string)) catch unreachable; - ptr.* = map; - return ptr; -} - -pub const ArrayIterator = struct { - array: *const E.Array, - index: u32, - - pub fn next(this: *ArrayIterator) ?Expr { - if (this.index >= this.array.items.len) { - return null; - } - defer this.index += 1; - return this.array.items.ptr[this.index]; - } -}; - -pub fn asArray(expr: *const Expr) ?ArrayIterator { - if (expr.data != .e_array) return null; - const array = expr.data.e_array; - if (array.items.len == 0) return null; - - return ArrayIterator{ .array = array, .index = 0 }; -} - -pub inline fn asUtf8StringLiteral(expr: *const Expr) ?string { - if (expr.data == .e_string) { - bun.debugAssert(expr.data.e_string.next == null); - return expr.data.e_string.data; - } - return null; -} - -pub inline fn asStringLiteral(expr: *const Expr, allocator: std.mem.Allocator) ?string { - if (expr.data != .e_string) return null; - return expr.data.e_string.string(allocator) catch null; -} - -pub inline fn isString(expr: *const Expr) bool { - return switch (expr.data) { - .e_string => true, - else => false, - }; -} - -pub inline fn asString(expr: *const Expr, allocator: std.mem.Allocator) ?string { - switch (expr.data) { - .e_string => |str| return bun.handleOom(str.string(allocator)), - else => return null, - } -} -pub inline fn asStringHash(expr: *const Expr, allocator: std.mem.Allocator, comptime hash_fn: *const fn (buf: []const u8) callconv(.@"inline") u64) OOM!?u64 { - switch (expr.data) { - .e_string => |str| { - if (str.isUTF8()) return hash_fn(str.data); - const utf8_str = try str.string(allocator); - defer allocator.free(utf8_str); - return hash_fn(utf8_str); - }, - else => return null, - } -} - -pub inline fn asStringCloned(expr: *const Expr, allocator: std.mem.Allocator) OOM!?string { - switch (expr.data) { - .e_string => |str| return try str.stringCloned(allocator), - else => return null, - } -} - -pub inline fn asStringZ(expr: *const Expr, allocator: std.mem.Allocator) OOM!?stringZ { - switch (expr.data) { - .e_string => |str| return try str.stringZ(allocator), - else => return null, - } -} - -pub fn asBool( - expr: *const Expr, -) ?bool { - return switch (expr.data) { - .e_boolean, .e_branch_boolean => |b| b.value, - else => null, - }; -} - -pub fn asNumber(expr: *const Expr) ?f64 { - if (expr.data != .e_number) return null; - - return expr.data.e_number.value; -} - -pub const EFlags = enum { none, ts_decorator }; - -const Serializable = struct { - type: Tag, - object: string, - value: Data, - loc: logger.Loc, -}; - -pub fn isMissing(a: *const Expr) bool { - return a.data == Expr.Tag.e_missing; -} - -// The goal of this function is to "rotate" the AST if it's possible to use the -// left-associative property of the operator to avoid unnecessary parentheses. -// -// When using this, make absolutely sure that the operator is actually -// associative. For example, the "-" operator is not associative for -// floating-point numbers. -pub fn joinWithLeftAssociativeOp( - comptime op: Op.Code, - a: Expr, - b: Expr, - allocator: std.mem.Allocator, -) Expr { - // "(a, b) op c" => "a, b op c" - switch (a.data) { - .e_binary => |comma| { - if (comma.op == .bin_comma) { - comma.right = joinWithLeftAssociativeOp(op, comma.right, b, allocator); - } - }, - else => {}, - } - - // "a op (b op c)" => "(a op b) op c" - // "a op (b op (c op d))" => "((a op b) op c) op d" - switch (b.data) { - .e_binary => |binary| { - if (binary.op == op) { - return joinWithLeftAssociativeOp( - op, - joinWithLeftAssociativeOp(op, a, binary.left, allocator), - binary.right, - allocator, - ); - } - }, - else => {}, - } - - // "a op b" => "a op b" - // "(a op b) op c" => "(a op b) op c" - return Expr.init(E.Binary, E.Binary{ .op = op, .left = a, .right = b }, a.loc); -} - -pub fn joinWithComma(a: Expr, b: Expr, _: std.mem.Allocator) Expr { - if (a.isMissing()) { - return b; - } - - if (b.isMissing()) { - return a; - } - - return Expr.init(E.Binary, E.Binary{ .op = .bin_comma, .left = a, .right = b }, a.loc); -} - -pub fn joinAllWithComma(all: []Expr, allocator: std.mem.Allocator) Expr { - bun.assert(all.len > 0); - switch (all.len) { - 1 => { - return all[0]; - }, - 2 => { - return Expr.joinWithComma(all[0], all[1], allocator); - }, - else => { - var expr = all[0]; - for (1..all.len) |i| { - expr = Expr.joinWithComma(expr, all[i], allocator); - } - return expr; - }, - } -} - -pub fn joinAllWithCommaCallback(all: []Expr, comptime Context: type, ctx: Context, comptime callback: (fn (ctx: anytype, expr: Expr) ?Expr), allocator: std.mem.Allocator) ?Expr { - switch (all.len) { - 0 => return null, - 1 => { - return callback(ctx, all[0]); - }, - 2 => { - const result = Expr.joinWithComma( - callback(ctx, all[0]) orelse Expr{ - .data = .{ .e_missing = .{} }, - .loc = all[0].loc, - }, - callback(ctx, all[1]) orelse Expr{ - .data = .{ .e_missing = .{} }, - .loc = all[1].loc, - }, - allocator, - ); - if (result.isMissing()) { - return null; - } - return result; - }, - else => { - var i: usize = 1; - var expr = callback(ctx, all[0]) orelse Expr{ - .data = .{ .e_missing = .{} }, - .loc = all[0].loc, - }; - - while (i < all.len) : (i += 1) { - expr = Expr.joinWithComma(expr, callback(ctx, all[i]) orelse Expr{ - .data = .{ .e_missing = .{} }, - .loc = all[i].loc, - }, allocator); - } - - if (expr.isMissing()) { - return null; - } - return expr; - }, - } -} - -pub fn jsonStringify(self: *const @This(), writer: anytype) !void { - return try writer.write(Serializable{ .type = std.meta.activeTag(self.data), .object = "expr", .value = self.data, .loc = self.loc }); -} - -pub fn extractNumericValuesInSafeRange(left: Expr.Data, right: Expr.Data) ?[2]f64 { - const l_value = left.extractNumericValue() orelse return null; - const r_value = right.extractNumericValue() orelse return null; - - // Check for NaN and return null if either value is NaN - if (std.math.isNan(l_value) or std.math.isNan(r_value)) { - return null; - } - - if (std.math.isInf(l_value) or std.math.isInf(r_value)) { - return .{ l_value, r_value }; - } - - if (l_value > bun.jsc.MAX_SAFE_INTEGER or r_value > bun.jsc.MAX_SAFE_INTEGER) { - return null; - } - if (l_value < bun.jsc.MIN_SAFE_INTEGER or r_value < bun.jsc.MIN_SAFE_INTEGER) { - return null; - } - - return .{ l_value, r_value }; -} - -pub fn extractNumericValues(left: Expr.Data, right: Expr.Data) ?[2]f64 { - return .{ - left.extractNumericValue() orelse return null, - right.extractNumericValue() orelse return null, - }; -} - -pub fn extractStringValues(left: Expr.Data, right: Expr.Data, allocator: std.mem.Allocator) ?[2]*E.String { - const l_string = left.extractStringValue() orelse return null; - const r_string = right.extractStringValue() orelse return null; - l_string.resolveRopeIfNeeded(allocator); - r_string.resolveRopeIfNeeded(allocator); - - if (l_string.isUTF8() != r_string.isUTF8()) return null; - - return .{ - l_string, - r_string, - }; -} - -pub var icount: usize = 0; - -// We don't need to dynamically allocate booleans -var true_bool = E.Boolean{ .value = true }; -var false_bool = E.Boolean{ .value = false }; -var bool_values = [_]*E.Boolean{ &false_bool, &true_bool }; - -/// When the lifetime of an Expr.Data's pointer must exist longer than reset() is called, use this function. -/// Be careful to free the memory (or use an allocator that does it for you) -/// Also, prefer Expr.init or Expr.alloc when possible. This will be slower. -pub fn allocate(allocator: std.mem.Allocator, comptime Type: type, st: Type, loc: logger.Loc) Expr { - icount += 1; - Data.Store.assert(); - - switch (Type) { - E.Array => { - return Expr{ - .loc = loc, - .data = Data{ - .e_array = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Class => { - return Expr{ - .loc = loc, - .data = Data{ - .e_class = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Unary => { - return Expr{ - .loc = loc, - .data = Data{ - .e_unary = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Binary => { - return Expr{ - .loc = loc, - .data = Data{ - .e_binary = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.This => { - return Expr{ - .loc = loc, - .data = Data{ - .e_this = st, - }, - }; - }, - E.Boolean => { - return Expr{ - .loc = loc, - .data = Data{ - .e_boolean = st, - }, - }; - }, - E.Super => { - return Expr{ - .loc = loc, - .data = Data{ - .e_super = st, - }, - }; - }, - E.Null => { - return Expr{ - .loc = loc, - .data = Data{ - .e_null = st, - }, - }; - }, - E.Undefined => { - return Expr{ - .loc = loc, - .data = Data{ - .e_undefined = st, - }, - }; - }, - E.New => { - return Expr{ - .loc = loc, - .data = Data{ - .e_new = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.NewTarget => { - return Expr{ - .loc = loc, - .data = Data{ - .e_new_target = st, - }, - }; - }, - E.Function => { - return Expr{ - .loc = loc, - .data = Data{ - .e_function = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.ImportMeta => { - return Expr{ - .loc = loc, - .data = Data{ - .e_import_meta = st, - }, - }; - }, - E.Call => { - return Expr{ - .loc = loc, - .data = Data{ - .e_call = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Dot => { - return Expr{ - .loc = loc, - .data = Data{ - .e_dot = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Index => { - return Expr{ - .loc = loc, - .data = Data{ - .e_index = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Arrow => { - return Expr{ - .loc = loc, - .data = Data{ - .e_arrow = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Identifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_identifier = E.Identifier{ - .ref = st.ref, - .must_keep_due_to_with_stmt = st.must_keep_due_to_with_stmt, - .can_be_removed_if_unused = st.can_be_removed_if_unused, - .call_can_be_unwrapped_if_unused = st.call_can_be_unwrapped_if_unused, - }, - }, - }; - }, - E.ImportIdentifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_import_identifier = .{ - .ref = st.ref, - .was_originally_identifier = st.was_originally_identifier, - }, - }, - }; - }, - E.CommonJSExportIdentifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_commonjs_export_identifier = .{ - .ref = st.ref, - }, - }, - }; - }, - - E.PrivateIdentifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_private_identifier = st, - }, - }; - }, - E.JSXElement => { - return Expr{ - .loc = loc, - .data = Data{ - .e_jsx_element = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Missing => { - return Expr{ .loc = loc, .data = Data{ .e_missing = E.Missing{} } }; - }, - E.Number => { - return Expr{ - .loc = loc, - .data = Data{ - .e_number = st, - }, - }; - }, - E.BigInt => { - return Expr{ - .loc = loc, - .data = Data{ - .e_big_int = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Object => { - return Expr{ - .loc = loc, - .data = Data{ - .e_object = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Spread => { - return Expr{ - .loc = loc, - .data = Data{ - .e_spread = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.String => { - if (comptime Environment.isDebug) { - // Sanity check: assert string is not a null ptr - if (st.data.len > 0 and st.isUTF8()) { - bun.assert(@intFromPtr(st.data.ptr) > 0); - } - } - return Expr{ - .loc = loc, - .data = Data{ - .e_string = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - - E.Template => { - return Expr{ - .loc = loc, - .data = Data{ - .e_template = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.RegExp => { - return Expr{ - .loc = loc, - .data = Data{ - .e_reg_exp = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Await => { - return Expr{ - .loc = loc, - .data = Data{ - .e_await = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.Yield => { - return Expr{ - .loc = loc, - .data = Data{ - .e_yield = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.If => { - return Expr{ - .loc = loc, - .data = Data{ - .e_if = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.RequireResolveString => { - return Expr{ - .loc = loc, - .data = Data{ - .e_require_resolve_string = st, - }, - }; - }, - E.Import => { - return Expr{ - .loc = loc, - .data = Data{ - .e_import = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st; - break :brk item; - }, - }, - }; - }, - E.RequireString => { - return Expr{ - .loc = loc, - .data = Data{ - .e_require_string = st, - }, - }; - }, - *E.String => { - return Expr{ - .loc = loc, - .data = Data{ - .e_string = brk: { - const item = allocator.create(Type) catch unreachable; - item.* = st.*; - break :brk item; - }, - }, - }; - }, - - else => { - @compileError("Invalid type passed to Expr.init: " ++ @typeName(Type)); - }, - } -} - -pub const Disabler = bun.DebugOnlyDisabler(@This()); - -pub fn init(comptime Type: type, st: Type, loc: logger.Loc) Expr { - icount += 1; - Data.Store.assert(); - - switch (Type) { - E.NameOfSymbol => { - return Expr{ - .loc = loc, - .data = Data{ - .e_name_of_symbol = Data.Store.append(E.NameOfSymbol, st), - }, - }; - }, - E.Array => { - return Expr{ - .loc = loc, - .data = Data{ - .e_array = Data.Store.append(Type, st), - }, - }; - }, - E.Class => { - return Expr{ - .loc = loc, - .data = Data{ - .e_class = Data.Store.append(Type, st), - }, - }; - }, - E.Unary => { - return Expr{ - .loc = loc, - .data = Data{ - .e_unary = Data.Store.append(Type, st), - }, - }; - }, - E.Binary => { - return Expr{ - .loc = loc, - .data = Data{ - .e_binary = Data.Store.append(Type, st), - }, - }; - }, - E.This => { - return Expr{ - .loc = loc, - .data = Data{ - .e_this = st, - }, - }; - }, - E.Boolean => { - return Expr{ - .loc = loc, - .data = Data{ - .e_boolean = st, - }, - }; - }, - E.Super => { - return Expr{ - .loc = loc, - .data = Data{ - .e_super = st, - }, - }; - }, - E.Null => { - return Expr{ - .loc = loc, - .data = Data{ - .e_null = st, - }, - }; - }, - E.Undefined => { - return Expr{ - .loc = loc, - .data = Data{ - .e_undefined = st, - }, - }; - }, - E.New => { - return Expr{ - .loc = loc, - .data = Data{ - .e_new = Data.Store.append(Type, st), - }, - }; - }, - E.NewTarget => { - return Expr{ - .loc = loc, - .data = Data{ - .e_new_target = st, - }, - }; - }, - E.Function => { - return Expr{ - .loc = loc, - .data = Data{ - .e_function = Data.Store.append(Type, st), - }, - }; - }, - E.ImportMeta => { - return Expr{ - .loc = loc, - .data = Data{ - .e_import_meta = st, - }, - }; - }, - E.Call => { - return Expr{ - .loc = loc, - .data = Data{ - .e_call = Data.Store.append(Type, st), - }, - }; - }, - E.Dot => { - return Expr{ - .loc = loc, - .data = Data{ - .e_dot = Data.Store.append(Type, st), - }, - }; - }, - E.Index => { - return Expr{ - .loc = loc, - .data = Data{ - .e_index = Data.Store.append(Type, st), - }, - }; - }, - E.Arrow => { - return Expr{ - .loc = loc, - .data = Data{ - .e_arrow = Data.Store.append(Type, st), - }, - }; - }, - E.Identifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_identifier = E.Identifier{ - .ref = st.ref, - .must_keep_due_to_with_stmt = st.must_keep_due_to_with_stmt, - .can_be_removed_if_unused = st.can_be_removed_if_unused, - .call_can_be_unwrapped_if_unused = st.call_can_be_unwrapped_if_unused, - }, - }, - }; - }, - E.ImportIdentifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_import_identifier = .{ - .ref = st.ref, - .was_originally_identifier = st.was_originally_identifier, - }, - }, - }; - }, - E.CommonJSExportIdentifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_commonjs_export_identifier = .{ - .ref = st.ref, - .base = st.base, - }, - }, - }; - }, - E.PrivateIdentifier => { - return Expr{ - .loc = loc, - .data = Data{ - .e_private_identifier = st, - }, - }; - }, - E.JSXElement => { - return Expr{ - .loc = loc, - .data = Data{ - .e_jsx_element = Data.Store.append(Type, st), - }, - }; - }, - E.Missing => { - return Expr{ .loc = loc, .data = Data{ .e_missing = E.Missing{} } }; - }, - E.Number => { - return Expr{ - .loc = loc, - .data = Data{ - .e_number = st, - }, - }; - }, - E.BigInt => { - return Expr{ - .loc = loc, - .data = Data{ - .e_big_int = Data.Store.append(Type, st), - }, - }; - }, - E.Object => { - return Expr{ - .loc = loc, - .data = Data{ - .e_object = Data.Store.append(Type, st), - }, - }; - }, - E.Spread => { - return Expr{ - .loc = loc, - .data = Data{ - .e_spread = Data.Store.append(Type, st), - }, - }; - }, - E.String => { - if (comptime Environment.isDebug) { - // Sanity check: assert string is not a null ptr - if (st.data.len > 0 and st.isUTF8()) { - bun.assert(@intFromPtr(st.data.ptr) > 0); - } - } - return Expr{ - .loc = loc, - .data = Data{ - .e_string = Data.Store.append(Type, st), - }, - }; - }, - - E.Template => { - return Expr{ - .loc = loc, - .data = Data{ - .e_template = Data.Store.append(Type, st), - }, - }; - }, - E.RegExp => { - return Expr{ - .loc = loc, - .data = Data{ - .e_reg_exp = Data.Store.append(Type, st), - }, - }; - }, - E.Await => { - return Expr{ - .loc = loc, - .data = Data{ - .e_await = Data.Store.append(Type, st), - }, - }; - }, - E.Yield => { - return Expr{ - .loc = loc, - .data = Data{ - .e_yield = Data.Store.append(Type, st), - }, - }; - }, - E.If => { - return Expr{ - .loc = loc, - .data = Data{ - .e_if = Data.Store.append(Type, st), - }, - }; - }, - E.RequireResolveString => { - return Expr{ - .loc = loc, - .data = Data{ - .e_require_resolve_string = st, - }, - }; - }, - E.Import => { - return Expr{ - .loc = loc, - .data = Data{ - .e_import = Data.Store.append(Type, st), - }, - }; - }, - E.RequireString => { - return Expr{ - .loc = loc, - .data = Data{ - .e_require_string = st, - }, - }; - }, - *E.String => { - return Expr{ - .loc = loc, - .data = Data{ - .e_string = Data.Store.append(@TypeOf(st.*), st.*), - }, - }; - }, - E.InlinedEnum => return .{ .loc = loc, .data = .{ - .e_inlined_enum = Data.Store.append(@TypeOf(st), st), - } }, - - else => { - @compileError("Invalid type passed to Expr.init: " ++ @typeName(Type)); - }, - } -} - -/// If this returns true, then calling this expression captures the target of -/// the property access as "this" when calling the function in the property. -pub inline fn isPropertyAccess(this: *const Expr) bool { - return this.hasValueForThisInCall(); -} - -pub inline fn isPrimitiveLiteral(this: *const Expr) bool { - return @as(Tag, this.data).isPrimitiveLiteral(); -} - -pub inline fn isRef(this: *const Expr, ref: Ref) bool { - return switch (this.data) { - .e_import_identifier => |import_identifier| import_identifier.ref.eql(ref), - .e_identifier => |ident| ident.ref.eql(ref), - else => false, - }; -} - -pub const Tag = enum { - e_array, - e_unary, - e_binary, - e_class, - e_new, - e_function, - e_call, - e_dot, - e_index, - e_arrow, - e_jsx_element, - e_object, - e_spread, - e_template, - e_reg_exp, - e_await, - e_yield, - e_if, - e_import, - e_identifier, - e_import_identifier, - e_private_identifier, - e_commonjs_export_identifier, - e_boolean, - /// Like e_boolean, but produced by `feature()` from `bun:bundle`. - /// This tag ensures feature() can only be used directly in conditional - /// contexts (if statements, ternaries). Invalid usage is caught during - /// the visit phase when this expression appears outside a branch condition. - e_branch_boolean, - e_number, - e_big_int, - e_string, - e_require_string, - e_require_resolve_string, - e_require_call_target, - e_require_resolve_call_target, - e_missing, - e_this, - e_super, - e_null, - e_undefined, - e_new_target, - e_import_meta, - e_import_meta_main, - e_require_main, - e_special, - e_inlined_enum, - e_name_of_symbol, - - // object, regex and array may have had side effects - pub fn isPrimitiveLiteral(tag: Tag) bool { - return switch (tag) { - .e_null, .e_undefined, .e_string, .e_boolean, .e_branch_boolean, .e_number, .e_big_int => true, - else => false, - }; - } - - pub fn typeof(tag: Tag) ?string { - return switch (tag) { - .e_array, .e_object, .e_null, .e_reg_exp => "object", - .e_undefined => "undefined", - .e_boolean, .e_branch_boolean => "boolean", - .e_number => "number", - .e_big_int => "bigint", - .e_string => "string", - .e_class, .e_function, .e_arrow => "function", - else => null, - }; - } - - pub fn format(tag: Tag, writer: *std.Io.Writer) !void { - try switch (tag) { - .e_string => writer.writeAll("string"), - .e_array => writer.writeAll("array"), - .e_unary => writer.writeAll("unary"), - .e_binary => writer.writeAll("binary"), - .e_boolean, .e_branch_boolean => writer.writeAll("boolean"), - .e_super => writer.writeAll("super"), - .e_null => writer.writeAll("null"), - .e_undefined => writer.writeAll("undefined"), - .e_new => writer.writeAll("new"), - .e_function => writer.writeAll("function"), - .e_new_target => writer.writeAll("new target"), - .e_import_meta => writer.writeAll("import.meta"), - .e_call => writer.writeAll("call"), - .e_dot => writer.writeAll("dot"), - .e_index => writer.writeAll("index"), - .e_arrow => writer.writeAll("arrow"), - .e_identifier => writer.writeAll("identifier"), - .e_import_identifier => writer.writeAll("import identifier"), - .e_private_identifier => writer.writeAll("#privateIdentifier"), - .e_jsx_element => writer.writeAll(""), - .e_missing => writer.writeAll(""), - .e_number => writer.writeAll("number"), - .e_big_int => writer.writeAll("BigInt"), - .e_object => writer.writeAll("object"), - .e_spread => writer.writeAll("..."), - .e_template => writer.writeAll("template"), - .e_reg_exp => writer.writeAll("regexp"), - .e_await => writer.writeAll("await"), - .e_yield => writer.writeAll("yield"), - .e_if => writer.writeAll("if"), - .e_require_resolve_string => writer.writeAll("require_or_require_resolve"), - .e_import => writer.writeAll("import"), - .e_this => writer.writeAll("this"), - .e_class => writer.writeAll("class"), - .e_require_string => writer.writeAll("require"), - else => writer.writeAll(@tagName(tag)), - }; - } - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - - pub fn isArray(self: Tag) bool { - switch (self) { - .e_array => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isUnary(self: Tag) bool { - switch (self) { - .e_unary => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isBinary(self: Tag) bool { - switch (self) { - .e_binary => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isThis(self: Tag) bool { - switch (self) { - .e_this => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isClass(self: Tag) bool { - switch (self) { - .e_class => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isBoolean(self: Tag) bool { - return self == .e_boolean or self == .e_branch_boolean; - } - pub fn isSuper(self: Tag) bool { - switch (self) { - .e_super => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isNull(self: Tag) bool { - switch (self) { - .e_null => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isUndefined(self: Tag) bool { - switch (self) { - .e_undefined => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isNew(self: Tag) bool { - switch (self) { - .e_new => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isNewTarget(self: Tag) bool { - switch (self) { - .e_new_target => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isFunction(self: Tag) bool { - switch (self) { - .e_function => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isImportMeta(self: Tag) bool { - switch (self) { - .e_import_meta => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isCall(self: Tag) bool { - switch (self) { - .e_call => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isDot(self: Tag) bool { - switch (self) { - .e_dot => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isIndex(self: Tag) bool { - switch (self) { - .e_index => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isArrow(self: Tag) bool { - switch (self) { - .e_arrow => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isIdentifier(self: Tag) bool { - switch (self) { - .e_identifier => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isImportIdentifier(self: Tag) bool { - switch (self) { - .e_import_identifier => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isPrivateIdentifier(self: Tag) bool { - switch (self) { - .e_private_identifier => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isJsxElement(self: Tag) bool { - switch (self) { - .e_jsx_element => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isMissing(self: Tag) bool { - switch (self) { - .e_missing => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isNumber(self: Tag) bool { - switch (self) { - .e_number => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isBigInt(self: Tag) bool { - switch (self) { - .e_big_int => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isObject(self: Tag) bool { - switch (self) { - .e_object => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isSpread(self: Tag) bool { - switch (self) { - .e_spread => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isString(self: Tag) bool { - switch (self) { - .e_string => { - return true; - }, - else => { - return false; - }, - } - } - - pub fn isTemplate(self: Tag) bool { - switch (self) { - .e_template => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isRegExp(self: Tag) bool { - switch (self) { - .e_reg_exp => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isAwait(self: Tag) bool { - switch (self) { - .e_await => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isYield(self: Tag) bool { - switch (self) { - .e_yield => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isIf(self: Tag) bool { - switch (self) { - .e_if => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isRequireResolveString(self: Tag) bool { - switch (self) { - .e_require_resolve_string => { - return true; - }, - else => { - return false; - }, - } - } - pub fn isImport(self: Tag) bool { - switch (self) { - .e_import => { - return true; - }, - else => { - return false; - }, - } - } -}; - -pub fn isBoolean(a: *const Expr) bool { - return switch (a.data) { - .e_boolean, .e_branch_boolean => true, - .e_if => |ex| ex.yes.isBoolean() and ex.no.isBoolean(), - .e_unary => |ex| ex.op == .un_not or ex.op == .un_delete, - .e_binary => |ex| switch (ex.op) { - .bin_strict_eq, .bin_strict_ne, .bin_loose_eq, .bin_loose_ne, .bin_lt, .bin_gt, .bin_le, .bin_ge, .bin_instanceof, .bin_in => true, - .bin_logical_or => ex.left.isBoolean() and ex.right.isBoolean(), - .bin_logical_and => ex.left.isBoolean() and ex.right.isBoolean(), - else => false, - }, - else => false, - }; -} - -pub fn assign(a: Expr, b: Expr) Expr { - return init(E.Binary, E.Binary{ - .op = .bin_assign, - .left = a, - .right = b, - }, a.loc); -} -pub inline fn at(expr: *const Expr, comptime Type: type, t: Type, _: std.mem.Allocator) Expr { - return init(Type, t, expr.loc); -} - -// Wraps the provided expression in the "!" prefix operator. The expression -// will potentially be simplified to avoid generating unnecessary extra "!" -// operators. For example, calling this with "!!x" will return "!x" instead -// of returning "!!!x". -pub fn not(expr: *const Expr, allocator: std.mem.Allocator) Expr { - return expr.maybeSimplifyNot(allocator) orelse - Expr.init( - E.Unary, - E.Unary{ - .op = .un_not, - .value = expr.*, - }, - expr.loc, - ); -} - -pub inline fn hasValueForThisInCall(expr: *const Expr) bool { - return switch (expr.data) { - .e_dot, .e_index => true, - else => false, - }; -} - -/// The given "expr" argument should be the operand of a "!" prefix operator -/// (i.e. the "x" in "!x"). This returns a simplified expression for the -/// whole operator (i.e. the "!x") if it can be simplified, or false if not. -/// It's separate from "Not()" above to avoid allocation on failure in case -/// that is undesired. -pub fn maybeSimplifyNot(expr: *const Expr, allocator: std.mem.Allocator) ?Expr { - switch (expr.data) { - .e_null, .e_undefined => { - return expr.at(E.Boolean, E.Boolean{ .value = true }, allocator); - }, - .e_boolean, .e_branch_boolean => |b| { - return expr.at(E.Boolean, E.Boolean{ .value = !b.value }, allocator); - }, - .e_number => |n| { - return expr.at(E.Boolean, E.Boolean{ .value = (n.value == 0 or std.math.isNan(n.value)) }, allocator); - }, - .e_big_int => |b| { - return expr.at(E.Boolean, E.Boolean{ .value = strings.eqlComptime(b.value, "0") }, allocator); - }, - .e_function, - .e_arrow, - .e_reg_exp, - => { - return expr.at(E.Boolean, E.Boolean{ .value = false }, allocator); - }, - // "!!!a" => "!a" - .e_unary => |un| { - if (un.op == Op.Code.un_not and un.value.knownPrimitive() == .boolean) { - return un.value; - } - }, - .e_binary => |ex| { - // TODO: evaluate whether or not it is safe to do this mutation since it's modifying in-place. - // Make sure that these transformations are all safe for special values. - // For example, "!(a < b)" is not the same as "a >= b" if a and/or b are - // NaN (or undefined, or null, or possibly other problem cases too). - switch (ex.op) { - Op.Code.bin_loose_eq => { - // "!(a == b)" => "a != b" - ex.op = .bin_loose_ne; - return expr.*; - }, - Op.Code.bin_loose_ne => { - // "!(a != b)" => "a == b" - ex.op = .bin_loose_eq; - return expr.*; - }, - Op.Code.bin_strict_eq => { - // "!(a === b)" => "a !== b" - ex.op = .bin_strict_ne; - return expr.*; - }, - Op.Code.bin_strict_ne => { - // "!(a !== b)" => "a === b" - ex.op = .bin_strict_eq; - return expr.*; - }, - Op.Code.bin_comma => { - // "!(a, b)" => "a, !b" - ex.right = ex.right.not(allocator); - return expr.*; - }, - else => {}, - } - }, - .e_inlined_enum => |inlined| { - return inlined.value.maybeSimplifyNot(allocator); - }, - - else => {}, - } - - return null; -} - -pub fn toStringExprWithoutSideEffects(expr: *const Expr, allocator: std.mem.Allocator) ?Expr { - const unwrapped = expr.unwrapInlined(); - const slice = switch (unwrapped.data) { - .e_null => "null", - .e_string => return expr.*, - .e_undefined => "undefined", - .e_boolean, .e_branch_boolean => |data| if (data.value) "true" else "false", - .e_big_int => |bigint| bigint.value, - .e_number => |num| if (num.toString(allocator)) |str| - str - else - null, - .e_reg_exp => |regexp| regexp.value, - .e_dot => |dot| @as(?[]const u8, brk: { - // This is dumb but some JavaScript obfuscators use this to generate string literals - if (bun.strings.eqlComptime(dot.name, "constructor")) { - break :brk switch (dot.target.data) { - .e_string => "function String() { [native code] }", - .e_reg_exp => "function RegExp() { [native code] }", - else => null, - }; - } - break :brk null; - }), - else => null, - }; - return if (slice) |s| Expr.init(E.String, E.String.init(s), expr.loc) else null; -} - -pub fn isOptionalChain(self: *const @This()) bool { - return switch (self.data) { - .e_dot => self.data.e_dot.optional_chain != null, - .e_index => self.data.e_index.optional_chain != null, - .e_call => self.data.e_call.optional_chain != null, - else => false, - }; -} - -pub inline fn knownPrimitive(self: *const @This()) PrimitiveType { - return self.data.knownPrimitive(); -} - -pub const PrimitiveType = enum { - unknown, - mixed, - null, - undefined, - boolean, - number, - string, - bigint, - - pub const static = std.enums.EnumSet(PrimitiveType).init(.{ - .mixed = true, - .null = true, - .undefined = true, - .boolean = true, - .number = true, - .string = true, - // for our purposes, bigint is dynamic - // it is technically static though - // .@"bigint" = true, - }); - - pub inline fn isStatic(this: PrimitiveType) bool { - return static.contains(this); - } - - pub fn merge(left_known: PrimitiveType, right_known: PrimitiveType) PrimitiveType { - if (right_known == .unknown or left_known == .unknown) - return .unknown; - - return if (left_known == right_known) - left_known - else - .mixed; - } -}; - -pub const Data = union(Tag) { - e_array: *E.Array, - e_unary: *E.Unary, - e_binary: *E.Binary, - e_class: *E.Class, - - e_new: *E.New, - e_function: *E.Function, - e_call: *E.Call, - e_dot: *E.Dot, - e_index: *E.Index, - e_arrow: *E.Arrow, - - e_jsx_element: *E.JSXElement, - e_object: *E.Object, - e_spread: *E.Spread, - e_template: *E.Template, - e_reg_exp: *E.RegExp, - e_await: *E.Await, - e_yield: *E.Yield, - e_if: *E.If, - e_import: *E.Import, - - e_identifier: E.Identifier, - e_import_identifier: E.ImportIdentifier, - e_private_identifier: E.PrivateIdentifier, - e_commonjs_export_identifier: E.CommonJSExportIdentifier, - - e_boolean: E.Boolean, - e_branch_boolean: E.Boolean, - e_number: E.Number, - e_big_int: *E.BigInt, - e_string: *E.String, - - e_require_string: E.RequireString, - e_require_resolve_string: E.RequireResolveString, - e_require_call_target, - e_require_resolve_call_target, - - e_missing: E.Missing, - e_this: E.This, - e_super: E.Super, - e_null: E.Null, - e_undefined: E.Undefined, - e_new_target: E.NewTarget, - e_import_meta: E.ImportMeta, - - e_import_meta_main: E.ImportMetaMain, - e_require_main, - - /// Covers some exotic AST node types under one namespace, since the - /// places this is found it all follows similar handling. - e_special: E.Special, - - e_inlined_enum: *E.InlinedEnum, - - e_name_of_symbol: *E.NameOfSymbol, - - comptime { - bun.assert_eql(@sizeOf(Data), 24); // Do not increase the size of Expr - } - - pub fn as(data: Data, comptime tag: Tag) ?@FieldType(Data, @tagName(tag)) { - return if (data == tag) @field(data, @tagName(tag)) else null; - } - - pub fn clone(this: Expr.Data, allocator: std.mem.Allocator) !Data { - return switch (this) { - .e_array => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_array))); - item.* = el.*; - return .{ .e_array = item }; - }, - .e_unary => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_unary))); - item.* = el.*; - return .{ .e_unary = item }; - }, - .e_binary => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_binary))); - item.* = el.*; - return .{ .e_binary = item }; - }, - .e_class => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_class))); - item.* = el.*; - return .{ .e_class = item }; - }, - .e_new => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_new))); - item.* = el.*; - return .{ .e_new = item }; - }, - .e_function => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_function))); - item.* = el.*; - return .{ .e_function = item }; - }, - .e_call => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_call))); - item.* = el.*; - return .{ .e_call = item }; - }, - .e_dot => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_dot))); - item.* = el.*; - return .{ .e_dot = item }; - }, - .e_index => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_index))); - item.* = el.*; - return .{ .e_index = item }; - }, - .e_arrow => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_arrow))); - item.* = el.*; - return .{ .e_arrow = item }; - }, - .e_jsx_element => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_jsx_element))); - item.* = el.*; - return .{ .e_jsx_element = item }; - }, - .e_object => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_object))); - item.* = el.*; - return .{ .e_object = item }; - }, - .e_spread => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_spread))); - item.* = el.*; - return .{ .e_spread = item }; - }, - .e_template => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_template))); - item.* = el.*; - return .{ .e_template = item }; - }, - .e_reg_exp => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_reg_exp))); - item.* = el.*; - return .{ .e_reg_exp = item }; - }, - .e_await => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_await))); - item.* = el.*; - return .{ .e_await = item }; - }, - .e_yield => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_yield))); - item.* = el.*; - return .{ .e_yield = item }; - }, - .e_if => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_if))); - item.* = el.*; - return .{ .e_if = item }; - }, - .e_import => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_import))); - item.* = el.*; - return .{ .e_import = item }; - }, - .e_big_int => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_big_int))); - item.* = el.*; - return .{ .e_big_int = item }; - }, - .e_string => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_string))); - item.* = el.*; - return .{ .e_string = item }; - }, - .e_inlined_enum => |el| { - const item = try allocator.create(std.meta.Child(@TypeOf(this.e_inlined_enum))); - item.* = el.*; - return .{ .e_inlined_enum = item }; - }, - else => this, - }; - } - - pub fn deepClone(this: Expr.Data, allocator: std.mem.Allocator) !Data { - return switch (this) { - .e_array => |el| { - const items = try el.items.deepClone(allocator); - const item = bun.create(allocator, E.Array, .{ - .items = items, - .comma_after_spread = el.comma_after_spread, - .was_originally_macro = el.was_originally_macro, - .is_single_line = el.is_single_line, - .is_parenthesized = el.is_parenthesized, - .close_bracket_loc = el.close_bracket_loc, - }); - return .{ .e_array = item }; - }, - .e_unary => |el| { - const item = bun.create(allocator, E.Unary, .{ - .op = el.op, - .value = try el.value.deepClone(allocator), - .flags = el.flags, - }); - return .{ .e_unary = item }; - }, - .e_binary => |el| { - const item = bun.create(allocator, E.Binary, .{ - .op = el.op, - .left = try el.left.deepClone(allocator), - .right = try el.right.deepClone(allocator), - }); - return .{ .e_binary = item }; - }, - .e_class => |el| { - const properties = try allocator.alloc(G.Property, el.properties.len); - for (el.properties, 0..) |prop, i| { - properties[i] = try prop.deepClone(allocator); - } - - const item = bun.create(allocator, E.Class, .{ - .class_keyword = el.class_keyword, - .ts_decorators = try el.ts_decorators.deepClone(allocator), - .class_name = el.class_name, - .extends = if (el.extends) |e| try e.deepClone(allocator) else null, - .body_loc = el.body_loc, - .close_brace_loc = el.close_brace_loc, - .properties = properties, - .has_decorators = el.has_decorators, - }); - return .{ .e_class = item }; - }, - .e_new => |el| { - const item = bun.create(allocator, E.New, .{ - .target = try el.target.deepClone(allocator), - .args = try el.args.deepClone(allocator), - .can_be_unwrapped_if_unused = el.can_be_unwrapped_if_unused, - .close_parens_loc = el.close_parens_loc, - }); - - return .{ .e_new = item }; - }, - .e_function => |el| { - const item = bun.create(allocator, E.Function, .{ - .func = try el.func.deepClone(allocator), - }); - return .{ .e_function = item }; - }, - .e_call => |el| { - const item = bun.create(allocator, E.Call, .{ - .target = try el.target.deepClone(allocator), - .args = try el.args.deepClone(allocator), - .optional_chain = el.optional_chain, - .is_direct_eval = el.is_direct_eval, - .close_paren_loc = el.close_paren_loc, - .can_be_unwrapped_if_unused = el.can_be_unwrapped_if_unused, - .was_jsx_element = el.was_jsx_element, - }); - return .{ .e_call = item }; - }, - .e_dot => |el| { - const item = bun.create(allocator, E.Dot, .{ - .target = try el.target.deepClone(allocator), - .name = el.name, - .name_loc = el.name_loc, - .optional_chain = el.optional_chain, - .can_be_removed_if_unused = el.can_be_removed_if_unused, - .call_can_be_unwrapped_if_unused = el.call_can_be_unwrapped_if_unused, - }); - return .{ .e_dot = item }; - }, - .e_index => |el| { - const item = bun.create(allocator, E.Index, .{ - .target = try el.target.deepClone(allocator), - .index = try el.index.deepClone(allocator), - .optional_chain = el.optional_chain, - }); - return .{ .e_index = item }; - }, - .e_arrow => |el| { - const args = try allocator.alloc(G.Arg, el.args.len); - for (0..args.len) |i| { - args[i] = try el.args[i].deepClone(allocator); - } - const item = bun.create(allocator, E.Arrow, .{ - .args = args, - .body = el.body, - .is_async = el.is_async, - .has_rest_arg = el.has_rest_arg, - .prefer_expr = el.prefer_expr, - }); - - return .{ .e_arrow = item }; - }, - .e_jsx_element => |el| { - const item = bun.create(allocator, E.JSXElement, .{ - .tag = if (el.tag) |tag| try tag.deepClone(allocator) else null, - .properties = try el.properties.deepClone(allocator), - .children = try el.children.deepClone(allocator), - .key_prop_index = el.key_prop_index, - .flags = el.flags, - .close_tag_loc = el.close_tag_loc, - }); - return .{ .e_jsx_element = item }; - }, - .e_object => |el| { - const item = bun.create(allocator, E.Object, .{ - .properties = try el.properties.deepClone(allocator), - .comma_after_spread = el.comma_after_spread, - .is_single_line = el.is_single_line, - .is_parenthesized = el.is_parenthesized, - .was_originally_macro = el.was_originally_macro, - .close_brace_loc = el.close_brace_loc, - }); - return .{ .e_object = item }; - }, - .e_spread => |el| { - const item = bun.create(allocator, E.Spread, .{ - .value = try el.value.deepClone(allocator), - }); - return .{ .e_spread = item }; - }, - .e_template => |el| { - const item = bun.create(allocator, E.Template, .{ - .tag = if (el.tag) |tag| try tag.deepClone(allocator) else null, - .parts = el.parts, - .head = el.head, - }); - return .{ .e_template = item }; - }, - .e_reg_exp => |el| { - const item = bun.create(allocator, E.RegExp, .{ - .value = el.value, - .flags_offset = el.flags_offset, - }); - return .{ .e_reg_exp = item }; - }, - .e_await => |el| { - const item = bun.create(allocator, E.Await, .{ - .value = try el.value.deepClone(allocator), - }); - return .{ .e_await = item }; - }, - .e_yield => |el| { - const item = bun.create(allocator, E.Yield, .{ - .value = if (el.value) |value| try value.deepClone(allocator) else null, - .is_star = el.is_star, - }); - return .{ .e_yield = item }; - }, - .e_if => |el| { - const item = bun.create(allocator, E.If, .{ - .test_ = try el.test_.deepClone(allocator), - .yes = try el.yes.deepClone(allocator), - .no = try el.no.deepClone(allocator), - }); - return .{ .e_if = item }; - }, - .e_import => |el| { - const item = bun.create(allocator, E.Import, .{ - .expr = try el.expr.deepClone(allocator), - .options = try el.options.deepClone(allocator), - .import_record_index = el.import_record_index, - }); - return .{ .e_import = item }; - }, - .e_big_int => |el| { - const item = bun.create(allocator, E.BigInt, .{ - .value = el.value, - }); - return .{ .e_big_int = item }; - }, - .e_string => |el| { - const item = bun.create(allocator, E.String, .{ - .data = el.data, - .prefer_template = el.prefer_template, - .next = el.next, - .end = el.end, - .rope_len = el.rope_len, - .is_utf16 = el.is_utf16, - }); - return .{ .e_string = item }; - }, - .e_inlined_enum => |el| { - const item = bun.create(allocator, E.InlinedEnum, .{ - .value = el.value, - .comment = el.comment, - }); - return .{ .e_inlined_enum = item }; - }, - else => this, - }; - } - - /// `hasher` should be something with 'pub fn update([]const u8) void'; - /// symbol table is passed to serialize `Ref` as an identifier names instead of a nondeterministic numbers - pub fn writeToHasher(this: Expr.Data, hasher: anytype, symbol_table: anytype) void { - writeAnyToHasher(hasher, std.meta.activeTag(this)); - switch (this) { - .e_name_of_symbol => |e| { - const symbol = e.ref.getSymbol(symbol_table); - hasher.update(symbol.original_name); - }, - .e_array => |e| { - writeAnyToHasher(hasher, .{ - e.is_single_line, - e.is_parenthesized, - e.was_originally_macro, - e.items.len, - }); - for (e.items.slice()) |item| { - item.data.writeToHasher(hasher, symbol_table); - } - }, - .e_unary => |e| { - writeAnyToHasher(hasher, @as(u8, @bitCast(e.flags))); - writeAnyToHasher(hasher, .{e.op}); - e.value.data.writeToHasher(hasher, symbol_table); - }, - .e_binary => |e| { - writeAnyToHasher(hasher, .{e.op}); - e.left.data.writeToHasher(hasher, symbol_table); - e.right.data.writeToHasher(hasher, symbol_table); - }, - .e_class => {}, - inline .e_new, .e_call => {}, - .e_function => {}, - .e_dot => |e| { - writeAnyToHasher(hasher, .{ e.optional_chain, e.name.len }); - e.target.data.writeToHasher(hasher, symbol_table); - hasher.update(e.name); - }, - .e_index => |e| { - writeAnyToHasher(hasher, .{e.optional_chain}); - e.target.data.writeToHasher(hasher, symbol_table); - e.index.data.writeToHasher(hasher, symbol_table); - }, - .e_arrow => {}, - .e_jsx_element => |e| { - _ = e; // autofix - }, - .e_object => |e| { - _ = e; // autofix - }, - inline .e_spread, .e_await => |e| { - e.value.data.writeToHasher(hasher, symbol_table); - }, - .e_yield => |e| { - writeAnyToHasher(hasher, .{ e.is_star, e.value }); - if (e.value) |value| - value.data.writeToHasher(hasher, symbol_table); - }, - .e_template => |e| { - _ = e; // autofix - }, - .e_if => |e| { - _ = e; // autofix - }, - .e_import => |e| { - _ = e; // autofix - - }, - inline .e_identifier, - .e_import_identifier, - .e_private_identifier, - .e_commonjs_export_identifier, - => |e| { - const symbol = e.ref.getSymbol(symbol_table); - hasher.update(symbol.original_name); - }, - inline .e_boolean, .e_branch_boolean, .e_number => |e| { - writeAnyToHasher(hasher, e.value); - }, - inline .e_big_int, .e_reg_exp => |e| { - hasher.update(e.value); - }, - - .e_string => |e| { - var next: ?*E.String = e; - if (next) |current| { - if (current.isUTF8()) { - hasher.update(current.data); - } else { - hasher.update(bun.reinterpretSlice(u8, current.slice16())); - } - next = current.next; - hasher.update("\x00"); - } - }, - inline .e_require_string, .e_require_resolve_string => |e| { - writeAnyToHasher(hasher, e.import_record_index); // preferably, i'd like to write the filepath - }, - - .e_import_meta_main => |e| { - writeAnyToHasher(hasher, e.inverted); - }, - .e_inlined_enum => |e| { - // pretend there is no comment - e.value.data.writeToHasher(hasher, symbol_table); - }, - - // no data - .e_require_call_target, - .e_require_resolve_call_target, - .e_missing, - .e_this, - .e_super, - .e_null, - .e_undefined, - .e_new_target, - .e_require_main, - .e_import_meta, - .e_special, - => {}, - } - } - - /// "const values" here refers to expressions that can participate in constant - /// inlining, as they have no side effects on instantiation, and there would be - /// no observable difference if duplicated. This is a subset of canBeMoved() - pub fn canBeConstValue(this: Expr.Data) bool { - return switch (this) { - .e_number, - .e_boolean, - .e_branch_boolean, - .e_null, - .e_undefined, - .e_inlined_enum, - => true, - .e_string => |str| str.next == null, - .e_array => |array| array.was_originally_macro, - .e_object => |object| object.was_originally_macro, - else => false, - }; - } - - /// Expressions that can be moved are those that do not have side - /// effects on their own. This is used to determine what can be moved - /// outside of a module wrapper (__esm/__commonJS). - pub fn canBeMoved(data: Expr.Data) bool { - return switch (data) { - // TODO: identifiers can be removed if unused, however code that - // moves expressions around sometimes does so incorrectly when - // doing destructures. test case: https://github.com/oven-sh/bun/issues/14027 - // .e_identifier => |id| id.can_be_removed_if_unused, - - .e_class => |class| class.canBeMoved(), - - .e_arrow, - .e_function, - - .e_number, - .e_boolean, - .e_branch_boolean, - .e_null, - .e_undefined, - // .e_reg_exp, - .e_big_int, - .e_string, - .e_inlined_enum, - .e_import_meta, - => true, - - .e_template => |template| template.tag == null and template.parts.len == 0, - - .e_array => |array| array.was_originally_macro, - .e_object => |object| object.was_originally_macro, - - // TODO: experiment with allowing some e_binary, e_unary, e_if as movable - - else => false, - }; - } - - pub fn isSafeToString(data: Expr.Data) bool { - return switch (data) { - // rope strings can throw when toString is called. - .e_string => |str| str.next == null, - - .e_number, .e_boolean, .e_branch_boolean, .e_undefined, .e_null => true, - // BigInt is deliberately excluded as a large enough BigInt could throw an out of memory error. - // - - else => false, - }; - } - - pub fn knownPrimitive(data: Expr.Data) PrimitiveType { - return switch (data) { - .e_big_int => .bigint, - .e_boolean, .e_branch_boolean => .boolean, - .e_null => .null, - .e_number => .number, - .e_string => .string, - .e_undefined => .undefined, - .e_template => if (data.e_template.tag == null) PrimitiveType.string else PrimitiveType.unknown, - .e_if => mergeKnownPrimitive(data.e_if.yes.data, data.e_if.no.data), - .e_binary => |binary| brk: { - switch (binary.op) { - .bin_strict_eq, - .bin_strict_ne, - .bin_loose_eq, - .bin_loose_ne, - .bin_lt, - .bin_gt, - .bin_le, - .bin_ge, - .bin_instanceof, - .bin_in, - => break :brk PrimitiveType.boolean, - .bin_logical_or, .bin_logical_and => break :brk binary.left.data.mergeKnownPrimitive(binary.right.data), - - .bin_nullish_coalescing => { - const left = binary.left.data.knownPrimitive(); - const right = binary.right.data.knownPrimitive(); - if (left == .null or left == .undefined) - break :brk right; - - if (left != .unknown) { - if (left != .mixed) - break :brk left; // Definitely not null or undefined - - if (right != .unknown) - break :brk PrimitiveType.mixed; // Definitely some kind of primitive - } - }, - - .bin_add => { - const left = binary.left.data.knownPrimitive(); - const right = binary.right.data.knownPrimitive(); - - if (left == .string or right == .string) - break :brk PrimitiveType.string; - - if (left == .bigint or right == .bigint) - break :brk PrimitiveType.bigint; - - if (switch (left) { - .unknown, .mixed, .bigint => false, - else => true, - } and switch (right) { - .unknown, .mixed, .bigint => false, - else => true, - }) - break :brk PrimitiveType.number; - - break :brk PrimitiveType.mixed; // Can be number or bigint or string (or an exception) - }, - - .bin_sub, - .bin_sub_assign, - .bin_mul, - .bin_mul_assign, - .bin_div, - .bin_div_assign, - .bin_rem, - .bin_rem_assign, - .bin_pow, - .bin_pow_assign, - .bin_bitwise_and, - .bin_bitwise_and_assign, - .bin_bitwise_or, - .bin_bitwise_or_assign, - .bin_bitwise_xor, - .bin_bitwise_xor_assign, - .bin_shl, - .bin_shl_assign, - .bin_shr, - .bin_shr_assign, - .bin_u_shr, - .bin_u_shr_assign, - => break :brk PrimitiveType.mixed, // Can be number or bigint (or an exception) - - .bin_assign, - .bin_comma, - => break :brk binary.right.data.knownPrimitive(), - - else => {}, - } - - break :brk PrimitiveType.unknown; - }, - - .e_unary => switch (data.e_unary.op) { - .un_void => PrimitiveType.undefined, - .un_typeof => PrimitiveType.string, - .un_not, .un_delete => PrimitiveType.boolean, - .un_pos => PrimitiveType.number, // Cannot be bigint because that throws an exception - .un_neg, .un_cpl => switch (data.e_unary.value.data.knownPrimitive()) { - .bigint => PrimitiveType.bigint, - .unknown, .mixed => PrimitiveType.mixed, - else => PrimitiveType.number, // Can be number or bigint - }, - .un_pre_dec, .un_pre_inc, .un_post_dec, .un_post_inc => PrimitiveType.mixed, // Can be number or bigint - - else => PrimitiveType.unknown, - }, - - .e_inlined_enum => |inlined| inlined.value.data.knownPrimitive(), - - else => PrimitiveType.unknown, - }; - } - - pub fn mergeKnownPrimitive(lhs: Expr.Data, rhs: Expr.Data) PrimitiveType { - return lhs.knownPrimitive().merge(rhs.knownPrimitive()); - } - - /// Returns true if the result of the "typeof" operator on this expression is - /// statically determined and this expression has no side effects (i.e. can be - /// removed without consequence). - pub inline fn toTypeof(data: Expr.Data) ?string { - return @as(Expr.Tag, data).typeof(); - } - - pub fn toNumber(data: Expr.Data) ?f64 { - return switch (data) { - .e_null => 0, - .e_undefined => std.math.nan(f64), - .e_string => |str| { - if (str.next != null) return null; - if (!str.isUTF8()) return null; - - // +'1' => 1 - return stringToEquivalentNumberValue(str.slice8()); - }, - .e_boolean, .e_branch_boolean => |b| @as(f64, if (b.value) 1.0 else 0.0), - .e_number => data.e_number.value, - .e_inlined_enum => |inlined| switch (inlined.value.data) { - .e_number => |num| num.value, - .e_string => |str| { - if (str.next != null) return null; - if (!str.isUTF8()) return null; - - // +'1' => 1 - return stringToEquivalentNumberValue(str.slice8()); - }, - else => null, - }, - else => null, - }; - } - - pub fn toFiniteNumber(data: Expr.Data) ?f64 { - return switch (data) { - .e_boolean, .e_branch_boolean => |b| @as(f64, if (b.value) 1.0 else 0.0), - .e_number => if (std.math.isFinite(data.e_number.value)) - data.e_number.value - else - null, - .e_inlined_enum => |inlined| switch (inlined.value.data) { - .e_number => |num| if (std.math.isFinite(num.value)) - num.value - else - null, - else => null, - }, - else => null, - }; - } - - pub fn extractNumericValue(data: Expr.Data) ?f64 { - return switch (data) { - .e_number => data.e_number.value, - .e_inlined_enum => |inlined| switch (inlined.value.data) { - .e_number => |num| num.value, - else => null, - }, - else => null, - }; - } - - pub fn extractStringValue(data: Expr.Data) ?*E.String { - return switch (data) { - .e_string => data.e_string, - .e_inlined_enum => |inlined| switch (inlined.value.data) { - .e_string => |str| str, - else => null, - }, - else => null, - }; - } - - pub const Equality = struct { - equal: bool = false, - ok: bool = false, - - /// This extra flag is unfortunately required for the case of visiting the expression - /// `require.main === module` (and any combination of !==, ==, !=, either ordering) - /// - /// We want to replace this with the dedicated import_meta_main node, which: - /// - Stops this module from having p.require_ref, allowing conversion to ESM - /// - Allows us to inline `import.meta.main`'s value, if it is known (bun build --compile) - is_require_main_and_module: bool = false, - - pub const @"true" = Equality{ .ok = true, .equal = true }; - pub const @"false" = Equality{ .ok = true, .equal = false }; - pub const unknown = Equality{ .ok = false }; - }; - - // Returns "equal, ok". If "ok" is false, then nothing is known about the two - // values. If "ok" is true, the equality or inequality of the two values is - // stored in "equal". - pub fn eql( - left: Expr.Data, - right: Expr.Data, - p: anytype, - comptime kind: enum { loose, strict }, - ) Equality { - comptime bun.assert(@typeInfo(@TypeOf(p)).pointer.size == .one); // pass *Parser - - // https://dorey.github.io/JavaScript-Equality-Table/ - switch (left) { - .e_inlined_enum => |inlined| return inlined.value.data.eql(right, p, kind), - - .e_null, .e_undefined => { - const ok = switch (@as(Expr.Tag, right)) { - .e_null, .e_undefined => true, - else => @as(Expr.Tag, right).isPrimitiveLiteral(), - }; - - if (comptime kind == .loose) { - return .{ - .equal = switch (@as(Expr.Tag, right)) { - .e_null, .e_undefined => true, - else => false, - }, - .ok = ok, - }; - } - - return .{ - .equal = @as(Tag, right) == @as(Tag, left), - .ok = ok, - }; - }, - .e_boolean, .e_branch_boolean => |l| { - switch (right) { - .e_boolean, .e_branch_boolean => |r| { - return .{ - .ok = true, - .equal = l.value == r.value, - }; - }, - .e_number => |num| { - if (comptime kind == .strict) { - // "true === 1" is false - // "false === 0" is false - return Equality.false; - } - - return .{ - .ok = true, - .equal = if (l.value) - num.value == 1 - else - num.value == 0, - }; - }, - .e_null, .e_undefined => { - return Equality.false; - }, - else => {}, - } - }, - .e_number => |l| { - switch (right) { - .e_number => |r| { - return .{ - .ok = true, - .equal = l.value == r.value, - }; - }, - .e_inlined_enum => |r| if (r.value.data == .e_number) { - return .{ - .ok = true, - .equal = l.value == r.value.data.e_number.value, - }; - }, - .e_boolean, .e_branch_boolean => |r| { - if (comptime kind == .loose) { - return .{ - .ok = true, - // "1 == true" is true - // "0 == false" is true - .equal = if (r.value) - l.value == 1 - else - l.value == 0, - }; - } - - // "1 === true" is false - // "0 === false" is false - return Equality.false; - }, - .e_null, .e_undefined => { - // "(not null or undefined) == undefined" is false - return Equality.false; - }, - else => {}, - } - }, - .e_big_int => |l| { - if (right == .e_big_int) { - if (strings.eqlLong(l.value, right.e_big_int.value, true)) { - return Equality.true; - } - - // 0x0000n == 0n is true - return .{ .ok = false }; - } else { - return .{ - .ok = switch (right) { - .e_null, .e_undefined => true, - else => false, - }, - .equal = false, - }; - } - }, - .e_string => |l| { - switch (right) { - .e_string => |r| { - r.resolveRopeIfNeeded(p.allocator); - l.resolveRopeIfNeeded(p.allocator); - return .{ - .ok = true, - .equal = r.eql(E.String, l), - }; - }, - .e_inlined_enum => |inlined| { - if (inlined.value.data == .e_string) { - const r = inlined.value.data.e_string; - - r.resolveRopeIfNeeded(p.allocator); - l.resolveRopeIfNeeded(p.allocator); - - return .{ - .ok = true, - .equal = r.eql(E.String, l), - }; - } - }, - .e_null, .e_undefined => { - return Equality.false; - }, - .e_number => |r| { - if (comptime kind == .loose) { - l.resolveRopeIfNeeded(p.allocator); - if (r.value == 0 and (l.isBlank() or l.eqlComptime("0"))) { - return Equality.true; - } - - if (r.value == 1 and l.eqlComptime("1")) { - return Equality.true; - } - - // the string could still equal 0 or 1 but it could be hex, binary, octal, ... - return Equality.unknown; - } else { - return Equality.false; - } - }, - - else => {}, - } - }, - - else => { - // Do not need to check left because e_require_main is - // always re-ordered to the right side. - if (right == .e_require_main) { - if (left.as(.e_identifier)) |id| { - if (id.ref.eql(p.module_ref)) return .{ - .ok = true, - .equal = true, - .is_require_main_and_module = true, - }; - } - } - }, - } - - return Equality.unknown; - } - - pub const toJS = @import("../../js_parser_jsc/expr_jsc.zig").dataToJS; - - pub const Store = struct { - const StoreType = NewStore(&.{ - E.NameOfSymbol, - E.Array, - E.Arrow, - E.Await, - E.BigInt, - E.Binary, - E.Call, - E.Class, - E.Dot, - E.Function, - E.If, - E.Import, - E.Index, - E.InlinedEnum, - E.JSXElement, - E.New, - E.Number, - E.Object, - E.PrivateIdentifier, - E.RegExp, - E.Spread, - E.String, - E.Template, - E.TemplatePart, - E.Unary, - E.Yield, - }, 512); - - pub threadlocal var instance: ?*StoreType = null; - pub threadlocal var memory_allocator: ?*ASTMemoryAllocator = null; - pub threadlocal var disable_reset = false; - - pub fn create() void { - if (instance != null or memory_allocator != null) { - return; - } - - instance = StoreType.init(); - } - - pub fn reset() void { - if (disable_reset or memory_allocator != null) return; - instance.?.reset(); - } - - pub fn deinit() void { - if (instance == null or memory_allocator != null) return; - instance.?.deinit(); - instance = null; - } - - pub inline fn assert() void { - if (comptime Environment.isDebug or Environment.enable_asan) { - if (instance == null and memory_allocator == null) - bun.unreachablePanic("Store must be init'd", .{}); - } - } - - /// create || reset - pub fn begin() void { - if (memory_allocator != null) return; - if (instance == null) { - create(); - return; - } - - if (!disable_reset) - instance.?.reset(); - } - - pub fn append(comptime T: type, value: T) *T { - if (memory_allocator) |allocator| { - return allocator.append(T, value); - } - - Disabler.assert(); - return instance.?.append(T, value); - } - }; - - pub inline fn isStringValue(self: Data) bool { - return @as(Expr.Tag, self) == .e_string; - } -}; - -pub fn StoredData(tag: Tag) type { - const T = @FieldType(Data, tag); - return switch (@typeInfo(T)) { - .pointer => |ptr| ptr.child, - else => T, - }; -} - -fn stringToEquivalentNumberValue(str: []const u8) f64 { - // +"" -> 0 - if (str.len == 0) return 0; - if (!bun.strings.isAllASCII(str)) - return std.math.nan(f64); - return bun.cpp.JSC__jsToNumber(str.ptr, str.len); -} - -const string = []const u8; -const stringZ = [:0]const u8; - -const JSPrinter = @import("../../js_printer/js_printer.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const JSONParser = bun.json; -const MutableString = bun.MutableString; -const OOM = bun.OOM; -const default_allocator = bun.default_allocator; -const jsc = bun.jsc; -const logger = bun.logger; -const strings = bun.strings; -const writeAnyToHasher = bun.writeAnyToHasher; -const MimeType = bun.http.MimeType; - -const js_ast = bun.ast; -const ASTMemoryAllocator = js_ast.ASTMemoryAllocator; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const NewStore = js_ast.NewStore; -const Op = js_ast.Op; -const Ref = js_ast.Ref; -const S = js_ast.S; -const Stmt = js_ast.Stmt; diff --git a/src/ast/fold_string_addition.zig b/src/ast/fold_string_addition.zig deleted file mode 100644 index ec2310fd97c5..000000000000 --- a/src/ast/fold_string_addition.zig +++ /dev/null @@ -1,233 +0,0 @@ -/// Concatenate two `E.String`s, mutating BOTH inputs -/// unless `has_inlined_enum_poison` is set. -/// -/// Currently inlined enum poison refers to where mutation would cause output -/// bugs due to inlined enum values sharing `E.String`s. If a new use case -/// besides inlined enums comes up to set this to true, please rename the -/// variable and document it. -fn joinStrings(left: *const E.String, right: *const E.String, has_inlined_enum_poison: bool) E.String { - var new = if (has_inlined_enum_poison) - // Inlined enums can be shared by multiple call sites. In - // this case, we need to ensure that the ENTIRE rope is - // cloned. In other situations, the lhs doesn't have any - // other owner, so it is fine to mutate `lhs.data.end.next`. - // - // Consider the following case: - // const enum A { - // B = "a" + "b", - // D = B + "d", - // }; - // console.log(A.B, A.D); - left.cloneRopeNodes() - else - left.*; - - // Similarly, the right side has to be cloned for an enum rope too. - // - // Consider the following case: - // const enum A { - // B = "1" + "2", - // C = ("3" + B) + "4", - // }; - // console.log(A.B, A.C); - const rhs_clone = Expr.Data.Store.append(E.String, if (has_inlined_enum_poison) - right.cloneRopeNodes() - else - right.*); - - new.push(rhs_clone); - new.prefer_template = new.prefer_template or rhs_clone.prefer_template; - - return new; -} - -/// Transforming the left operand into a string is not safe if it comes from a -/// nested AST node. -const FoldStringAdditionKind = enum { - // "x" + "y" -> "xy" - // 1 + "y" -> "1y" - normal, - // a + "x" + "y" -> a + "xy" - // a + 1 + "y" -> a + 1 + y - nested_left, -}; - -/// NOTE: unlike esbuild's js_ast_helpers.FoldStringAddition, this does mutate -/// the input AST in the case of rope strings -pub fn foldStringAddition(l: Expr, r: Expr, allocator: std.mem.Allocator, kind: FoldStringAdditionKind) ?Expr { - // "See through" inline enum constants - // TODO: implement foldAdditionPreProcess to fold some more things :) - var lhs = l.unwrapInlined(); - var rhs = r.unwrapInlined(); - - if (kind != .nested_left) { - // See comment on `FoldStringAdditionKind` for examples - switch (rhs.data) { - .e_string, .e_template => { - if (lhs.toStringExprWithoutSideEffects(allocator)) |str| { - lhs = str; - } - }, - else => {}, - } - } - - switch (lhs.data) { - .e_string => |left| { - if (rhs.toStringExprWithoutSideEffects(allocator)) |str| { - rhs = str; - } - - if (left.isUTF8()) { - switch (rhs.data) { - // "bar" + "baz" => "barbaz" - .e_string => |right| { - if (right.isUTF8()) { - const has_inlined_enum_poison = - l.data == .e_inlined_enum or - r.data == .e_inlined_enum; - - return Expr.init(E.String, joinStrings( - left, - right, - has_inlined_enum_poison, - ), lhs.loc); - } - }, - // "bar" + `baz${bar}` => `barbaz${bar}` - .e_template => |right| { - if (right.head.isUTF8()) { - return Expr.init(E.Template, E.Template{ - .parts = right.parts, - .head = .{ .cooked = joinStrings( - left, - &right.head.cooked, - l.data == .e_inlined_enum, - ) }, - }, l.loc); - } - }, - else => { - // other constant-foldable ast nodes would have been converted to .e_string - }, - } - - // "'x' + `y${z}`" => "`xy${z}`" - if (rhs.data == .e_template and rhs.data.e_template.tag == null) {} - } - - if (left.len() == 0 and rhs.knownPrimitive() == .string) { - return rhs; - } - - return null; - }, - - .e_template => |left| { - // "`${x}` + 0" => "`${x}` + '0'" - if (rhs.toStringExprWithoutSideEffects(allocator)) |str| { - rhs = str; - } - - if (left.tag == null) { - switch (rhs.data) { - // `foo${bar}` + "baz" => `foo${bar}baz` - .e_string => |right| { - if (right.isUTF8()) { - // Mutation of this node is fine because it will be not - // be shared by other places. Note that e_template will - // be treated by enums as strings, but will not be - // inlined unless they could be converted into - // .e_string. - if (left.parts.len > 0) { - const i = left.parts.len - 1; - const last = left.parts[i]; - if (last.tail.isUTF8()) { - left.parts[i].tail = .{ .cooked = joinStrings( - &last.tail.cooked, - right, - r.data == .e_inlined_enum, - ) }; - return lhs; - } - } else { - if (left.head.isUTF8()) { - left.head = .{ .cooked = joinStrings( - &left.head.cooked, - right, - r.data == .e_inlined_enum, - ) }; - return lhs; - } - } - } - }, - // `foo${bar}` + `a${hi}b` => `foo${bar}a${hi}b` - .e_template => |right| { - if (right.tag == null and right.head.isUTF8()) { - if (left.parts.len > 0) { - const i = left.parts.len - 1; - const last = left.parts[i]; - if (last.tail.isUTF8() and right.head.isUTF8()) { - left.parts[i].tail = .{ .cooked = joinStrings( - &last.tail.cooked, - &right.head.cooked, - r.data == .e_inlined_enum, - ) }; - - left.parts = if (right.parts.len == 0) - left.parts - else - std.mem.concat( - allocator, - E.TemplatePart, - &.{ left.parts, right.parts }, - ) catch |err| bun.handleOom(err); - return lhs; - } - } else { - if (left.head.isUTF8() and right.head.isUTF8()) { - left.head = .{ .cooked = joinStrings( - &left.head.cooked, - &right.head.cooked, - r.data == .e_inlined_enum, - ) }; - left.parts = right.parts; - return lhs; - } - } - } - }, - else => { - // other constant-foldable ast nodes would have been converted to .e_string - }, - } - } - }, - - else => { - // other constant-foldable ast nodes would have been converted to .e_string - }, - } - - if (rhs.data.as(.e_string)) |right| { - if (right.len() == 0 and lhs.knownPrimitive() == .string) { - return lhs; - } - } - - return null; -} - -const string = []const u8; - -const std = @import("std"); -const Allocator = std.mem.Allocator; - -const bun = @import("bun"); -const strings = bun.strings; - -const js_ast = bun.ast; -const B = js_ast.B; -const E = js_ast.E; -const Expr = js_ast.Expr; diff --git a/src/ast/g.zig b/src/ast/g.zig deleted file mode 100644 index 0dee1eb1c6ab..000000000000 --- a/src/ast/g.zig +++ /dev/null @@ -1,232 +0,0 @@ -pub const Decl = struct { - binding: BindingNodeIndex, - value: ?ExprNodeIndex = null, - - pub const List = BabyList(Decl); -}; - -pub const NamespaceAlias = struct { - namespace_ref: Ref, - alias: string, - - was_originally_property_access: bool = false, - - import_record_index: u32 = std.math.maxInt(u32), -}; - -pub const ExportStarAlias = struct { - loc: logger.Loc, - - // Although this alias name starts off as being the same as the statement's - // namespace symbol, it may diverge if the namespace symbol name is minified. - // The original alias name is preserved here to avoid this scenario. - original_name: string, -}; - -pub const Class = struct { - class_keyword: logger.Range = logger.Range.None, - ts_decorators: ExprNodeList = ExprNodeList{}, - class_name: ?LocRef = null, - extends: ?ExprNodeIndex = null, - body_loc: logger.Loc = logger.Loc.Empty, - close_brace_loc: logger.Loc = logger.Loc.Empty, - properties: []Property = &([_]Property{}), - has_decorators: bool = false, - should_lower_standard_decorators: bool = false, - - pub fn canBeMoved(this: *const Class) bool { - if (this.extends != null) - return false; - - if (this.has_decorators) { - return false; - } - - for (this.properties) |property| { - if (property.kind == .class_static_block) - return false; - - const flags = property.flags; - if (flags.contains(.is_computed) or flags.contains(.is_spread)) { - return false; - } - - if (property.kind == .normal) { - if (flags.contains(.is_static)) { - for ([2]?Expr{ property.value, property.initializer }) |val_| { - if (val_) |val| { - switch (val.data) { - .e_arrow, .e_function => {}, - else => { - if (!val.canBeMoved()) { - return false; - } - }, - } - } - } - } - } - } - - return true; - } -}; - -// invalid shadowing if left as Comment -pub const Comment = struct { loc: logger.Loc, text: string }; - -pub const ClassStaticBlock = struct { - stmts: BabyList(Stmt) = .{}, - loc: logger.Loc, -}; - -pub const Property = struct { - /// This is used when parsing a pattern that uses default values: - /// - /// [a = 1] = []; - /// ({a = 1} = {}); - /// - /// It's also used for class fields: - /// - /// class Foo { a = 1 } - /// - initializer: ?ExprNodeIndex = null, - kind: Kind = .normal, - flags: Flags.Property.Set = Flags.Property.None, - - class_static_block: ?*ClassStaticBlock = null, - ts_decorators: ExprNodeList = .{}, - // Key is optional for spread - key: ?ExprNodeIndex = null, - - // This is omitted for class fields - value: ?ExprNodeIndex = null, - - ts_metadata: TypeScript.Metadata = .m_none, - - pub const List = BabyList(Property); - - pub fn deepClone(this: *const Property, allocator: std.mem.Allocator) !Property { - var class_static_block: ?*ClassStaticBlock = null; - if (this.class_static_block != null) { - class_static_block = bun.create(allocator, ClassStaticBlock, .{ - .loc = this.class_static_block.?.loc, - .stmts = try this.class_static_block.?.stmts.clone(allocator), - }); - } - return .{ - .initializer = if (this.initializer) |init| try init.deepClone(allocator) else null, - .kind = this.kind, - .flags = this.flags, - .class_static_block = class_static_block, - .ts_decorators = try this.ts_decorators.deepClone(allocator), - .key = if (this.key) |key| try key.deepClone(allocator) else null, - .value = if (this.value) |value| try value.deepClone(allocator) else null, - .ts_metadata = this.ts_metadata, - }; - } - - pub const Kind = enum(u3) { - normal, - get, - set, - spread, - declare, - abstract, - class_static_block, - auto_accessor, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - }; -}; - -pub const FnBody = struct { - loc: logger.Loc, - stmts: StmtNodeList, - - pub fn initReturnExpr(allocator: std.mem.Allocator, expr: Expr) !FnBody { - return .{ - .stmts = try allocator.dupe(Stmt, &.{Stmt.alloc(S.Return, .{ - .value = expr, - }, expr.loc)}), - .loc = expr.loc, - }; - } -}; - -pub const Fn = struct { - name: ?LocRef = null, - open_parens_loc: logger.Loc = logger.Loc.Empty, - args: []Arg = &.{}, - // This was originally nullable, but doing so I believe caused a miscompilation - // Specifically, the body was always null. - body: FnBody = .{ .loc = logger.Loc.Empty, .stmts = &.{} }, - arguments_ref: ?Ref = null, - - flags: Flags.Function.Set = Flags.Function.None, - - return_ts_metadata: TypeScript.Metadata = .m_none, - - pub fn deepClone(this: *const Fn, allocator: std.mem.Allocator) !Fn { - const args = try allocator.alloc(Arg, this.args.len); - for (0..args.len) |i| { - args[i] = try this.args[i].deepClone(allocator); - } - return .{ - .name = this.name, - .open_parens_loc = this.open_parens_loc, - .args = args, - .body = .{ - .loc = this.body.loc, - .stmts = this.body.stmts, - }, - .arguments_ref = this.arguments_ref, - .flags = this.flags, - .return_ts_metadata = this.return_ts_metadata, - }; - } -}; -pub const Arg = struct { - ts_decorators: ExprNodeList = ExprNodeList{}, - binding: BindingNodeIndex, - default: ?ExprNodeIndex = null, - - // "constructor(public x: boolean) {}" - is_typescript_ctor_field: bool = false, - - ts_metadata: TypeScript.Metadata = .m_none, - - pub fn deepClone(this: *const Arg, allocator: std.mem.Allocator) !Arg { - return .{ - .ts_decorators = try this.ts_decorators.deepClone(allocator), - .binding = this.binding, - .default = if (this.default) |d| try d.deepClone(allocator) else null, - .is_typescript_ctor_field = this.is_typescript_ctor_field, - .ts_metadata = this.ts_metadata, - }; - } -}; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const logger = bun.logger; -const TypeScript = bun.js_parser.TypeScript; - -const js_ast = bun.ast; -const BindingNodeIndex = js_ast.BindingNodeIndex; -const Expr = js_ast.Expr; -const ExprNodeIndex = js_ast.ExprNodeIndex; -const ExprNodeList = js_ast.ExprNodeList; -const Flags = js_ast.Flags; -const LocRef = js_ast.LocRef; -const Ref = js_ast.Ref; -const S = js_ast.S; -const Stmt = js_ast.Stmt; -const StmtNodeList = js_ast.StmtNodeList; diff --git a/src/ast/known_global.zig b/src/ast/known_global.zig deleted file mode 100644 index 08bd1ca950d9..000000000000 --- a/src/ast/known_global.zig +++ /dev/null @@ -1,361 +0,0 @@ -pub const KnownGlobal = enum { - WeakSet, - WeakMap, - Date, - Set, - Map, - Headers, - Response, - TextEncoder, - TextDecoder, - Error, - TypeError, - SyntaxError, - RangeError, - ReferenceError, - EvalError, - URIError, - AggregateError, - Array, - Object, - Function, - RegExp, - - pub const map = bun.ComptimeEnumMap(KnownGlobal); - - inline fn callFromNew(e: *E.New, loc: logger.Loc) js_ast.Expr { - const call = E.Call{ - .target = e.target, - .args = e.args, - .close_paren_loc = e.close_parens_loc, - .can_be_unwrapped_if_unused = e.can_be_unwrapped_if_unused, - }; - return js_ast.Expr.init(E.Call, call, loc); - } - - pub noinline fn minifyGlobalConstructor(allocator: std.mem.Allocator, noalias e: *E.New, symbols: []const Symbol, loc: logger.Loc, minify_whitespace: bool) ?js_ast.Expr { - const id = if (e.target.data == .e_identifier) e.target.data.e_identifier.ref else return null; - const symbol = &symbols[id.innerIndex()]; - if (symbol.kind != .unbound) - return null; - - const constructor = map.get(symbol.original_name) orelse return null; - - return switch (constructor) { - // Error constructors can be called without 'new' with identical behavior - .Error, .TypeError, .SyntaxError, .RangeError, .ReferenceError, .EvalError, .URIError, .AggregateError => { - // Convert `new Error(...)` to `Error(...)` to save bytes - return callFromNew(e, loc); - }, - - .Object => { - const n = e.args.len; - - if (n == 0) { - // new Object() -> {} - return js_ast.Expr.init(E.Object, E.Object{}, loc); - } - - if (n == 1) { - const arg = e.args.ptr[0]; - switch (arg.data) { - .e_object, .e_array => { - // new Object({a: 1}) -> {a: 1} - // new Object([1, 2]) -> [1, 2] - return arg; - }, - .e_null, .e_undefined => { - // new Object(null) -> {} - // new Object(undefined) -> {} - return js_ast.Expr.init(E.Object, E.Object{}, loc); - }, - else => {}, - } - } - - // For other cases, just remove 'new' - return callFromNew(e, loc); - }, - - .Array => { - const n = e.args.len; - - return switch (n) { - 0 => { - // new Array() -> [] - return js_ast.Expr.init(E.Array, E.Array{}, loc); - }, - 1 => { - // For single argument, only convert to literal if we're SURE it's not a number - const arg = e.args.ptr[0]; - - // Check if it's an object or array literal first - switch (arg.data) { - .e_object, .e_array => { - // new Array({}) -> [{}], new Array([1]) -> [[1]] - // These are definitely not numbers, safe to convert - return js_ast.Expr.init(E.Array, .{ .items = e.args }, loc); - }, - else => {}, - } - - // For other types, check via knownPrimitive - const primitive = arg.knownPrimitive(); - // Only convert if we know for certain it's not a number - // unknown could be a number at runtime, so we must preserve Array() call - switch (primitive) { - .null, .undefined, .boolean, .string, .bigint => { - // These are definitely not numbers, safe to convert - return js_ast.Expr.init(E.Array, .{ .items = e.args }, loc); - }, - .number => { - if (arg.data != .e_number) { - return callFromNew(e, loc); - } - const val = arg.data.e_number.value; - if ( - // only want this with whitespace minification - minify_whitespace and - (val == 0 or - val == 1 or - val == 2 or - val == 3 or - val == 4 or - val == 5 or - val == 6 or - val == 7 or - val == 8 or - val == 9 or - val == 10)) - { - const arg_loc = arg.loc; - var list = e.args.moveToListManaged(allocator); - list.clearRetainingCapacity(); - bun.handleOom(list.appendNTimes(js_ast.Expr{ .data = js_parser.Prefill.Data.EMissing, .loc = arg_loc }, @intFromFloat(val))); - return js_ast.Expr.init(E.Array, .{ .items = .moveFromList(&list) }, loc); - } - return callFromNew(e, loc); - }, - .unknown, .mixed => { - // Could be a number, preserve Array() call - return callFromNew(e, loc); - }, - } - }, - // > 1 - else => { - // new Array(1, 2, 3) -> [1, 2, 3] - // But NOT new Array(3) which creates an array with 3 empty slots - return js_ast.Expr.init(E.Array, .{ .items = e.args }, loc); - }, - }; - }, - - .Function => { - // Just remove 'new' for Function - return callFromNew(e, loc); - }, - .RegExp => { - // Don't optimize RegExp - the semantics are too complex: - // - new RegExp(re) creates a copy, but RegExp(re) returns the same instance - // - This affects object identity and lastIndex behavior - // - The difference only applies when flags are undefined - // Keep the original new RegExp() call to preserve correct semantics - return null; - }, - .WeakSet, .WeakMap => { - const n = e.args.len; - - if (n == 0) { - // "new WeakSet()" is pure - e.can_be_unwrapped_if_unused = .if_unused; - - return null; - } - - if (n == 1) { - switch (e.args.ptr[0].data) { - .e_null, .e_undefined => { - // "new WeakSet(null)" is pure - // "new WeakSet(void 0)" is pure - e.can_be_unwrapped_if_unused = .if_unused; - }, - .e_array => |array| { - if (array.items.len == 0) { - // "new WeakSet([])" is pure - e.can_be_unwrapped_if_unused = .if_unused; - } else { - // "new WeakSet([x])" is impure because an exception is thrown if "x" is not an object - } - }, - else => { - // "new WeakSet(x)" is impure because the iterator for "x" could have side effects - }, - } - } - return null; - }, - .Date => { - const n = e.args.len; - - if (n == 0) { - // "new Date()" is pure - e.can_be_unwrapped_if_unused = .if_unused; - - return null; - } - - if (n == 1) { - switch (e.args.ptr[0].knownPrimitive()) { - .null, .undefined, .boolean, .number, .string => { - // "new Date('')" is pure - // "new Date(0)" is pure - // "new Date(null)" is pure - // "new Date(true)" is pure - // "new Date(false)" is pure - // "new Date(undefined)" is pure - e.can_be_unwrapped_if_unused = .if_unused; - }, - else => { - // "new Date(x)" is impure because the argument could be a string with side effects - - }, - } - } - return null; - }, - - .Set => { - const n = e.args.len; - - if (n == 0) { - // "new Set()" is pure - e.can_be_unwrapped_if_unused = .if_unused; - return null; - } - - if (n == 1) { - switch (e.args.ptr[0].data) { - .e_array, .e_null, .e_undefined => { - // "new Set([a, b, c])" is pure - // "new Set(null)" is pure - // "new Set(void 0)" is pure - e.can_be_unwrapped_if_unused = .if_unused; - }, - else => { - // "new Set(x)" is impure because the iterator for "x" could have side effects - }, - } - } - return null; - }, - - .Headers => { - const n = e.args.len; - - if (n == 0) { - // "new Headers()" is pure - e.can_be_unwrapped_if_unused = .if_unused; - - return null; - } - return null; - }, - - .Response => { - const n = e.args.len; - - if (n == 0) { - // "new Response()" is pure - e.can_be_unwrapped_if_unused = .if_unused; - - return null; - } - - if (n == 1) { - switch (e.args.ptr[0].knownPrimitive()) { - .null, .undefined, .boolean, .number, .string => { - // "new Response('')" is pure - // "new Response(0)" is pure - // "new Response(null)" is pure - // "new Response(true)" is pure - // "new Response(false)" is pure - // "new Response(undefined)" is pure - - e.can_be_unwrapped_if_unused = .if_unused; - }, - else => { - // "new Response(x)" is impure - }, - } - } - return null; - }, - .TextDecoder, .TextEncoder => { - const n = e.args.len; - - if (n == 0) { - // "new TextEncoder()" is pure - // "new TextDecoder()" is pure - e.can_be_unwrapped_if_unused = .if_unused; - - return null; - } - - // We _could_ validate the encoding argument - // But let's not bother - return null; - }, - - .Map => { - const n = e.args.len; - - if (n == 0) { - // "new Map()" is pure - e.can_be_unwrapped_if_unused = .if_unused; - return null; - } - - if (n == 1) { - switch (e.args.ptr[0].data) { - .e_null, .e_undefined => { - // "new Map(null)" is pure - // "new Map(void 0)" is pure - e.can_be_unwrapped_if_unused = .if_unused; - }, - .e_array => |array| { - var all_items_are_arrays = true; - for (array.items.slice()) |item| { - if (item.data != .e_array) { - all_items_are_arrays = false; - break; - } - } - - if (all_items_are_arrays) { - // "new Map([[a, b], [c, d]])" is pure - e.can_be_unwrapped_if_unused = .if_unused; - } - }, - else => { - // "new Map(x)" is impure because the iterator for "x" could have side effects - }, - } - } - return null; - }, - }; - } -}; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const js_parser = bun.js_parser; -const logger = bun.logger; - -const js_ast = bun.ast; -const E = js_ast.E; -const Symbol = js_ast.Symbol; diff --git a/src/ast/logger.zig b/src/ast/logger.zig deleted file mode 100644 index 123c09f7464e..000000000000 --- a/src/ast/logger.zig +++ /dev/null @@ -1,1522 +0,0 @@ -pub const Kind = enum(u8) { - err = 0, - warn = 1, - note = 2, - debug = 3, - verbose = 4, - - pub inline fn shouldPrint(this: Kind, other: Log.Level) bool { - return switch (other) { - .err => switch (this) { - .err, .note => true, - else => false, - }, - .warn => switch (this) { - .err, .warn, .note => true, - else => false, - }, - .info, .debug => this != .verbose, - .verbose => true, - }; - } - - pub inline fn string(self: Kind) []const u8 { - return switch (self) { - .err => "error", - .warn => "warn", - .note => "note", - .debug => "debug", - .verbose => "verbose", - }; - } - - pub inline fn toAPI(kind: Kind) api.MessageLevel { - return switch (kind) { - .err => .err, - .warn => .warn, - .note => .note, - else => .debug, - }; - } -}; - -// Do not mark these as packed -// https://github.com/ziglang/zig/issues/15715 -pub const Loc = struct { - start: i32 = -1, - - pub inline fn toNullable(loc: Loc) ?Loc { - return if (loc.start == -1) null else loc; - } - - pub const toUsize = i; - - pub inline fn i(self: *const Loc) usize { - return @as(usize, @intCast(@max(self.start, 0))); - } - - pub const Empty = Loc{ .start = -1 }; - - pub inline fn eql(loc: Loc, other: Loc) bool { - return loc.start == other.start; - } - - pub inline fn isEmpty(this: Loc) bool { - return eql(this, Empty); - } - - pub fn jsonStringify(self: *const Loc, writer: anytype) !void { - return try writer.write(self.start); - } -}; - -pub const Location = struct { - // Field ordering optimized to reduce padding: - // - 16-byte fields first: string (ptr+len), ?string (ptr+len+null flag) - // - 8-byte fields next: usize - // - 4-byte fields last: i32 - // This eliminates padding between differently-sized fields. - - file: string, - namespace: string = "file", - /// Text on the line, avoiding the need to refetch the source code - line_text: ?string = null, - /// Number of bytes this location should highlight. - /// 0 to just point at a single character - length: usize = 0, - // TODO: document or remove - offset: usize = 0, - - /// 1-based line number. - /// Line <= 0 means there is no line and column information. - // TODO: move to `bun.Ordinal` - line: i32, - // TODO: figure out how this is interpreted, convert to `bun.Ordinal` - // original docs: 0-based, in bytes. - // but there is a place where this is emitted in output, implying one based character offset - column: i32, - - pub fn memoryCost(this: *const Location) usize { - var cost: usize = 0; - cost += this.file.len; - cost += this.namespace.len; - if (this.line_text) |text| cost += text.len; - return cost; - } - - pub fn count(this: Location, builder: *StringBuilder) void { - builder.count(this.file); - builder.count(this.namespace); - if (this.line_text) |text| builder.count(text); - } - - pub fn clone(this: Location, allocator: std.mem.Allocator) !Location { - return Location{ - .file = try allocator.dupe(u8, this.file), - .namespace = this.namespace, - .line = this.line, - .column = this.column, - .length = this.length, - .line_text = if (this.line_text != null) try allocator.dupe(u8, this.line_text.?) else null, - .offset = this.offset, - }; - } - - pub fn cloneWithBuilder(this: Location, string_builder: *StringBuilder) Location { - return Location{ - .file = string_builder.append(this.file), - .namespace = this.namespace, - .line = this.line, - .column = this.column, - .length = this.length, - .line_text = if (this.line_text != null) string_builder.append(this.line_text.?) else null, - .offset = this.offset, - }; - } - - pub fn toAPI(this: *const Location) api.Location { - return api.Location{ - .file = this.file, - .namespace = this.namespace, - .line = this.line, - .column = this.column, - .line_text = this.line_text orelse "", - .offset = @as(u32, @truncate(this.offset)), - }; - } - - // don't really know what's safe to deinit here! - pub fn deinit(_: *Location, _: std.mem.Allocator) void {} - - pub fn init(file: string, namespace: string, line: i32, column: i32, length: u32, line_text: ?string) Location { - return Location{ - .file = file, - .namespace = namespace, - .line = line, - .column = column, - .length = length, - .line_text = line_text, - .offset = length, - }; - } - - pub fn initOrNull(_source: ?*const Source, r: Range) ?Location { - if (_source) |source| { - if (r.isEmpty()) { - return Location{ - .file = source.path.text, - .namespace = source.path.namespace, - .line = -1, - .column = -1, - .length = 0, - .line_text = "", - .offset = 0, - }; - } - const data = source.initErrorPosition(r.loc); - var full_line = source.contents[data.line_start..data.line_end]; - if (full_line.len > 80 + data.column_count) { - full_line = full_line[@max(data.column_count, 40) - 40 .. @min(data.column_count + 40, full_line.len - 40) + 40]; - } - - return Location{ - .file = source.path.text, - .namespace = source.path.namespace, - .line = usize2Loc(data.line_count).start, - .column = usize2Loc(data.column_count).start, - .length = if (r.len > -1) @as(u32, @intCast(r.len)) else 1, - .line_text = std.mem.trimLeft(u8, full_line, "\n\r"), - .offset = @as(usize, @intCast(@max(r.loc.start, 0))), - }; - } - return null; - } -}; - -pub const Data = struct { - text: string, - location: ?Location = null, - - pub fn memoryCost(this: *const Data) usize { - var cost: usize = 0; - cost += this.text.len; - if (this.location) |*loc| { - cost += loc.memoryCost(); - } - return cost; - } - - pub fn deinit(d: *Data, allocator: std.mem.Allocator) void { - if (d.location) |*loc| { - loc.deinit(allocator); - } - - allocator.free(d.text); - } - - pub fn cloneLineText(this: Data, should: bool, allocator: std.mem.Allocator) OOM!Data { - if (!should or this.location == null or this.location.?.line_text == null) - return this; - - const new_line_text = try allocator.dupe(u8, this.location.?.line_text.?); - var new_location = this.location.?; - new_location.line_text = new_line_text; - return Data{ - .text = this.text, - .location = new_location, - }; - } - - pub fn clone(this: Data, allocator: std.mem.Allocator) OOM!Data { - return Data{ - .text = if (this.text.len > 0) try allocator.dupe(u8, this.text) else "", - .location = if (this.location != null) try this.location.?.clone(allocator) else null, - }; - } - - pub fn cloneWithBuilder(this: Data, builder: *StringBuilder) Data { - return Data{ - .text = if (this.text.len > 0) builder.append(this.text) else "", - .location = if (this.location != null) this.location.?.cloneWithBuilder(builder) else null, - }; - } - - pub fn count(this: Data, builder: *StringBuilder) void { - builder.count(this.text); - if (this.location) |loc| loc.count(builder); - } - - pub fn toAPI(this: *const Data) api.MessageData { - return api.MessageData{ - .text = this.text, - .location = if (this.location != null) this.location.?.toAPI() else null, - }; - } - - pub fn writeFormat( - this: *const Data, - to: *std.Io.Writer, - kind: Kind, - redact_sensitive_information: bool, - comptime enable_ansi_colors: bool, - ) !void { - if (this.text.len == 0) return; - - const message_color = switch (kind) { - .err => comptime Output.color_map.get("b").?, - .note => comptime Output.color_map.get("blue").?, - else => comptime Output.color_map.get("d").? ++ Output.color_map.get("b").?, - }; - - const color_name: string = switch (kind) { - .err => comptime Output.color_map.get("red").?, - .note => comptime Output.color_map.get("blue").?, - else => comptime Output.color_map.get("d").?, - }; - - if (this.location) |*location| { - if (location.line_text) |line_text_| { - const line_text_right_trimmed = std.mem.trimRight(u8, line_text_, " \r\n\t"); - const line_text = std.mem.trimLeft(u8, line_text_right_trimmed, "\n\r"); - if (location.column > 0 and line_text.len > 0) { - var line_offset_for_second_line: usize = @intCast(location.column - 1); - - if (location.line > -1) { - switch (kind == .err or kind == .warn) { - inline else => |bold| try to.print( - // bold the line number for error but dim for the attached note - if (bold) - comptime Output.prettyFmt("{d} | ", enable_ansi_colors) - else - comptime Output.prettyFmt("{d} | ", enable_ansi_colors), - .{ - location.line, - }, - ), - } - - line_offset_for_second_line += std.fmt.count("{d} | ", .{location.line}); - } - - try to.print("{f}\n", .{bun.fmt.fmtJavaScript(line_text, .{ - .enable_colors = enable_ansi_colors, - .redact_sensitive_information = redact_sensitive_information, - })}); - - try to.splatByteAll(' ', line_offset_for_second_line); - if ((comptime enable_ansi_colors) and message_color.len > 0) { - try to.writeAll(message_color); - try to.writeAll(color_name); - // always bold the ^ - try to.writeAll(comptime Output.color_map.get("b").?); - - try to.writeByte('^'); - - try to.writeAll("\x1b[0m\n"); - } else { - try to.writeAll("^\n"); - } - } - } - } - - if (comptime enable_ansi_colors) { - try to.writeAll(color_name); - } - - try to.writeAll(kind.string()); - - try to.print(comptime Output.prettyFmt(": ", enable_ansi_colors), .{}); - - if (comptime enable_ansi_colors) { - try to.writeAll(message_color); - } - - try to.print(comptime Output.prettyFmt("{s}", enable_ansi_colors), .{this.text}); - - if (this.location) |*location| { - if (location.file.len > 0) { - try to.writeAll("\n"); - try to.splatByteAll(' ', (kind.string().len + ": ".len) - "at ".len); - - try to.print(comptime Output.prettyFmt("at {s}", enable_ansi_colors), .{ - location.file, - }); - - if (location.line > 0 and location.column > -1) { - try to.print(comptime Output.prettyFmt(":{d}:{d}", enable_ansi_colors), .{ - location.line, - location.column, - }); - } else if (location.line > -1) { - try to.print(comptime Output.prettyFmt(":{d}", enable_ansi_colors), .{ - location.line, - }); - } - - if (Environment.isDebug) { - // comptime magic: do not print byte when using Bun.inspect, but only print - // when you the writer is to a file (like standard out) - if ((comptime std.mem.indexOf(u8, @typeName(@TypeOf(to)), "fs.file") != null) and Output.enable_ansi_colors_stderr) { - try to.print(comptime Output.prettyFmt(" byte={d}", enable_ansi_colors), .{ - location.offset, - }); - } - } - } - } - } -}; - -pub const BabyString = packed struct(u32) { - offset: u16, - len: u16, - - pub fn in(parent: string, text: string) BabyString { - return BabyString{ - .offset = @as(u16, @truncate(std.mem.indexOf(u8, parent, text) orelse unreachable)), - .len = @as(u16, @truncate(text.len)), - }; - } - - pub fn slice(this: BabyString, container: string) string { - return container[this.offset..][0..this.len]; - } -}; - -pub const Msg = struct { - kind: Kind = Kind.err, - data: Data, - metadata: Metadata = .build, - notes: []Data = &.{}, - redact_sensitive_information: bool = false, - - pub fn memoryCost(this: *const Msg) usize { - var cost: usize = 0; - cost += this.data.memoryCost(); - for (this.notes) |*note| { - cost += note.memoryCost(); - } - return cost; - } - - pub const fromJS = @import("../logger_jsc/logger_jsc.zig").msgFromJS; - pub const toJS = @import("../logger_jsc/logger_jsc.zig").msgToJS; - - pub fn count(this: *const Msg, builder: *StringBuilder) void { - this.data.count(builder); - for (this.notes) |note| { - note.count(builder); - } - } - - pub fn clone(this: *const Msg, allocator: std.mem.Allocator) OOM!Msg { - return Msg{ - .kind = this.kind, - .data = try this.data.clone(allocator), - .metadata = this.metadata, - .notes = try bun.clone(this.notes, allocator), - }; - } - - pub fn cloneWithBuilder(this: *const Msg, notes: []Data, builder: *StringBuilder) Msg { - return Msg{ - .kind = this.kind, - .data = this.data.cloneWithBuilder(builder), - .metadata = this.metadata, - .notes = if (this.notes.len > 0) brk: { - for (this.notes, 0..) |note, i| { - notes[i] = note.cloneWithBuilder(builder); - } - break :brk notes[0..this.notes.len]; - } else &.{}, - }; - } - - pub const Metadata = union(enum) { - build, - resolve: Resolve, - - pub const Resolve = struct { - specifier: BabyString, - import_kind: ImportKind, - err: anyerror = error.ModuleNotFound, - }; - }; - - pub fn toAPI(this: *const Msg, allocator: std.mem.Allocator) OOM!api.Message { - var notes = try allocator.alloc( - api.MessageData, - this.notes.len, - ); - const msg = api.Message{ - .level = this.kind.toAPI(), - .data = this.data.toAPI(), - .notes = notes, - .on = api.MessageMeta{ - .resolve = if (this.metadata == .resolve) this.metadata.resolve.specifier.slice(this.data.text) else "", - .build = this.metadata == .build, - }, - }; - - for (this.notes, 0..) |note, i| { - notes[i] = note.toAPI(); - } - - return msg; - } - - pub fn toAPIFromList(comptime ListType: type, list: ListType, allocator: std.mem.Allocator) OOM![]api.Message { - var out_list = try allocator.alloc(api.Message, list.items.len); - for (list.items, 0..) |item, i| { - out_list[i] = try item.toAPI(allocator); - } - - return out_list; - } - - pub fn deinit(msg: *Msg, allocator: std.mem.Allocator) void { - msg.data.deinit(allocator); - for (msg.notes) |*note| { - note.deinit(allocator); - } - - allocator.free(msg.notes); - - msg.notes = &.{}; - } - - pub fn writeFormat( - msg: *const Msg, - to: *std.Io.Writer, - comptime enable_ansi_colors: bool, - ) !void { - try msg.data.writeFormat(to, msg.kind, msg.redact_sensitive_information, enable_ansi_colors); - - if (msg.notes.len > 0) { - try to.writeAll("\n"); - } - - for (msg.notes) |note| { - try to.writeAll("\n"); - - try note.writeFormat(to, .note, msg.redact_sensitive_information, enable_ansi_colors); - } - } - - pub fn formatWriter( - msg: *const Msg, - comptime Writer: type, - writer: Writer, - comptime _: bool, - ) !void { - if (msg.data.location) |location| { - try writer.print("{s}: {s}\n{s}\n{s}:{}:{} ({d})", .{ - msg.kind.string(), - msg.data.text, - location.line_text orelse "", - location.file, - location.line, - location.column, - location.offset, - }); - } else { - try writer.print("{s}: {s}", .{ - msg.kind.string(), - msg.data.text, - }); - } - } - - pub fn formatNoWriter(msg: *const Msg, comptime formatterFunc: @TypeOf(Output.panic)) void { - formatterFunc("\n\n{s}: {s}\n{s}\n{s}:{}:{} ({d})", .{ - msg.kind.string(), - msg.data.text, - msg.data.location.?.line_text, - msg.data.location.?.file, - msg.data.location.?.line, - msg.data.location.?.column, - msg.data.location.?.offset, - }); - } -}; - -// Do not mark these as packed -// https://github.com/ziglang/zig/issues/15715 -pub const Range = struct { - loc: Loc = Loc.Empty, - len: i32 = 0, - - /// Deprecated: use .none - pub const None = none; - pub const none = Range{ .loc = Loc.Empty, .len = 0 }; - - pub fn in(this: Range, buf: []const u8) []const u8 { - if (this.loc.start < 0 or this.len <= 0) return ""; - const slice = buf[@as(usize, @intCast(this.loc.start))..]; - return slice[0..@min(@as(usize, @intCast(this.len)), buf.len)]; - } - - pub fn contains(this: Range, k: i32) bool { - return k >= this.loc.start and k < this.loc.start + this.len; - } - - pub fn isEmpty(r: *const Range) bool { - return r.len == 0 and r.loc.start == Loc.Empty.start; - } - - pub fn end(self: *const Range) Loc { - return Loc{ .start = self.loc.start + self.len }; - } - pub fn endI(self: *const Range) usize { - return std.math.lossyCast(usize, self.loc.start + self.len); - } - - pub fn jsonStringify(self: *const Range, writer: anytype) !void { - return try writer.write([2]i32{ self.loc.start, self.len + self.loc.start }); - } -}; - -pub const Log = struct { - warnings: u32 = 0, - errors: u32 = 0, - msgs: std.array_list.Managed(Msg), - level: Level = if (Environment.isDebug) Level.info else Level.warn, - - clone_line_text: bool = false, - - pub fn memoryCost(this: *const Log) usize { - var cost: usize = 0; - for (this.msgs.items) |msg| { - cost += msg.memoryCost(); - } - return cost; - } - - pub inline fn hasErrors(this: *const Log) bool { - return this.errors > 0; - } - - pub fn reset(this: *Log) void { - this.msgs.clearRetainingCapacity(); - this.warnings = 0; - this.errors = 0; - } - - pub var default_log_level = Level.warn; - - pub fn hasAny(this: *const Log) bool { - return (this.warnings + this.errors) > 0; - } - - pub fn toAPI(this: *const Log, allocator: std.mem.Allocator) !api.Log { - var warnings: u32 = 0; - var errors: u32 = 0; - for (this.msgs.items) |msg| { - errors += @as(u32, @intCast(@intFromBool(msg.kind == .err))); - warnings += @as(u32, @intCast(@intFromBool(msg.kind == .warn))); - } - - return api.Log{ - .warnings = warnings, - .errors = errors, - .msgs = try Msg.toAPIFromList(@TypeOf(this.msgs), this.msgs, allocator), - }; - } - - pub const Level = enum(i8) { - verbose, // 0 - debug, // 1 - info, // 2 - warn, // 3 - err, // 4 - - pub fn atLeast(this: Level, other: Level) bool { - return @intFromEnum(this) <= @intFromEnum(other); - } - - pub const label: std.EnumArray(Level, string) = brk: { - var map = std.EnumArray(Level, string).initFill(""); - map.set(Level.verbose, "verbose"); - map.set(Level.debug, "debug"); - map.set(Level.info, "info"); - map.set(Level.warn, "warn"); - map.set(Level.err, "error"); - break :brk map; - }; - pub const Map = bun.ComptimeStringMap(Level, .{ - .{ "verbose", Level.verbose }, - .{ "debug", Level.debug }, - .{ "info", Level.info }, - .{ "warn", Level.warn }, - .{ "error", Level.err }, - }); - - pub const fromJS = @import("../logger_jsc/logger_jsc.zig").levelFromJS; - }; - - pub fn init(allocator: std.mem.Allocator) Log { - return Log{ - .msgs = std.array_list.Managed(Msg).init(allocator), - .level = default_log_level, - }; - } - - pub fn initComptime(allocator: std.mem.Allocator) Log { - return Log{ - .msgs = std.array_list.Managed(Msg).init(allocator), - }; - } - - pub inline fn addDebugFmt(log: *Log, source: ?*const Source, l: Loc, allocator: std.mem.Allocator, comptime text: string, args: anytype) OOM!void { - if (!Kind.shouldPrint(.debug, log.level)) return; - return log.addFormattedMsg(.debug, source, .{ .loc = l }, try allocPrint(allocator, text, args), &.{}, true, false); - } - - pub fn addVerbose(log: *Log, source: ?*const Source, loc: Loc, text: string) OOM!void { - if (Kind.shouldPrint(.verbose, log.level)) { - @branchHint(.cold); - try log.addMsg(.{ - .kind = .verbose, - .data = rangeData(source, Range{ .loc = loc }, text), - }); - } - } - - pub const toJS = @import("../logger_jsc/logger_jsc.zig").logToJS; - pub const toJSAggregateError = @import("../logger_jsc/logger_jsc.zig").logToJSAggregateError; - pub const toJSArray = @import("../logger_jsc/logger_jsc.zig").logToJSArray; - - pub fn cloneTo(self: *Log, other: *Log) OOM!void { - var notes_count: usize = 0; - - for (self.msgs.items) |msg_| { - const msg: Msg = msg_; - for (msg.notes) |note| { - notes_count += @as(usize, @intCast(@intFromBool(note.text.len > 0))); - } - } - - if (notes_count > 0) { - var notes = try other.msgs.allocator.alloc(Data, notes_count); - var note_i: usize = 0; - for (self.msgs.items) |*msg| { - const start_note_i: usize = note_i; - for (msg.notes) |note| { - notes[note_i] = note; - note_i += 1; - } - msg.notes = notes[start_note_i..note_i]; - } - } - - try other.msgs.appendSlice(self.msgs.items); - other.warnings += self.warnings; - other.errors += self.errors; - } - - pub fn appendTo(self: *Log, other: *Log) OOM!void { - try self.cloneTo(other); - self.msgs.clearAndFree(); - } - - pub fn cloneToWithRecycled(self: *Log, other: *Log, recycled: bool) OOM!void { - try other.msgs.appendSlice(self.msgs.items); - other.warnings += self.warnings; - other.errors += self.errors; - - if (recycled) { - var string_builder = StringBuilder{}; - var notes_count: usize = 0; - { - for (self.msgs.items) |msg| { - msg.count(&string_builder); - - notes_count += msg.notes.len; - } - } - - try string_builder.allocate(other.msgs.allocator); - var notes_buf = try other.msgs.allocator.alloc(Data, notes_count); - var note_i: usize = 0; - - { - for (self.msgs.items, (other.msgs.items.len - self.msgs.items.len)..) |msg, j| { - other.msgs.items[j] = msg.cloneWithBuilder(notes_buf[note_i..], &string_builder); - note_i += msg.notes.len; - } - } - } - } - - pub fn appendToWithRecycled(self: *Log, other: *Log, recycled: bool) OOM!void { - try self.cloneToWithRecycled(other, recycled); - self.msgs.clearAndFree(); - } - - pub fn appendToMaybeRecycled(self: *Log, other: *Log, source: *const Source) OOM!void { - return self.appendToWithRecycled(other, source.contents_is_recycled); - } - - pub fn deinit(log: *Log) void { - log.msgs.clearAndFree(); - // log.warnings = 0; - // log.errors = 0; - } - - // TODO: remove `deinit` because it does not de-initialize the log; it clears it - pub const clearAndFree = deinit; - - pub fn addVerboseWithNotes(log: *Log, source: ?*const Source, loc: Loc, text: string, notes: []Data) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.verbose, log.level)) return; - - try log.addMsg(.{ - .kind = .verbose, - .data = rangeData(source, Range{ .loc = loc }, text), - .notes = notes, - }); - } - - pub inline fn allocPrint(allocator: std.mem.Allocator, comptime fmt: string, args: anytype) OOM!string { - return switch (Output.enable_ansi_colors_stderr) { - inline else => |enable_ansi_colors| std.fmt.allocPrint(allocator, Output.prettyFmt(fmt, enable_ansi_colors), args), - }; - } - - /// Shared, non-generic tail for the `add*Fmt` family. The public wrappers - /// are `inline` and only do the per-call-site `allocPrint(fmt, args)`; the - /// rest (counter bump, rangeData, cloneLineText, addMsg) lives here so it - /// isn't re-stamped for every distinct format string. ~165 callers of - /// `addErrorFmt` alone used to duplicate this body. - noinline fn addFormattedMsg( - log: *Log, - kind: Kind, - source: ?*const Source, - r: Range, - text: string, - notes: []Data, - clone: bool, - redact: bool, - ) OOM!void { - @branchHint(.cold); - switch (kind) { - .err => log.errors += 1, - .warn => log.warnings += 1, - else => {}, - } - var data = rangeData(source, r, text); - if (clone) data = try data.cloneLineText(log.clone_line_text, log.msgs.allocator); - try log.addMsg(.{ - .kind = kind, - .data = data, - .notes = notes, - .redact_sensitive_information = redact, - }); - } - - inline fn addResolveErrorWithLevel( - log: *Log, - source: ?*const Source, - r: Range, - allocator: std.mem.Allocator, - comptime fmt: string, - args: anytype, - import_kind: ImportKind, - comptime dupe_text: bool, - comptime kind: enum { err, warn }, - err: anyerror, - ) OOM!void { - const text = try allocPrint(allocator, fmt, args); - // TODO: fix this. this is stupid, it should be returned in allocPrint. - const specifier = BabyString.in(text, args.@"0"); - if (comptime kind == .err) { - log.errors += 1; - } else { - log.warnings += 1; - } - - const data = if (comptime dupe_text) brk: { - var _data = rangeData( - source, - r, - text, - ); - if (_data.location != null) { - if (_data.location.?.line_text) |line| { - _data.location.?.line_text = try allocator.dupe(u8, line); - } - } - break :brk _data; - } else rangeData( - source, - r, - text, - ); - - const msg = Msg{ - // .kind = if (comptime error_type == .err) Kind.err else Kind.warn, - .kind = @field(Kind, @tagName(kind)), - .data = data, - .metadata = .{ .resolve = Msg.Metadata.Resolve{ - .specifier = specifier, - .import_kind = import_kind, - .err = err, - } }, - }; - - try log.addMsg(msg); - } - - pub fn addResolveError( - log: *Log, - source: ?*const Source, - r: Range, - allocator: std.mem.Allocator, - comptime fmt: string, - args: anytype, - import_kind: ImportKind, - err: anyerror, - ) OOM!void { - @branchHint(.cold); - // Always dupe the line_text from the source to ensure the Location data - // outlives the source's backing memory (which may be arena-allocated). - return try addResolveErrorWithLevel(log, source, r, allocator, fmt, args, import_kind, true, .err, err); - } - - pub fn addResolveErrorWithTextDupe( - log: *Log, - source: ?*const Source, - r: Range, - allocator: std.mem.Allocator, - comptime fmt: string, - args: anytype, - import_kind: ImportKind, - ) OOM!void { - @branchHint(.cold); - return try addResolveErrorWithLevel(log, source, r, allocator, fmt, args, import_kind, true, .err, error.ModuleNotFound); - } - - pub fn addRangeError(log: *Log, source: ?*const Source, r: Range, text: string) OOM!void { - @branchHint(.cold); - log.errors += 1; - try log.addMsg(.{ - .kind = .err, - .data = rangeData(source, r, text), - }); - } - - pub inline fn addRangeErrorFmt(log: *Log, source: ?*const Source, r: Range, allocator: std.mem.Allocator, comptime text: string, args: anytype) OOM!void { - return log.addFormattedMsg(.err, source, r, try allocPrint(allocator, text, args), &.{}, true, false); - } - - pub inline fn addRangeErrorFmtWithNotes(log: *Log, source: ?*const Source, r: Range, allocator: std.mem.Allocator, notes: []Data, comptime fmt: string, args: anytype) OOM!void { - return log.addFormattedMsg(.err, source, r, try allocPrint(allocator, fmt, args), notes, true, false); - } - - pub inline fn addErrorFmt(log: *Log, source: ?*const Source, l: Loc, allocator: std.mem.Allocator, comptime text: string, args: anytype) OOM!void { - return log.addFormattedMsg(.err, source, .{ .loc = l }, try allocPrint(allocator, text, args), &.{}, true, false); - } - - // TODO(dylan-conway): rename and replace `addErrorFmt` - pub inline fn addErrorFmtOpts(log: *Log, allocator: std.mem.Allocator, comptime fmt: string, args: anytype, opts: AddErrorOptions) OOM!void { - return log.addFormattedMsg(.err, opts.source, .{ .loc = opts.loc, .len = opts.len }, try allocPrint(allocator, fmt, args), &.{}, true, opts.redact_sensitive_information); - } - - // Use a bun.sys.Error's message in addition to some extra context. - pub fn addSysError(log: *Log, alloc: std.mem.Allocator, e: bun.sys.Error, comptime fmt: string, args: anytype) OOM!void { - const tag_name, const sys_errno = e.getErrorCodeTagName() orelse { - try log.addErrorFmt(null, Loc.Empty, alloc, fmt, args); - return; - }; - try log.addErrorFmt( - null, - Loc.Empty, - alloc, - "{s}: " ++ fmt, - .{bun.sys.coreutils_error_map.get(sys_errno) orelse tag_name} ++ args, - ); - } - - pub fn addZigErrorWithNote(log: *Log, allocator: std.mem.Allocator, err: anyerror, comptime noteFmt: string, args: anytype) OOM!void { - @branchHint(.cold); - log.errors += 1; - - var notes = try allocator.alloc(Data, 1); - notes[0] = rangeData(null, Range.None, try allocPrint(allocator, noteFmt, args)); - - try log.addMsg(.{ - .kind = .err, - .data = rangeData(null, Range.None, @errorName(err)), - .notes = notes, - }); - } - - pub fn addRangeWarning(log: *Log, source: ?*const Source, r: Range, text: string) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.warn, log.level)) return; - log.warnings += 1; - try log.addMsg(.{ - .kind = .warn, - .data = try rangeData(source, r, text).cloneLineText(log.clone_line_text, log.msgs.allocator), - }); - } - - pub inline fn addWarningFmt(log: *Log, source: ?*const Source, l: Loc, allocator: std.mem.Allocator, comptime text: string, args: anytype) OOM!void { - if (!Kind.shouldPrint(.warn, log.level)) return; - return log.addFormattedMsg(.warn, source, .{ .loc = l }, try allocPrint(allocator, text, args), &.{}, true, false); - } - - pub fn addWarningFmtLineCol(log: *Log, filepath: []const u8, line: u32, col: u32, allocator: std.mem.Allocator, comptime text: string, args: anytype) OOM!void { - @branchHint(.cold); - return log.addWarningFmtLineColWithNotes(filepath, line, col, allocator, text, args, &[_]Data{}); - } - - pub fn addWarningFmtLineColWithNotes(log: *Log, filepath: []const u8, line: u32, col: u32, allocator: std.mem.Allocator, comptime text: string, args: anytype, notes: []Data) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.warn, log.level)) return; - log.warnings += 1; - - // TODO: do this properly - - try log.addMsg(.{ - .kind = .warn, - .data = try Data.cloneLineText( - Data{ - .text = try allocPrint(allocator, text, args), - .location = Location{ - .file = filepath, - .line = @intCast(line), - .column = @intCast(col), - }, - }, - log.clone_line_text, - allocator, - ), - .notes = notes, - }); - } - - // pub fn addWarningFmtLineColWithNote(log: *Log, filepath: []const u8, line: u32, col: u32, allocator: std.mem.Allocator, comptime text: string, args: anytype, comptime note_fmt: string, note_args: anytype, note_range: Range) OOM!void { - // @branchHint(.cold); - // if (!Kind.shouldPrint(.warn, log.level)) return; - // log.warnings += 1; - - // var notes = try allocator.alloc(Data, 1); - // notes[0] = Data{ - // .text = try allocPrint(allocator, note_fmt, note_args), - // .lcoation = Location{ - // .file = filepath, - // .line = @intCast(line), - // .column = @intCast(col), - // }, - // }; - - // try log.addMsg(.{ - // .kind = .warn, - // .data = try Data.cloneLineText( - // Data{ - // .text = try allocPrint(allocator, text, args), - // .location = Location{ - // .file = filepath, - // .line = @intCast(line), - // .column = @intCast(col), - // }, - // }, - // log.clone_line_text, - // allocator, - // ), - // .notes = notes, - // }); - // } - - pub inline fn addRangeWarningFmt(log: *Log, source: ?*const Source, r: Range, allocator: std.mem.Allocator, comptime text: string, args: anytype) OOM!void { - if (!Kind.shouldPrint(.warn, log.level)) return; - return log.addFormattedMsg(.warn, source, r, try allocPrint(allocator, text, args), &.{}, true, false); - } - - pub fn addRangeWarningFmtWithNote( - log: *Log, - source: ?*const Source, - r: Range, - allocator: std.mem.Allocator, - comptime fmt: string, - args: anytype, - comptime note_fmt: string, - note_args: anytype, - note_range: Range, - ) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.warn, log.level)) return; - log.warnings += 1; - - var notes = try allocator.alloc(Data, 1); - notes[0] = rangeData(source, note_range, try allocPrint(allocator, note_fmt, note_args)); - - try log.addMsg(.{ - .kind = .warn, - .data = rangeData(source, r, try allocPrint(allocator, fmt, args)), - .notes = notes, - }); - } - - pub inline fn addRangeWarningFmtWithNotes(log: *Log, source: ?*const Source, r: Range, allocator: std.mem.Allocator, notes: []Data, comptime fmt: string, args: anytype) OOM!void { - return log.addFormattedMsg(.warn, source, r, try allocPrint(allocator, fmt, args), notes, true, false); - } - - pub fn addRangeErrorFmtWithNote( - log: *Log, - source: ?*const Source, - r: Range, - allocator: std.mem.Allocator, - comptime fmt: string, - args: anytype, - comptime note_fmt: string, - note_args: anytype, - note_range: Range, - ) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.err, log.level)) return; - log.errors += 1; - - var notes = try allocator.alloc(Data, 1); - notes[0] = rangeData(source, note_range, try allocPrint(allocator, note_fmt, note_args)); - - try log.addMsg(.{ - .kind = .err, - .data = rangeData(source, r, try allocPrint(allocator, fmt, args)), - .notes = notes, - }); - } - - pub fn addWarning(log: *Log, source: ?*const Source, l: Loc, text: string) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.warn, log.level)) return; - log.warnings += 1; - try log.addMsg(.{ - .kind = .warn, - .data = rangeData(source, Range{ .loc = l }, text), - }); - } - - pub fn addWarningWithNote(log: *Log, source: ?*const Source, l: Loc, allocator: std.mem.Allocator, warn: string, comptime note_fmt: string, note_args: anytype) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.warn, log.level)) return; - log.warnings += 1; - - var notes = try allocator.alloc(Data, 1); - notes[0] = rangeData(source, Range{ .loc = l }, try allocPrint(allocator, note_fmt, note_args)); - - try log.addMsg(.{ - .kind = .warn, - .data = rangeData(null, Range.None, warn), - .notes = notes, - }); - } - - pub fn addRangeDebug(log: *Log, source: ?*const Source, r: Range, text: string) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.debug, log.level)) return; - try log.addMsg(.{ - .kind = .debug, - .data = rangeData(source, r, text), - }); - } - - pub fn addRangeDebugWithNotes(log: *Log, source: ?*const Source, r: Range, text: string, notes: []Data) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.debug, log.level)) return; - // log.de += 1; - try log.addMsg(.{ - .kind = Kind.debug, - .data = rangeData(source, r, text), - .notes = notes, - }); - } - - pub fn addRangeErrorWithNotes(log: *Log, source: ?*const Source, r: Range, text: string, notes: []Data) OOM!void { - @branchHint(.cold); - log.errors += 1; - try log.addMsg(.{ - .kind = Kind.err, - .data = rangeData(source, r, text), - .notes = notes, - }); - } - - pub fn addRangeWarningWithNotes(log: *Log, source: ?*const Source, r: Range, text: string, notes: []Data) OOM!void { - @branchHint(.cold); - if (!Kind.shouldPrint(.warn, log.level)) return; - log.warnings += 1; - try log.addMsg(.{ - .kind = .warning, - .data = rangeData(source, r, text), - .notes = notes, - }); - } - - pub fn addMsg(self: *Log, msg: Msg) OOM!void { - try self.msgs.append(msg); - } - - pub fn addError(self: *Log, _source: ?*const Source, loc: Loc, text: string) OOM!void { - @branchHint(.cold); - self.errors += 1; - try self.addMsg(.{ .kind = .err, .data = rangeData(_source, Range{ .loc = loc }, text) }); - } - - const AddErrorOptions = struct { - source: ?*const Source = null, - loc: Loc = Loc.Empty, - len: i32 = 0, - redact_sensitive_information: bool = false, - }; - - // TODO(dylan-conway): rename and replace `addError` - pub fn addErrorOpts(self: *Log, text: string, opts: AddErrorOptions) OOM!void { - @branchHint(.cold); - self.errors += 1; - try self.addMsg(.{ - .kind = .err, - .data = rangeData(opts.source, .{ .loc = opts.loc, .len = opts.len }, text), - .redact_sensitive_information = opts.redact_sensitive_information, - }); - } - - pub fn addSymbolAlreadyDeclaredError(self: *Log, allocator: std.mem.Allocator, source: *const Source, name: string, new_loc: Loc, old_loc: Loc) OOM!void { - var notes = try allocator.alloc(Data, 1); - notes[0] = rangeData( - source, - source.rangeOfIdentifier(old_loc), - try std.fmt.allocPrint(allocator, "\"{s}\" was originally declared here", .{name}), - ); - - try self.addRangeErrorFmtWithNotes( - source, - source.rangeOfIdentifier(new_loc), - allocator, - notes, - "\"{s}\" has already been declared", - .{name}, - ); - } - - pub fn print(self: *const Log, to: *std.Io.Writer) !void { - return switch (Output.enable_ansi_colors_stderr) { - inline else => |enable_ansi_colors| self.printWithEnableAnsiColors(to, enable_ansi_colors), - }; - } - - pub fn printWithEnableAnsiColors(self: *const Log, to: *std.Io.Writer, comptime enable_ansi_colors: bool) !void { - var needs_newline = false; - if (self.warnings > 0 and self.errors > 0) { - // Print warnings at the top - // errors at the bottom - // This is so if you're reading from a terminal - // and there are a bunch of warnings - // You can more easily see where the errors are - for (self.msgs.items) |*msg| { - if (msg.kind != .err) { - if (msg.kind.shouldPrint(self.level)) { - if (needs_newline) try to.writeAll("\n\n"); - try msg.writeFormat(to, enable_ansi_colors); - needs_newline = true; - } - } - } - - for (self.msgs.items) |*msg| { - if (msg.kind == .err) { - if (msg.kind.shouldPrint(self.level)) { - if (needs_newline) try to.writeAll("\n\n"); - try msg.writeFormat(to, enable_ansi_colors); - needs_newline = true; - } - } - } - } else { - for (self.msgs.items) |*msg| { - if (msg.kind.shouldPrint(self.level)) { - if (needs_newline) try to.writeAll("\n\n"); - try msg.writeFormat(to, enable_ansi_colors); - needs_newline = true; - } - } - } - - if (needs_newline) _ = try to.write("\n"); - } -}; - -pub inline fn usize2Loc(loc: usize) Loc { - return Loc{ .start = @as(i32, @intCast(loc)) }; -} - -pub const Source = struct { - path: fs.Path, - - contents: string, - contents_is_recycled: bool = false, - - /// Lazily-generated human-readable identifier name that is non-unique - /// Avoid accessing this directly most of the time - identifier_name: string = "", - - index: Index = Index.source(0), - - pub fn fmtIdentifier(this: *const Source) bun.fmt.FormatValidIdentifier { - return this.path.name.fmtIdentifier(); - } - - pub fn identifierName(this: *Source, allocator: std.mem.Allocator) !string { - if (this.identifier_name.len > 0) { - return this.identifier_name; - } - - bun.assert(this.path.text.len > 0); - const name = try this.path.name.nonUniqueNameString(allocator); - this.identifier_name = name; - return name; - } - - pub fn rangeOfIdentifier(this: *const Source, loc: Loc) Range { - const js_lexer = @import("../js_parser/lexer.zig"); - return js_lexer.rangeOfIdentifier(this, loc); - } - - pub fn isWebAssembly(this: *const Source) bool { - if (this.contents.len < 4) return false; - - const bytes = @as(u32, @bitCast(this.contents[0..4].*)); - return bytes == 0x6d736100; // "\0asm" - } - - pub const ErrorPosition = struct { - line_start: usize, - line_end: usize, - column_count: usize, - line_count: usize, - }; - - pub fn initEmptyFile(filepath: string) Source { - const path = fs.Path.init(filepath); - return Source{ .path = path, .contents = "" }; - } - - pub fn initFile(file: fs.PathContentsPair, _: std.mem.Allocator) !Source { - var source = Source{ - .path = file.path, - .contents = file.contents, - }; - source.path.namespace = "file"; - return source; - } - - pub fn initRecycledFile(file: fs.PathContentsPair, _: std.mem.Allocator) !Source { - var source = Source{ - .path = file.path, - .contents = file.contents, - .contents_is_recycled = true, - }; - source.path.namespace = "file"; - - return source; - } - - pub fn initPathString(pathString: string, contents: string) Source { - const path = fs.Path.init(pathString); - return Source{ .path = path, .contents = contents }; - } - - pub fn textForRange(self: *const Source, r: Range) string { - return self.contents[r.loc.i()..r.endI()]; - } - - pub fn rangeOfOperatorBefore(self: *const Source, loc: Loc, op: string) Range { - const text = self.contents[0..loc.i()]; - const index = strings.index(text, op); - if (index >= 0) { - return Range{ .loc = Loc{ - .start = loc.start + index, - }, .len = @as(i32, @intCast(op.len)) }; - } - - return Range{ .loc = loc }; - } - - pub fn rangeOfString(self: *const Source, loc: Loc) Range { - if (loc.start < 0) return Range.None; - - const text = self.contents[loc.i()..]; - - if (text.len == 0) { - return Range.None; - } - - const quote = text[0]; - - if (quote == '"' or quote == '\'') { - var i: usize = 1; - var c: u8 = 0; - while (i < text.len) { - c = text[i]; - - if (c == quote) { - return Range{ .loc = loc, .len = @as(i32, @intCast(i + 1)) }; - } else if (c == '\\') { - i += 1; - } - i += 1; - } - } - - return Range{ .loc = loc, .len = 0 }; - } - - pub fn rangeOfOperatorAfter(self: *const Source, loc: Loc, op: string) Range { - const text = self.contents[loc.i()..]; - const index = strings.index(text, op); - if (index >= 0) { - return Range{ .loc = Loc{ - .start = loc.start + index, - }, .len = op.len }; - } - - return Range{ .loc = loc }; - } - - pub fn initErrorPosition(self: *const Source, offset_loc: Loc) ErrorPosition { - bun.assert(!offset_loc.isEmpty()); - var prev_code_point: i32 = 0; - const offset: usize = @min(@as(usize, @intCast(offset_loc.start)), @max(self.contents.len, 1) - 1); - - const contents = self.contents; - - var iter_ = strings.CodepointIterator{ - .bytes = self.contents[0..offset], - .i = 0, - }; - var iter = strings.CodepointIterator.Cursor{}; - - var line_start: usize = 0; - var line_count: usize = 1; - var column_number: usize = 1; - - while (iter_.next(&iter)) { - switch (iter.c) { - '\n' => { - column_number = 1; - line_start = iter.width + iter.i; - if (prev_code_point != '\r') { - line_count += 1; - } - }, - - '\r' => { - column_number = 0; - line_start = iter.width + iter.i; - line_count += 1; - }, - - 0x2028, 0x2029 => { - line_start = iter.width + iter.i; // These take three bytes to encode in UTF-8 - line_count += 1; - column_number = 1; - }, - else => { - column_number += 1; - }, - } - - prev_code_point = iter.c; - } - - iter_ = strings.CodepointIterator{ - .bytes = self.contents[offset..], - .i = 0, - }; - - iter = strings.CodepointIterator.Cursor{}; - // Scan to the end of the line (or end of file if this is the last line) - var line_end: usize = contents.len; - - loop: while (iter_.next(&iter)) { - switch (iter.c) { - '\r', '\n', 0x2028, 0x2029 => { - line_end = offset + iter.i; - break :loop; - }, - else => {}, - } - } - - return ErrorPosition{ - .line_start = if (line_start > 0) line_start - 1 else line_start, - .line_end = line_end, - .line_count = line_count, - .column_count = column_number, - }; - } - pub fn lineColToByteOffset(source_contents: []const u8, start_line: usize, start_col: usize, line: usize, col: usize) ?usize { - var iter_ = strings.CodepointIterator{ - .bytes = source_contents, - .i = 0, - }; - var iter = strings.CodepointIterator.Cursor{}; - - var line_count: usize = start_line; - var column_number: usize = start_col; - - _ = iter_.next(&iter); - while (true) { - const c = iter.c; - if (!iter_.next(&iter)) break; - switch (c) { - '\n' => { - column_number = 1; - line_count += 1; - }, - - '\r' => { - column_number = 1; - line_count += 1; - if (iter.c == '\n') { - _ = iter_.next(&iter); - } - }, - - 0x2028, 0x2029 => { - line_count += 1; - column_number = 1; - }, - else => { - column_number += 1; - }, - } - - if (line_count == line and column_number == col) return iter.i; - if (line_count > line) return null; - } - return null; - } -}; - -pub fn rangeData(source: ?*const Source, r: Range, text: string) Data { - return Data{ .text = text, .location = Location.initOrNull(source, r) }; -} - -const string = []const u8; - -const fs = @import("../resolver/fs.zig"); -const std = @import("std"); -const ImportKind = @import("../options_types/import_record.zig").ImportKind; - -const bun = @import("bun"); -const Environment = bun.Environment; -const OOM = bun.OOM; -const Output = bun.Output; -const StringBuilder = bun.StringBuilder; -const assert = bun.assert; -const strings = bun.strings; -const Index = bun.ast.Index; -const api = bun.schema.api; diff --git a/src/ast/new_store.zig b/src/ast/new_store.zig deleted file mode 100644 index ebf11dcf7b22..000000000000 --- a/src/ast/new_store.zig +++ /dev/null @@ -1,171 +0,0 @@ -/// This "Store" is a specialized memory allocation strategy very similar to an -/// arena, used for allocating expression and statement nodes during JavaScript -/// parsing and visiting. Allocations are grouped into large blocks, where each -/// block is treated as a fixed-buffer allocator. When a block runs out of -/// space, a new one is created; all blocks are joined as a linked list. -/// -/// Similarly to an arena, you can call .reset() to reset state, reusing memory -/// across operations. -pub fn NewStore(comptime types: []const type, comptime count: usize) type { - const largest_size, const largest_align = brk: { - var largest_size = 0; - var largest_align = 1; - for (types) |T| { - if (@sizeOf(T) == 0) { - @compileError("NewStore does not support 0 size type: " ++ @typeName(T)); - } - largest_size = @max(@sizeOf(T), largest_size); - largest_align = @max(@alignOf(T), largest_align); - } - break :brk .{ largest_size, largest_align }; - }; - - const backing_allocator = bun.default_allocator; - - const log = Output.scoped(.Store, .hidden); - - return struct { - const Store = @This(); - - current: *Block, - debug_lock: std.debug.SafetyLock = .{}, - - pub const Block = struct { - pub const size = largest_size * count * 2; - pub const Size = std.math.IntFittingRange(0, size + largest_size); - - buffer: [size]u8 align(largest_align), - bytes_used: Size = 0, - next: ?*Block = null, - - pub inline fn zero(this: *Block) void { - // Avoid initializing the entire struct. - this.bytes_used = 0; - this.next = null; - } - - pub fn tryAlloc(block: *Block, comptime T: type) ?*T { - const start = std.mem.alignForward(usize, block.bytes_used, @alignOf(T)); - if (start + @sizeOf(T) > block.buffer.len) return null; - defer block.bytes_used = @intCast(start + @sizeOf(T)); - - // it's simpler to use @ptrCast, but as a sanity check, we also - // try to compute the slice. Zig will report an out of bounds - // panic if the null detection logic above is wrong - if (Environment.isDebug) { - _ = block.buffer[block.bytes_used..][0..@sizeOf(T)]; - } - - return @ptrCast(@alignCast(&block.buffer[start])); - } - }; - - const PreAlloc = struct { - metadata: Store, - first_block: Block, - - pub inline fn zero(this: *PreAlloc) void { - // Avoid initializing the entire struct. - this.first_block.zero(); - this.metadata.current = &this.first_block; - } - }; - - pub fn firstBlock(store: *Store) *Block { - return &@as(*PreAlloc, @fieldParentPtr("metadata", store)).first_block; - } - - pub fn init() *Store { - log("init", .{}); - // Avoid initializing the entire struct. - const prealloc = bun.handleOom(backing_allocator.create(PreAlloc)); - prealloc.zero(); - - return &prealloc.metadata; - } - - pub fn deinit(store: *Store) void { - log("deinit", .{}); - var it = store.firstBlock().next; // do not free `store.head` - while (it) |next| { - if (Environment.isDebug or Environment.enable_asan) - @memset(next.buffer, undefined); - it = next.next; - backing_allocator.destroy(next); - } - - const prealloc: PreAlloc = @fieldParentPtr("metadata", store); - bun.assert(&prealloc.first_block == store.head); - backing_allocator.destroy(prealloc); - } - - pub fn reset(store: *Store) void { - log("reset", .{}); - - if (Environment.isDebug or Environment.enable_asan) { - var it: ?*Block = store.firstBlock(); - while (it) |next| : (it = next.next) { - next.bytes_used = undefined; - @memset(&next.buffer, undefined); - } - } - - store.current = store.firstBlock(); - store.current.bytes_used = 0; - } - - fn allocate(store: *Store, comptime T: type) *T { - comptime bun.assert(@sizeOf(T) > 0); // don't allocate! - comptime if (!supportsType(T)) { - @compileError("Store does not know about type: " ++ @typeName(T)); - }; - - if (store.current.tryAlloc(T)) |ptr| - return ptr; - - // a new block is needed - const next_block = if (store.current.next) |next| brk: { - next.bytes_used = 0; - break :brk next; - } else brk: { - const new_block = backing_allocator.create(Block) catch - bun.outOfMemory(); - new_block.zero(); - store.current.next = new_block; - break :brk new_block; - }; - - store.current = next_block; - - return next_block.tryAlloc(T) orelse - unreachable; // newly initialized blocks must have enough space for at least one - } - - pub inline fn append(store: *Store, comptime T: type, data: T) *T { - const ptr = store.allocate(T); - if (Environment.isDebug) { - log("append({s}) -> 0x{x}", .{ bun.meta.typeName(T), @intFromPtr(ptr) }); - } - ptr.* = data; - return ptr; - } - - pub fn lock(store: *Store) void { - store.debug_lock.lock(); - } - - pub fn unlock(store: *Store) void { - store.debug_lock.unlock(); - } - - fn supportsType(T: type) bool { - return std.mem.indexOfScalar(type, types, T) != null; - } - }; -} - -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const Output = bun.Output; diff --git a/src/ast/op.zig b/src/ast/op.zig deleted file mode 100644 index 7c259987478d..000000000000 --- a/src/ast/op.zig +++ /dev/null @@ -1,291 +0,0 @@ -// If you add a new token, remember to add it to "Table" too -pub const Code = enum { - // Prefix - un_pos, // +expr - un_neg, // -expr - un_cpl, // ~expr - un_not, // !expr - un_void, - un_typeof, - un_delete, - - // Prefix update - un_pre_dec, - un_pre_inc, - - // Postfix update - un_post_dec, - un_post_inc, - - /// Left-associative - bin_add, - /// Left-associative - bin_sub, - /// Left-associative - bin_mul, - /// Left-associative - bin_div, - /// Left-associative - bin_rem, - /// Left-associative - bin_pow, - /// Left-associative - bin_lt, - /// Left-associative - bin_le, - /// Left-associative - bin_gt, - /// Left-associative - bin_ge, - /// Left-associative - bin_in, - /// Left-associative - bin_instanceof, - /// Left-associative - bin_shl, - /// Left-associative - bin_shr, - /// Left-associative - bin_u_shr, - /// Left-associative - bin_loose_eq, - /// Left-associative - bin_loose_ne, - /// Left-associative - bin_strict_eq, - /// Left-associative - bin_strict_ne, - /// Left-associative - bin_nullish_coalescing, - /// Left-associative - bin_logical_or, - /// Left-associative - bin_logical_and, - /// Left-associative - bin_bitwise_or, - /// Left-associative - bin_bitwise_and, - /// Left-associative - bin_bitwise_xor, - - /// Non-associative - bin_comma, - - /// Right-associative - bin_assign, - /// Right-associative - bin_add_assign, - /// Right-associative - bin_sub_assign, - /// Right-associative - bin_mul_assign, - /// Right-associative - bin_div_assign, - /// Right-associative - bin_rem_assign, - /// Right-associative - bin_pow_assign, - /// Right-associative - bin_shl_assign, - /// Right-associative - bin_shr_assign, - /// Right-associative - bin_u_shr_assign, - /// Right-associative - bin_bitwise_or_assign, - /// Right-associative - bin_bitwise_and_assign, - /// Right-associative - bin_bitwise_xor_assign, - /// Right-associative - bin_nullish_coalescing_assign, - /// Right-associative - bin_logical_or_assign, - /// Right-associative - bin_logical_and_assign, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - - pub fn unaryAssignTarget(code: Op.Code) AssignTarget { - if (@intFromEnum(code) >= - @intFromEnum(Op.Code.un_pre_dec) and @intFromEnum(code) <= - @intFromEnum(Op.Code.un_post_inc)) - { - return AssignTarget.update; - } - - return AssignTarget.none; - } - pub fn isLeftAssociative(code: Op.Code) bool { - return @intFromEnum(code) >= - @intFromEnum(Op.Code.bin_add) and - @intFromEnum(code) < @intFromEnum(Op.Code.bin_comma) and code != .bin_pow; - } - pub fn isRightAssociative(code: Op.Code) bool { - return @intFromEnum(code) >= @intFromEnum(Op.Code.bin_assign) or code == .bin_pow; - } - pub fn binaryAssignTarget(code: Op.Code) AssignTarget { - if (code == .bin_assign) { - return AssignTarget.replace; - } - - if (@intFromEnum(code) > @intFromEnum(Op.Code.bin_assign)) { - return AssignTarget.update; - } - - return AssignTarget.none; - } - - pub fn isPrefix(code: Op.Code) bool { - return @intFromEnum(code) < @intFromEnum(Op.Code.un_post_dec); - } -}; - -pub const Level = enum(u6) { - lowest, - comma, - spread, - yield, - assign, - conditional, - nullish_coalescing, - logical_or, - logical_and, - bitwise_or, - bitwise_xor, - bitwise_and, - equals, - compare, - shift, - add, - multiply, - exponentiation, - prefix, - postfix, - new, - call, - member, - - pub inline fn lt(self: Level, b: Level) bool { - return @intFromEnum(self) < @intFromEnum(b); - } - pub inline fn gt(self: Level, b: Level) bool { - return @intFromEnum(self) > @intFromEnum(b); - } - pub inline fn gte(self: Level, b: Level) bool { - return @intFromEnum(self) >= @intFromEnum(b); - } - pub inline fn lte(self: Level, b: Level) bool { - return @intFromEnum(self) <= @intFromEnum(b); - } - pub inline fn eql(self: Level, b: Level) bool { - return @intFromEnum(self) == @intFromEnum(b); - } - - pub inline fn sub(self: Level, i: anytype) Level { - return @as(Level, @enumFromInt(@intFromEnum(self) - i)); - } - - pub inline fn addF(self: Level, i: anytype) Level { - return @as(Level, @enumFromInt(@intFromEnum(self) + i)); - } -}; - -text: string, -level: Level, -is_keyword: bool = false, - -pub fn init(triple: anytype) Op { - return Op{ - .text = triple.@"0", - .level = triple.@"1", - .is_keyword = triple.@"2", - }; -} - -pub fn jsonStringify(self: *const @This(), writer: anytype) !void { - return try writer.write(self.text); -} - -pub const TableType: std.EnumArray(Op.Code, Op) = undefined; -pub const Table = brk: { - var table = std.EnumArray(Op.Code, Op).initUndefined(); - - // Prefix - table.set(Op.Code.un_pos, Op.init(.{ "+", Level.prefix, false })); - table.set(Op.Code.un_neg, Op.init(.{ "-", Level.prefix, false })); - table.set(Op.Code.un_cpl, Op.init(.{ "~", Level.prefix, false })); - table.set(Op.Code.un_not, Op.init(.{ "!", Level.prefix, false })); - table.set(Op.Code.un_void, Op.init(.{ "void", Level.prefix, true })); - table.set(Op.Code.un_typeof, Op.init(.{ "typeof", Level.prefix, true })); - table.set(Op.Code.un_delete, Op.init(.{ "delete", Level.prefix, true })); - - // Prefix update - table.set(Op.Code.un_pre_dec, Op.init(.{ "--", Level.prefix, false })); - table.set(Op.Code.un_pre_inc, Op.init(.{ "++", Level.prefix, false })); - - // Postfix update - table.set(Op.Code.un_post_dec, Op.init(.{ "--", Level.postfix, false })); - table.set(Op.Code.un_post_inc, Op.init(.{ "++", Level.postfix, false })); - - // Left-associative - table.set(Op.Code.bin_add, Op.init(.{ "+", Level.add, false })); - table.set(Op.Code.bin_sub, Op.init(.{ "-", Level.add, false })); - table.set(Op.Code.bin_mul, Op.init(.{ "*", Level.multiply, false })); - table.set(Op.Code.bin_div, Op.init(.{ "/", Level.multiply, false })); - table.set(Op.Code.bin_rem, Op.init(.{ "%", Level.multiply, false })); - table.set(Op.Code.bin_pow, Op.init(.{ "**", Level.exponentiation, false })); - table.set(Op.Code.bin_lt, Op.init(.{ "<", Level.compare, false })); - table.set(Op.Code.bin_le, Op.init(.{ "<=", Level.compare, false })); - table.set(Op.Code.bin_gt, Op.init(.{ ">", Level.compare, false })); - table.set(Op.Code.bin_ge, Op.init(.{ ">=", Level.compare, false })); - table.set(Op.Code.bin_in, Op.init(.{ "in", Level.compare, true })); - table.set(Op.Code.bin_instanceof, Op.init(.{ "instanceof", Level.compare, true })); - table.set(Op.Code.bin_shl, Op.init(.{ "<<", Level.shift, false })); - table.set(Op.Code.bin_shr, Op.init(.{ ">>", Level.shift, false })); - table.set(Op.Code.bin_u_shr, Op.init(.{ ">>>", Level.shift, false })); - table.set(Op.Code.bin_loose_eq, Op.init(.{ "==", Level.equals, false })); - table.set(Op.Code.bin_loose_ne, Op.init(.{ "!=", Level.equals, false })); - table.set(Op.Code.bin_strict_eq, Op.init(.{ "===", Level.equals, false })); - table.set(Op.Code.bin_strict_ne, Op.init(.{ "!==", Level.equals, false })); - table.set(Op.Code.bin_nullish_coalescing, Op.init(.{ "??", Level.nullish_coalescing, false })); - table.set(Op.Code.bin_logical_or, Op.init(.{ "||", Level.logical_or, false })); - table.set(Op.Code.bin_logical_and, Op.init(.{ "&&", Level.logical_and, false })); - table.set(Op.Code.bin_bitwise_or, Op.init(.{ "|", Level.bitwise_or, false })); - table.set(Op.Code.bin_bitwise_and, Op.init(.{ "&", Level.bitwise_and, false })); - table.set(Op.Code.bin_bitwise_xor, Op.init(.{ "^", Level.bitwise_xor, false })); - - // Non-associative - table.set(Op.Code.bin_comma, Op.init(.{ ",", Level.comma, false })); - - // Right-associative - table.set(Op.Code.bin_assign, Op.init(.{ "=", Level.assign, false })); - table.set(Op.Code.bin_add_assign, Op.init(.{ "+=", Level.assign, false })); - table.set(Op.Code.bin_sub_assign, Op.init(.{ "-=", Level.assign, false })); - table.set(Op.Code.bin_mul_assign, Op.init(.{ "*=", Level.assign, false })); - table.set(Op.Code.bin_div_assign, Op.init(.{ "/=", Level.assign, false })); - table.set(Op.Code.bin_rem_assign, Op.init(.{ "%=", Level.assign, false })); - table.set(Op.Code.bin_pow_assign, Op.init(.{ "**=", Level.assign, false })); - table.set(Op.Code.bin_shl_assign, Op.init(.{ "<<=", Level.assign, false })); - table.set(Op.Code.bin_shr_assign, Op.init(.{ ">>=", Level.assign, false })); - table.set(Op.Code.bin_u_shr_assign, Op.init(.{ ">>>=", Level.assign, false })); - table.set(Op.Code.bin_bitwise_or_assign, Op.init(.{ "|=", Level.assign, false })); - table.set(Op.Code.bin_bitwise_and_assign, Op.init(.{ "&=", Level.assign, false })); - table.set(Op.Code.bin_bitwise_xor_assign, Op.init(.{ "^=", Level.assign, false })); - table.set(Op.Code.bin_nullish_coalescing_assign, Op.init(.{ "??=", Level.assign, false })); - table.set(Op.Code.bin_logical_or_assign, Op.init(.{ "||=", Level.assign, false })); - table.set(Op.Code.bin_logical_and_assign, Op.init(.{ "&&=", Level.assign, false })); - - break :brk table; -}; - -const string = []const u8; - -const bun = @import("bun"); -const std = @import("std"); - -const js_ast = bun.ast; -const AssignTarget = js_ast.AssignTarget; -const Op = js_ast.Op; diff --git a/src/ast/s.zig b/src/ast/s.zig deleted file mode 100644 index 372cb322169d..000000000000 --- a/src/ast/s.zig +++ /dev/null @@ -1,237 +0,0 @@ -pub const Block = struct { - stmts: StmtNodeList, - close_brace_loc: logger.Loc = logger.Loc.Empty, -}; - -pub const SExpr = struct { - value: ExprNodeIndex, - - // This is set to true for automatically-generated expressions that should - // not affect tree shaking. For example, calling a function from the runtime - // that doesn't have externally-visible side effects. - does_not_affect_tree_shaking: bool = false, -}; - -pub const Comment = struct { text: string }; - -pub const Directive = struct { - value: []const u8, -}; - -pub const ExportClause = struct { - items: []ClauseItem, - is_single_line: bool, -}; - -pub const Empty = struct {}; - -pub const ExportStar = struct { - namespace_ref: Ref, - alias: ?G.ExportStarAlias = null, - import_record_index: u32, -}; - -// This is an "export = value;" statement in TypeScript -pub const ExportEquals = struct { value: ExprNodeIndex }; - -pub const Label = struct { name: LocRef, stmt: StmtNodeIndex }; - -// This is a stand-in for a TypeScript type declaration -pub const TypeScript = struct {}; - -pub const Debugger = struct {}; - -pub const ExportFrom = struct { - items: []ClauseItem, - namespace_ref: Ref, - import_record_index: u32, - is_single_line: bool, -}; - -pub const ExportDefault = struct { - default_name: LocRef, // value may be a SFunction or SClass - value: StmtOrExpr, - - pub fn canBeMoved(self: *const ExportDefault) bool { - return switch (self.value) { - .expr => |e| e.canBeMoved(), - .stmt => |s| switch (s.data) { - .s_class => |class| class.class.canBeMoved(), - .s_function => true, - else => false, - }, - }; - } -}; - -pub const Enum = struct { - name: LocRef, - arg: Ref, - values: []EnumValue, - is_export: bool, -}; - -pub const Namespace = struct { - name: LocRef, - arg: Ref, - stmts: StmtNodeList, - is_export: bool, -}; - -pub const Function = struct { - func: G.Fn, -}; - -pub const Class = struct { class: G.Class, is_export: bool = false }; - -pub const If = struct { - test_: ExprNodeIndex, - yes: StmtNodeIndex, - no: ?StmtNodeIndex, -}; - -pub const For = struct { - // May be a SConst, SLet, SVar, or SExpr - init: ?StmtNodeIndex = null, - test_: ?ExprNodeIndex = null, - update: ?ExprNodeIndex = null, - body: StmtNodeIndex, -}; - -pub const ForIn = struct { - // May be a SConst, SLet, SVar, or SExpr - init: StmtNodeIndex, - value: ExprNodeIndex, - body: StmtNodeIndex, -}; - -pub const ForOf = struct { - is_await: bool = false, - // May be a SConst, SLet, SVar, or SExpr - init: StmtNodeIndex, - value: ExprNodeIndex, - body: StmtNodeIndex, -}; - -pub const DoWhile = struct { body: StmtNodeIndex, test_: ExprNodeIndex }; - -pub const While = struct { - test_: ExprNodeIndex, - body: StmtNodeIndex, -}; - -pub const With = struct { - value: ExprNodeIndex, - body: StmtNodeIndex, - body_loc: logger.Loc = logger.Loc.Empty, -}; - -pub const Try = struct { - body_loc: logger.Loc, - body: StmtNodeList, - - catch_: ?Catch = null, - finally: ?Finally = null, -}; - -pub const Switch = struct { - test_: ExprNodeIndex, - body_loc: logger.Loc, - cases: []Case, -}; - -// This object represents all of these types of import statements: -// -// import 'path' -// import {item1, item2} from 'path' -// import * as ns from 'path' -// import defaultItem, {item1, item2} from 'path' -// import defaultItem, * as ns from 'path' -// -// Many parts are optional and can be combined in different ways. The only -// restriction is that you cannot have both a clause and a star namespace. -pub const Import = struct { - // If this is a star import: This is a Ref for the namespace symbol. The Loc - // for the symbol is StarLoc. - // - // Otherwise: This is an auto-generated Ref for the namespace representing - // the imported file. In this case StarLoc is nil. The NamespaceRef is used - // when converting this module to a CommonJS module. - namespace_ref: Ref, - default_name: ?LocRef = null, - items: []ClauseItem = &.{}, - star_name_loc: ?logger.Loc = null, - import_record_index: u32, - is_single_line: bool = false, -}; - -pub const Return = struct { value: ?ExprNodeIndex = null }; -pub const Throw = struct { value: ExprNodeIndex }; - -pub const Local = struct { - kind: Kind = .k_var, - decls: G.Decl.List = .{}, - is_export: bool = false, - // The TypeScript compiler doesn't generate code for "import foo = bar" - // statements where the import is never used. - was_ts_import_equals: bool = false, - - was_commonjs_export: bool = false, - - pub fn canMergeWith(this: *const Local, other: *const Local) bool { - // Don't merge "using" / "await using" declarations. Merging them is - // spec-compliant but matches esbuild's behavior of keeping them - // separate, and avoids any downstream pass assuming one decl per - // `using` statement. - if (this.kind.isUsing()) return false; - return this.kind == other.kind and this.is_export == other.is_export and - this.was_commonjs_export == other.was_commonjs_export; - } - - pub const Kind = enum { - k_var, - k_let, - k_const, - k_using, - k_await_using, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - - pub fn isUsing(self: Kind) bool { - return self == .k_using or self == .k_await_using; - } - - pub fn isReassignable(kind: Kind) bool { - return kind == .k_var or kind == .k_let; - } - }; -}; - -pub const Break = struct { - label: ?LocRef = null, -}; - -pub const Continue = struct { - label: ?LocRef = null, -}; - -const string = []const u8; - -const bun = @import("bun"); -const logger = bun.logger; - -const js_ast = bun.ast; -const Case = js_ast.Case; -const Catch = js_ast.Catch; -const ClauseItem = js_ast.ClauseItem; -const EnumValue = js_ast.EnumValue; -const ExprNodeIndex = js_ast.ExprNodeIndex; -const Finally = js_ast.Finally; -const G = js_ast.G; -const LocRef = js_ast.LocRef; -const Ref = js_ast.Ref; -const StmtNodeIndex = js_ast.StmtNodeIndex; -const StmtNodeList = js_ast.StmtNodeList; -const StmtOrExpr = js_ast.StmtOrExpr; diff --git a/src/ast/scope.zig b/src/ast/scope.zig deleted file mode 100644 index d9e3a0b6daf5..000000000000 --- a/src/ast/scope.zig +++ /dev/null @@ -1,220 +0,0 @@ -pub const MemberHashMap = bun.StringHashMapUnmanaged(Member); - -id: usize = 0, -kind: Kind = Kind.block, -parent: ?*Scope = null, -children: BabyList(*Scope) = .{}, -members: MemberHashMap = .{}, -generated: BabyList(Ref) = .{}, - -// This is used to store the ref of the label symbol for ScopeLabel scopes. -label_ref: ?Ref = null, -label_stmt_is_loop: bool = false, - -// If a scope contains a direct eval() expression, then none of the symbols -// inside that scope can be renamed. We conservatively assume that the -// evaluated code might reference anything that it has access to. -contains_direct_eval: bool = false, - -// This is to help forbid "arguments" inside class body scopes -forbid_arguments: bool = false, - -strict_mode: StrictModeKind = StrictModeKind.sloppy_mode, - -is_after_const_local_prefix: bool = false, - -// This will be non-null if this is a TypeScript "namespace" or "enum" -ts_namespace: ?*TSNamespaceScope = null, - -pub const NestedScopeMap = std.AutoArrayHashMap(u32, bun.BabyList(*Scope)); - -pub fn getMemberHash(name: []const u8) u64 { - return bun.StringHashMapContext.hash(.{}, name); -} - -pub fn getMemberWithHash(this: *const Scope, name: []const u8, hash_value: u64) ?Member { - const hashed = bun.StringHashMapContext.Prehashed{ - .value = hash_value, - .input = name, - }; - return this.members.getAdapted(name, hashed); -} - -pub fn getOrPutMemberWithHash( - this: *Scope, - allocator: std.mem.Allocator, - name: []const u8, - hash_value: u64, -) !MemberHashMap.GetOrPutResult { - const hashed = bun.StringHashMapContext.Prehashed{ - .value = hash_value, - .input = name, - }; - return this.members.getOrPutContextAdapted(allocator, name, hashed, .{}); -} - -pub fn reset(this: *Scope) void { - this.children.clearRetainingCapacity(); - this.generated.clearRetainingCapacity(); - this.members.clearRetainingCapacity(); - this.parent = null; - this.id = 0; - this.label_ref = null; - this.label_stmt_is_loop = false; - this.contains_direct_eval = false; - this.strict_mode = .sloppy_mode; - this.kind = .block; -} - -// Do not make this a packed struct -// Two hours of debugging time lost to that. -// It causes a crash due to undefined memory -pub const Member = struct { - ref: Ref, - loc: logger.Loc, - - pub fn eql(a: Member, b: Member) bool { - return @call(bun.callmod_inline, Ref.eql, .{ a.ref, b.ref }) and a.loc.start == b.loc.start; - } -}; - -pub const SymbolMergeResult = enum { - forbidden, - replace_with_new, - overwrite_with_new, - keep_existing, - become_private_get_set_pair, - become_private_static_get_set_pair, -}; - -pub fn canMergeSymbols( - scope: *Scope, - existing: Symbol.Kind, - new: Symbol.Kind, - comptime is_typescript_enabled: bool, -) SymbolMergeResult { - if (existing == .unbound) { - return .replace_with_new; - } - - if (comptime is_typescript_enabled) { - // In TypeScript, imports are allowed to silently collide with symbols within - // the module. Presumably this is because the imports may be type-only: - // - // import {Foo} from 'bar' - // class Foo {} - // - if (existing == .import) { - return .replace_with_new; - } - - // "enum Foo {} enum Foo {}" - // "namespace Foo { ... } enum Foo {}" - if (new == .ts_enum and (existing == .ts_enum or existing == .ts_namespace)) { - return .replace_with_new; - } - - // "namespace Foo { ... } namespace Foo { ... }" - // "function Foo() {} namespace Foo { ... }" - // "enum Foo {} namespace Foo { ... }" - if (new == .ts_namespace) { - switch (existing) { - .ts_namespace, - .ts_enum, - .hoisted_function, - .generator_or_async_function, - .class, - => return .keep_existing, - else => {}, - } - } - } - - // "var foo; var foo;" - // "var foo; function foo() {}" - // "function foo() {} var foo;" - // "function *foo() {} function *foo() {}" but not "{ function *foo() {} function *foo() {} }" - if (Symbol.isKindHoistedOrFunction(new) and - Symbol.isKindHoistedOrFunction(existing) and - (scope.kind == .entry or scope.kind == .function_body or scope.kind == .function_args or - (new == existing and Symbol.isKindHoisted(existing)))) - { - return .replace_with_new; - } - - // "get #foo() {} set #foo() {}" - // "set #foo() {} get #foo() {}" - if ((existing == .private_get and new == .private_set) or - (existing == .private_set and new == .private_get)) - { - return .become_private_get_set_pair; - } - if ((existing == .private_static_get and new == .private_static_set) or - (existing == .private_static_set and new == .private_static_get)) - { - return .become_private_static_get_set_pair; - } - - // "try {} catch (e) { var e }" - if (existing == .catch_identifier and new == .hoisted) { - return .replace_with_new; - } - - // "function() { var arguments }" - if (existing == .arguments and new == .hoisted) { - return .keep_existing; - } - - // "function() { let arguments }" - if (existing == .arguments and new != .hoisted) { - return .overwrite_with_new; - } - - return .forbidden; -} - -pub const Kind = enum(u8) { - block, - with, - label, - class_name, - class_body, - catch_binding, - - // The scopes below stop hoisted variables from extending into parent scopes - entry, // This is a module, TypeScript enum, or TypeScript namespace - function_args, - function_body, - class_static_init, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } -}; - -pub fn recursiveSetStrictMode(s: *Scope, kind: StrictModeKind) void { - if (s.strict_mode == .sloppy_mode) { - s.strict_mode = kind; - for (s.children.slice()) |child| { - child.recursiveSetStrictMode(kind); - } - } -} - -pub inline fn kindStopsHoisting(s: *const Scope) bool { - return @intFromEnum(s.kind) >= @intFromEnum(Kind.entry); -} - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const logger = bun.logger; - -const js_ast = bun.ast; -const Ref = js_ast.Ref; -const Scope = js_ast.Scope; -const StrictModeKind = js_ast.StrictModeKind; -const Symbol = js_ast.Symbol; -const TSNamespaceScope = js_ast.TSNamespaceScope; -const TypeScript = js_ast.TypeScript; diff --git a/src/ast/server_component_boundary.zig b/src/ast/server_component_boundary.zig deleted file mode 100644 index 5e20cddf8565..000000000000 --- a/src/ast/server_component_boundary.zig +++ /dev/null @@ -1,121 +0,0 @@ -//! Represents a boundary between client and server code. Every boundary -//! gets bundled twice, once for the desired target, and once to generate -//! a module of "references". Specifically, the generated file takes the -//! canonical Ast as input to derive a wrapper. See `Framework.ServerComponents` -//! for more details about this generated file. -//! -//! This is sometimes abbreviated as SCB -use_directive: UseDirective, - -/// The index of the original file. -source_index: Index.Int, - -/// Index to the file imported on the opposite platform, which is -/// generated by the bundler. For client components, this is the -/// server's code. For server actions, this is the client's code. -reference_source_index: Index.Int, - -/// When `bake.Framework.ServerComponents.separate_ssr_graph` is enabled this -/// points to the separated module. When the SSR graph is not separate, this is -/// equal to `reference_source_index` -// -// TODO: Is this used for server actions. -ssr_source_index: Index.Int, - -/// The requirements for this data structure is to have reasonable lookup -/// speed, but also being able to pull a `[]const Index.Int` of all -/// boundaries for iteration. -pub const List = struct { - list: std.MultiArrayList(ServerComponentBoundary) = .{}, - /// Used to facilitate fast lookups into `items` by `.source_index` - map: Map = .{}, - - const Map = std.ArrayHashMapUnmanaged(void, void, struct {}, true); - - /// Can only be called on the bundler thread. - pub fn put( - m: *List, - allocator: std.mem.Allocator, - source_index: Index.Int, - use_directive: UseDirective, - reference_source_index: Index.Int, - ssr_source_index: Index.Int, - ) !void { - try m.list.append(allocator, .{ - .source_index = source_index, - .use_directive = use_directive, - .reference_source_index = reference_source_index, - .ssr_source_index = ssr_source_index, - }); - const gop = try m.map.getOrPutAdapted( - allocator, - source_index, - Adapter{ .list = m.list.slice() }, - ); - bun.assert(!gop.found_existing); - } - - /// Can only be called on the bundler thread. - pub fn getIndex(l: *const List, real_source_index: Index.Int) ?usize { - return l.map.getIndexAdapted( - real_source_index, - Adapter{ .list = l.list.slice() }, - ); - } - - /// Use this to improve speed of accessing fields at the cost of - /// storing more pointers. Invalidated when input is mutated. - pub fn slice(l: List) Slice { - return .{ .list = l.list.slice(), .map = l.map }; - } - - pub const Slice = struct { - list: std.MultiArrayList(ServerComponentBoundary).Slice, - map: Map, - - pub fn getIndex(l: *const Slice, real_source_index: Index.Int) ?usize { - return l.map.getIndexAdapted( - real_source_index, - Adapter{ .list = l.list }, - ) orelse return null; - } - - pub fn getReferenceSourceIndex(l: *const Slice, real_source_index: Index.Int) ?u32 { - const i = l.map.getIndexAdapted( - real_source_index, - Adapter{ .list = l.list }, - ) orelse return null; - bun.unsafeAssert(l.list.capacity > 0); // optimize MultiArrayList.Slice.items - return l.list.items(.reference_source_index)[i]; - } - - pub fn bitSet(scbs: Slice, alloc: std.mem.Allocator, input_file_count: usize) !bun.bit_set.DynamicBitSetUnmanaged { - var scb_bitset = try bun.bit_set.DynamicBitSetUnmanaged.initEmpty(alloc, input_file_count); - for (scbs.list.items(.source_index)) |source_index| { - scb_bitset.set(source_index); - } - return scb_bitset; - } - }; - - pub const Adapter = struct { - list: std.MultiArrayList(ServerComponentBoundary).Slice, - - pub fn hash(_: Adapter, key: Index.Int) u32 { - return std.hash.int(@as(u32, key)); - } - - pub fn eql(adapt: Adapter, a: Index.Int, _: void, b_index: usize) bool { - bun.unsafeAssert(adapt.list.capacity > 0); // optimize MultiArrayList.Slice.items - return a == adapt.list.items(.source_index)[b_index]; - } - }; -}; - -const bun = @import("bun"); -const std = @import("std"); - -const js_ast = bun.ast; -const Index = js_ast.Index; -const ServerComponentBoundary = js_ast.ServerComponentBoundary; -const UseDirective = js_ast.UseDirective; diff --git a/src/ast/stmt.zig b/src/ast/stmt.zig deleted file mode 100644 index 49317adf9057..000000000000 --- a/src/ast/stmt.zig +++ /dev/null @@ -1,423 +0,0 @@ -loc: logger.Loc, -data: Data, - -pub const Batcher = NewBatcher(Stmt); - -pub fn assign(a: Expr, b: Expr) Stmt { - return Stmt.alloc( - S.SExpr, - S.SExpr{ - .value = Expr.assign(a, b), - }, - a.loc, - ); -} - -const Serializable = struct { - type: Tag, - object: string, - value: Data, - loc: logger.Loc, -}; - -pub fn jsonStringify(self: *const Stmt, writer: anytype) !void { - return try writer.write(Serializable{ .type = std.meta.activeTag(self.data), .object = "stmt", .value = self.data, .loc = self.loc }); -} - -pub fn isTypeScript(self: *Stmt) bool { - return @as(Stmt.Tag, self.data) == .s_type_script; -} - -pub fn isSuperCall(self: Stmt) bool { - return self.data == .s_expr and self.data.s_expr.value.data == .e_call and self.data.s_expr.value.data.e_call.target.data == .e_super; -} - -pub fn isMissingExpr(self: Stmt) bool { - return self.data == .s_expr and self.data.s_expr.value.data == .e_missing; -} - -pub fn empty() Stmt { - return Stmt{ .data = .{ .s_empty = None }, .loc = logger.Loc{} }; -} - -pub fn toEmpty(this: Stmt) Stmt { - return .{ - .data = .{ - .s_empty = None, - }, - .loc = this.loc, - }; -} - -const None = S.Empty{}; - -pub var icount: usize = 0; -pub fn init(comptime StatementType: type, origData: *StatementType, loc: logger.Loc) Stmt { - icount += 1; - - return switch (comptime StatementType) { - S.Empty => Stmt{ .loc = loc, .data = Data{ .s_empty = S.Empty{} } }, - S.Block => Stmt.comptime_init("s_block", S.Block, origData, loc), - S.Break => Stmt.comptime_init("s_break", S.Break, origData, loc), - S.Class => Stmt.comptime_init("s_class", S.Class, origData, loc), - S.Comment => Stmt.comptime_init("s_comment", S.Comment, origData, loc), - S.Continue => Stmt.comptime_init("s_continue", S.Continue, origData, loc), - S.Debugger => Stmt.comptime_init("s_debugger", S.Debugger, origData, loc), - S.Directive => Stmt.comptime_init("s_directive", S.Directive, origData, loc), - S.DoWhile => Stmt.comptime_init("s_do_while", S.DoWhile, origData, loc), - S.Enum => Stmt.comptime_init("s_enum", S.Enum, origData, loc), - S.ExportClause => Stmt.comptime_init("s_export_clause", S.ExportClause, origData, loc), - S.ExportDefault => Stmt.comptime_init("s_export_default", S.ExportDefault, origData, loc), - S.ExportEquals => Stmt.comptime_init("s_export_equals", S.ExportEquals, origData, loc), - S.ExportFrom => Stmt.comptime_init("s_export_from", S.ExportFrom, origData, loc), - S.ExportStar => Stmt.comptime_init("s_export_star", S.ExportStar, origData, loc), - S.SExpr => Stmt.comptime_init("s_expr", S.SExpr, origData, loc), - S.ForIn => Stmt.comptime_init("s_for_in", S.ForIn, origData, loc), - S.ForOf => Stmt.comptime_init("s_for_of", S.ForOf, origData, loc), - S.For => Stmt.comptime_init("s_for", S.For, origData, loc), - S.Function => Stmt.comptime_init("s_function", S.Function, origData, loc), - S.If => Stmt.comptime_init("s_if", S.If, origData, loc), - S.Import => Stmt.comptime_init("s_import", S.Import, origData, loc), - S.Label => Stmt.comptime_init("s_label", S.Label, origData, loc), - S.Local => Stmt.comptime_init("s_local", S.Local, origData, loc), - S.Namespace => Stmt.comptime_init("s_namespace", S.Namespace, origData, loc), - S.Return => Stmt.comptime_init("s_return", S.Return, origData, loc), - S.Switch => Stmt.comptime_init("s_switch", S.Switch, origData, loc), - S.Throw => Stmt.comptime_init("s_throw", S.Throw, origData, loc), - S.Try => Stmt.comptime_init("s_try", S.Try, origData, loc), - S.TypeScript => Stmt.comptime_init("s_type_script", S.TypeScript, origData, loc), - S.While => Stmt.comptime_init("s_while", S.While, origData, loc), - S.With => Stmt.comptime_init("s_with", S.With, origData, loc), - else => @compileError("Invalid type in Stmt.init"), - }; -} -inline fn comptime_alloc(comptime tag_name: string, comptime typename: type, origData: anytype, loc: logger.Loc) Stmt { - return Stmt{ - .loc = loc, - .data = @unionInit( - Data, - tag_name, - Data.Store.append( - typename, - origData, - ), - ), - }; -} - -fn allocateData(allocator: std.mem.Allocator, comptime tag_name: string, comptime typename: type, origData: anytype, loc: logger.Loc) Stmt { - const value = allocator.create(@TypeOf(origData)) catch unreachable; - value.* = origData; - - return comptime_init(tag_name, *typename, value, loc); -} - -inline fn comptime_init(comptime tag_name: string, comptime TypeName: type, origData: TypeName, loc: logger.Loc) Stmt { - return Stmt{ .loc = loc, .data = @unionInit(Data, tag_name, origData) }; -} - -pub fn alloc(comptime StatementData: type, origData: StatementData, loc: logger.Loc) Stmt { - Stmt.Data.Store.assert(); - - icount += 1; - return switch (StatementData) { - S.Block => Stmt.comptime_alloc("s_block", S.Block, origData, loc), - S.Break => Stmt.comptime_alloc("s_break", S.Break, origData, loc), - S.Class => Stmt.comptime_alloc("s_class", S.Class, origData, loc), - S.Comment => Stmt.comptime_alloc("s_comment", S.Comment, origData, loc), - S.Continue => Stmt.comptime_alloc("s_continue", S.Continue, origData, loc), - S.Debugger => Stmt{ .loc = loc, .data = .{ .s_debugger = origData } }, - S.Directive => Stmt.comptime_alloc("s_directive", S.Directive, origData, loc), - S.DoWhile => Stmt.comptime_alloc("s_do_while", S.DoWhile, origData, loc), - S.Empty => Stmt{ .loc = loc, .data = Data{ .s_empty = S.Empty{} } }, - S.Enum => Stmt.comptime_alloc("s_enum", S.Enum, origData, loc), - S.ExportClause => Stmt.comptime_alloc("s_export_clause", S.ExportClause, origData, loc), - S.ExportDefault => Stmt.comptime_alloc("s_export_default", S.ExportDefault, origData, loc), - S.ExportEquals => Stmt.comptime_alloc("s_export_equals", S.ExportEquals, origData, loc), - S.ExportFrom => Stmt.comptime_alloc("s_export_from", S.ExportFrom, origData, loc), - S.ExportStar => Stmt.comptime_alloc("s_export_star", S.ExportStar, origData, loc), - S.SExpr => Stmt.comptime_alloc("s_expr", S.SExpr, origData, loc), - S.ForIn => Stmt.comptime_alloc("s_for_in", S.ForIn, origData, loc), - S.ForOf => Stmt.comptime_alloc("s_for_of", S.ForOf, origData, loc), - S.For => Stmt.comptime_alloc("s_for", S.For, origData, loc), - S.Function => Stmt.comptime_alloc("s_function", S.Function, origData, loc), - S.If => Stmt.comptime_alloc("s_if", S.If, origData, loc), - S.Import => Stmt.comptime_alloc("s_import", S.Import, origData, loc), - S.Label => Stmt.comptime_alloc("s_label", S.Label, origData, loc), - S.Local => Stmt.comptime_alloc("s_local", S.Local, origData, loc), - S.Namespace => Stmt.comptime_alloc("s_namespace", S.Namespace, origData, loc), - S.Return => Stmt.comptime_alloc("s_return", S.Return, origData, loc), - S.Switch => Stmt.comptime_alloc("s_switch", S.Switch, origData, loc), - S.Throw => Stmt.comptime_alloc("s_throw", S.Throw, origData, loc), - S.Try => Stmt.comptime_alloc("s_try", S.Try, origData, loc), - S.TypeScript => Stmt{ .loc = loc, .data = Data{ .s_type_script = S.TypeScript{} } }, - S.While => Stmt.comptime_alloc("s_while", S.While, origData, loc), - S.With => Stmt.comptime_alloc("s_with", S.With, origData, loc), - else => @compileError("Invalid type in Stmt.init"), - }; -} - -pub const Disabler = bun.DebugOnlyDisabler(@This()); - -/// When the lifetime of an Stmt.Data's pointer must exist longer than reset() is called, use this function. -/// Be careful to free the memory (or use an allocator that does it for you) -/// Also, prefer Stmt.init or Stmt.alloc when possible. This will be slower. -pub fn allocate(allocator: std.mem.Allocator, comptime StatementData: type, origData: StatementData, loc: logger.Loc) Stmt { - Stmt.Data.Store.assert(); - - icount += 1; - return switch (StatementData) { - S.Block => Stmt.allocateData(allocator, "s_block", S.Block, origData, loc), - S.Break => Stmt.allocateData(allocator, "s_break", S.Break, origData, loc), - S.Class => Stmt.allocateData(allocator, "s_class", S.Class, origData, loc), - S.Comment => Stmt.allocateData(allocator, "s_comment", S.Comment, origData, loc), - S.Continue => Stmt.allocateData(allocator, "s_continue", S.Continue, origData, loc), - S.Debugger => Stmt{ .loc = loc, .data = .{ .s_debugger = origData } }, - S.Directive => Stmt.allocateData(allocator, "s_directive", S.Directive, origData, loc), - S.DoWhile => Stmt.allocateData(allocator, "s_do_while", S.DoWhile, origData, loc), - S.Empty => Stmt{ .loc = loc, .data = Data{ .s_empty = S.Empty{} } }, - S.Enum => Stmt.allocateData(allocator, "s_enum", S.Enum, origData, loc), - S.ExportClause => Stmt.allocateData(allocator, "s_export_clause", S.ExportClause, origData, loc), - S.ExportDefault => Stmt.allocateData(allocator, "s_export_default", S.ExportDefault, origData, loc), - S.ExportEquals => Stmt.allocateData(allocator, "s_export_equals", S.ExportEquals, origData, loc), - S.ExportFrom => Stmt.allocateData(allocator, "s_export_from", S.ExportFrom, origData, loc), - S.ExportStar => Stmt.allocateData(allocator, "s_export_star", S.ExportStar, origData, loc), - S.SExpr => Stmt.allocateData(allocator, "s_expr", S.SExpr, origData, loc), - S.ForIn => Stmt.allocateData(allocator, "s_for_in", S.ForIn, origData, loc), - S.ForOf => Stmt.allocateData(allocator, "s_for_of", S.ForOf, origData, loc), - S.For => Stmt.allocateData(allocator, "s_for", S.For, origData, loc), - S.Function => Stmt.allocateData(allocator, "s_function", S.Function, origData, loc), - S.If => Stmt.allocateData(allocator, "s_if", S.If, origData, loc), - S.Import => Stmt.allocateData(allocator, "s_import", S.Import, origData, loc), - S.Label => Stmt.allocateData(allocator, "s_label", S.Label, origData, loc), - S.Local => Stmt.allocateData(allocator, "s_local", S.Local, origData, loc), - S.Namespace => Stmt.allocateData(allocator, "s_namespace", S.Namespace, origData, loc), - S.Return => Stmt.allocateData(allocator, "s_return", S.Return, origData, loc), - S.Switch => Stmt.allocateData(allocator, "s_switch", S.Switch, origData, loc), - S.Throw => Stmt.allocateData(allocator, "s_throw", S.Throw, origData, loc), - S.Try => Stmt.allocateData(allocator, "s_try", S.Try, origData, loc), - S.TypeScript => Stmt{ .loc = loc, .data = Data{ .s_type_script = S.TypeScript{} } }, - S.While => Stmt.allocateData(allocator, "s_while", S.While, origData, loc), - S.With => Stmt.allocateData(allocator, "s_with", S.With, origData, loc), - else => @compileError("Invalid type in Stmt.init"), - }; -} - -pub fn allocateExpr(allocator: std.mem.Allocator, expr: Expr) Stmt { - return Stmt.allocate(allocator, S.SExpr, S.SExpr{ .value = expr }, expr.loc); -} - -pub const Tag = enum { - s_block, - s_break, - s_class, - s_comment, - s_continue, - s_directive, - s_do_while, - s_enum, - s_export_clause, - s_export_default, - s_export_equals, - s_export_from, - s_export_star, - s_expr, - s_for_in, - s_for_of, - s_for, - s_function, - s_if, - s_import, - s_label, - s_local, - s_namespace, - s_return, - s_switch, - s_throw, - s_try, - s_while, - s_with, - s_type_script, - s_empty, - s_debugger, - s_lazy_export, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - - pub fn isExportLike(tag: Tag) bool { - return switch (tag) { - .s_export_clause, .s_export_default, .s_export_equals, .s_export_from, .s_export_star, .s_empty => true, - else => false, - }; - } -}; - -pub const Data = union(Tag) { - s_block: *S.Block, - s_break: *S.Break, - s_class: *S.Class, - s_comment: *S.Comment, - s_continue: *S.Continue, - s_directive: *S.Directive, - s_do_while: *S.DoWhile, - s_enum: *S.Enum, - s_export_clause: *S.ExportClause, - s_export_default: *S.ExportDefault, - s_export_equals: *S.ExportEquals, - s_export_from: *S.ExportFrom, - s_export_star: *S.ExportStar, - s_expr: *S.SExpr, - s_for_in: *S.ForIn, - s_for_of: *S.ForOf, - s_for: *S.For, - s_function: *S.Function, - s_if: *S.If, - s_import: *S.Import, - s_label: *S.Label, - s_local: *S.Local, - s_namespace: *S.Namespace, - s_return: *S.Return, - s_switch: *S.Switch, - s_throw: *S.Throw, - s_try: *S.Try, - s_while: *S.While, - s_with: *S.With, - - s_type_script: S.TypeScript, - s_empty: S.Empty, // special case, its a zero value type - s_debugger: S.Debugger, - - s_lazy_export: *Expr.Data, - - comptime { - if (@sizeOf(Stmt) > 24) { - @compileLog("Expected Stmt to be <= 24 bytes, but it is", @sizeOf(Stmt), " bytes"); - } - } - - pub const Store = struct { - const StoreType = NewStore(&.{ - S.Block, - S.Break, - S.Class, - S.Comment, - S.Continue, - S.Directive, - S.DoWhile, - S.Enum, - S.ExportClause, - S.ExportDefault, - S.ExportEquals, - S.ExportFrom, - S.ExportStar, - S.SExpr, - S.ForIn, - S.ForOf, - S.For, - S.Function, - S.If, - S.Import, - S.Label, - S.Local, - S.Namespace, - S.Return, - S.Switch, - S.Throw, - S.Try, - S.While, - S.With, - }, 128); - - pub threadlocal var instance: ?*StoreType = null; - pub threadlocal var memory_allocator: ?*ASTMemoryAllocator = null; - pub threadlocal var disable_reset = false; - - pub fn create() void { - if (instance != null or memory_allocator != null) { - return; - } - - instance = StoreType.init(); - } - - /// create || reset - pub fn begin() void { - if (memory_allocator != null) return; - if (instance == null) { - create(); - return; - } - - if (!disable_reset) - instance.?.reset(); - } - - pub fn reset() void { - if (disable_reset or memory_allocator != null) return; - instance.?.reset(); - } - - pub fn deinit() void { - if (instance == null or memory_allocator != null) return; - instance.?.deinit(); - instance = null; - } - - pub inline fn assert() void { - if (comptime Environment.allow_assert) { - if (instance == null and memory_allocator == null) - bun.unreachablePanic("Store must be init'd", .{}); - } - } - - pub fn append(comptime T: type, value: T) *T { - if (memory_allocator) |allocator| { - return allocator.append(T, value); - } - - Disabler.assert(); - return instance.?.append(T, value); - } - }; -}; - -pub fn StoredData(tag: Tag) type { - const T = @FieldType(Data, tag); - return switch (@typeInfo(T)) { - .pointer => |ptr| ptr.child, - else => T, - }; -} - -pub fn caresAboutScope(self: *Stmt) bool { - return switch (self.data) { - .s_block, .s_empty, .s_debugger, .s_expr, .s_if, .s_for, .s_for_in, .s_for_of, .s_do_while, .s_while, .s_with, .s_try, .s_switch, .s_return, .s_throw, .s_break, .s_continue, .s_directive => { - return false; - }, - - .s_local => |local| { - return local.kind != .k_var; - }, - else => { - return true; - }, - }; -} - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const logger = bun.logger; - -const js_ast = bun.ast; -const ASTMemoryAllocator = js_ast.ASTMemoryAllocator; -const Expr = js_ast.Expr; -const NewBatcher = js_ast.NewBatcher; -const NewStore = js_ast.NewStore; -const S = js_ast.S; -const Stmt = js_ast.Stmt; diff --git a/src/ast/symbol.zig b/src/ast/symbol.zig deleted file mode 100644 index efe8dbae1965..000000000000 --- a/src/ast/symbol.zig +++ /dev/null @@ -1,487 +0,0 @@ -/// This is the name that came from the parser. Printed names may be renamed -/// during minification or to avoid name collisions. Do not use the original -/// name during printing. -original_name: []const u8, - -/// This is used for symbols that represent items in the import clause of an -/// ES6 import statement. These should always be referenced by EImportIdentifier -/// instead of an EIdentifier. When this is present, the expression should -/// be printed as a property access off the namespace instead of as a bare -/// identifier. -/// -/// For correctness, this must be stored on the symbol instead of indirectly -/// associated with the Ref for the symbol somehow. In ES6 "flat bundling" -/// mode, re-exported symbols are collapsed using MergeSymbols() and renamed -/// symbols from other files that end up at this symbol must be able to tell -/// if it has a namespace alias. -namespace_alias: ?G.NamespaceAlias = null, - -/// Used by the parser for single pass parsing. -link: Ref = Ref.None, - -/// An estimate of the number of uses of this symbol. This is used to detect -/// whether a symbol is used or not. For example, TypeScript imports that are -/// unused must be removed because they are probably type-only imports. This -/// is an estimate and may not be completely accurate due to oversights in the -/// code. But it should always be non-zero when the symbol is used. -use_count_estimate: u32 = 0, - -/// This is for generating cross-chunk imports and exports for code splitting. -/// -/// Do not use this directly. Use `chunkIndex()` instead. -chunk_index: u32 = invalid_chunk_index, - -/// This is used for minification. Symbols that are declared in sibling scopes -/// can share a name. A good heuristic (from Google Closure Compiler) is to -/// assign names to symbols from sibling scopes in declaration order. That way -/// local variable names are reused in each global function like this, which -/// improves gzip compression: -/// -/// function x(a, b) { ... } -/// function y(a, b, c) { ... } -/// -/// The parser fills this in for symbols inside nested scopes. There are three -/// slot namespaces: regular symbols, label symbols, and private symbols. -/// -/// Do not use this directly. Use `nestedScopeSlot()` instead. -nested_scope_slot: u32 = invalid_nested_scope_slot, - -did_keep_name: bool = true, - -must_start_with_capital_letter_for_jsx: bool = false, - -/// The kind of symbol. This is used to determine how to print the symbol -/// and how to deal with conflicts, renaming, etc. -kind: Kind = Kind.other, - -/// Certain symbols must not be renamed or minified. For example, the -/// "arguments" variable is declared by the runtime for every function. -/// Renaming can also break any identifier used inside a "with" statement. -must_not_be_renamed: bool = false, - -/// We automatically generate import items for property accesses off of -/// namespace imports. This lets us remove the expensive namespace imports -/// while bundling in many cases, replacing them with a cheap import item -/// instead: -/// -/// import * as ns from 'path' -/// ns.foo() -/// -/// That can often be replaced by this, which avoids needing the namespace: -/// -/// import {foo} from 'path' -/// foo() -/// -/// However, if the import is actually missing then we don't want to report a -/// compile-time error like we do for real import items. This status lets us -/// avoid this. We also need to be able to replace such import items with -/// undefined, which this status is also used for. -import_item_status: ImportItemStatus = ImportItemStatus.none, - -/// --- Not actually used yet ----------------------------------------------- -/// Sometimes we lower private symbols even if they are supported. For example, -/// consider the following TypeScript code: -/// -/// class Foo { -/// #foo = 123 -/// bar = this.#foo -/// } -/// -/// If "useDefineForClassFields: false" is set in "tsconfig.json", then "bar" -/// must use assignment semantics instead of define semantics. We can compile -/// that to this code: -/// -/// class Foo { -/// constructor() { -/// this.#foo = 123; -/// this.bar = this.#foo; -/// } -/// #foo; -/// } -/// -/// However, we can't do the same for static fields: -/// -/// class Foo { -/// static #foo = 123 -/// static bar = this.#foo -/// } -/// -/// Compiling these static fields to something like this would be invalid: -/// -/// class Foo { -/// static #foo; -/// } -/// Foo.#foo = 123; -/// Foo.bar = Foo.#foo; -/// -/// Thus "#foo" must be lowered even though it's supported. Another case is -/// when we're converting top-level class declarations to class expressions -/// to avoid the TDZ and the class shadowing symbol is referenced within the -/// class body: -/// -/// class Foo { -/// static #foo = Foo -/// } -/// -/// This cannot be converted into something like this: -/// -/// var Foo = class { -/// static #foo; -/// }; -/// Foo.#foo = Foo; -/// -/// --- Not actually used yet ----------------------------------------------- -private_symbol_must_be_lowered: bool = false, - -remove_overwritten_function_declaration: bool = false, - -/// Used in HMR to decide when live binding code is needed. -has_been_assigned_to: bool = false, - -comptime { - bun.assert_eql(@sizeOf(Symbol), 88); - bun.assert_eql(@alignOf(Symbol), @alignOf([]const u8)); -} - -const invalid_chunk_index = std.math.maxInt(u32); -pub const invalid_nested_scope_slot = std.math.maxInt(u32); - -pub const SlotNamespace = enum { - must_not_be_renamed, - default, - label, - private_name, - mangled_prop, - - pub const CountsArray = std.EnumArray(SlotNamespace, u32); -}; - -/// This is for generating cross-chunk imports and exports for code splitting. -pub inline fn chunkIndex(this: *const Symbol) ?u32 { - const i = this.chunk_index; - return if (i == invalid_chunk_index) null else i; -} - -pub inline fn nestedScopeSlot(this: *const Symbol) ?u32 { - const i = this.nested_scope_slot; - return if (i == invalid_nested_scope_slot) null else i; -} - -pub fn slotNamespace(this: *const Symbol) SlotNamespace { - const kind = this.kind; - - if (kind == .unbound or this.must_not_be_renamed) { - return .must_not_be_renamed; - } - - if (kind.isPrivate()) { - return .private_name; - } - - return switch (kind) { - // .mangled_prop => .mangled_prop, - .label => .label, - else => .default, - }; -} - -pub inline fn hasLink(this: *const Symbol) bool { - return this.link.tag != .invalid; -} - -pub const Kind = enum { - /// An unbound symbol is one that isn't declared in the file it's referenced - /// in. For example, using "window" without declaring it will be unbound. - unbound, - - /// This has special merging behavior. You're allowed to re-declare these - /// symbols more than once in the same scope. These symbols are also hoisted - /// out of the scope they are declared in to the closest containing function - /// or module scope. These are the symbols with this kind: - /// - /// - Function arguments - /// - Function statements - /// - Variables declared using "var" - hoisted, - hoisted_function, - - /// There's a weird special case where catch variables declared using a simple - /// identifier (i.e. not a binding pattern) block hoisted variables instead of - /// becoming an error: - /// - /// var e = 0; - /// try { throw 1 } catch (e) { - /// print(e) // 1 - /// var e = 2 - /// print(e) // 2 - /// } - /// print(e) // 0 (since the hoisting stops at the catch block boundary) - /// - /// However, other forms are still a syntax error: - /// - /// try {} catch (e) { let e } - /// try {} catch ({e}) { var e } - /// - /// This symbol is for handling this weird special case. - catch_identifier, - - /// Generator and async functions are not hoisted, but still have special - /// properties such as being able to overwrite previous functions with the - /// same name - generator_or_async_function, - - /// This is the special "arguments" variable inside functions - arguments, - - /// Classes can merge with TypeScript namespaces. - class, - - /// A class-private identifier (i.e. "#foo"). - private_field, - private_method, - private_get, - private_set, - private_get_set_pair, - private_static_field, - private_static_method, - private_static_get, - private_static_set, - private_static_get_set_pair, - - /// Labels are in their own namespace - label, - - /// TypeScript enums can merge with TypeScript namespaces and other TypeScript - /// enums. - ts_enum, - - /// TypeScript namespaces can merge with classes, functions, TypeScript enums, - /// and other TypeScript namespaces. - ts_namespace, - - /// In TypeScript, imports are allowed to silently collide with symbols within - /// the module. Presumably this is because the imports may be type-only. - /// Import statement namespace references should NOT have this set. - import, - - /// Assigning to a "const" symbol will throw a TypeError at runtime - constant, - - // CSS identifiers that are renamed to be unique to the file they are in - local_css, - - /// This annotates all other symbols that don't have special behavior. - other, - - pub fn jsonStringify(self: @This(), writer: anytype) !void { - return try writer.write(@tagName(self)); - } - - pub inline fn isPrivate(kind: Symbol.Kind) bool { - return @intFromEnum(kind) >= @intFromEnum(Symbol.Kind.private_field) and @intFromEnum(kind) <= @intFromEnum(Symbol.Kind.private_static_get_set_pair); - } - - pub inline fn isHoisted(kind: Symbol.Kind) bool { - return switch (kind) { - .hoisted, .hoisted_function => true, - else => false, - }; - } - - pub inline fn isHoistedOrFunction(kind: Symbol.Kind) bool { - return switch (kind) { - .hoisted, .hoisted_function, .generator_or_async_function => true, - else => false, - }; - } - - pub inline fn isFunction(kind: Symbol.Kind) bool { - return switch (kind) { - .hoisted_function, .generator_or_async_function => true, - else => false, - }; - } -}; - -pub const Use = struct { - count_estimate: u32 = 0, -}; - -pub const List = BabyList(Symbol); -pub const NestedList = BabyList(List); - -pub fn mergeContentsWith(this: *Symbol, old: *Symbol) void { - this.use_count_estimate += old.use_count_estimate; - if (old.must_not_be_renamed) { - this.original_name = old.original_name; - this.must_not_be_renamed = true; - } - - // TODO: MustStartWithCapitalLetterForJSX -} - -pub const Map = struct { - // This could be represented as a "map[Ref]Symbol" but a two-level array was - // more efficient in profiles. This appears to be because it doesn't involve - // a hash. This representation also makes it trivial to quickly merge symbol - // maps from multiple files together. Each file only generates symbols in a - // single inner array, so you can join the maps together by just make a - // single outer array containing all of the inner arrays. See the comment on - // "Ref" for more detail. - symbols_for_source: NestedList = .{}, - - pub fn dump(this: Map) void { - defer Output.flush(); - for (this.symbols_for_source.slice(), 0..) |symbols, i| { - Output.prettyln("\n\n-- Source ID: {d} ({d} symbols) --\n\n", .{ i, symbols.len }); - for (symbols.slice(), 0..) |symbol, inner_index| { - Output.prettyln( - " name: {s}\n tag: {s}\n {f}\n", - .{ - symbol.original_name, @tagName(symbol.kind), - if (symbol.hasLink()) symbol.link else Ref{ - .source_index = @truncate(i), - .inner_index = @truncate(inner_index), - .tag = .symbol, - }, - }, - ); - } - } - } - - pub fn assignChunkIndex(this: *Map, decls_: DeclaredSymbol.List, chunk_index: u32) void { - const Iterator = struct { - map: *Map, - chunk_index: u32, - - pub fn next(self: @This(), ref: Ref) void { - var symbol = self.map.get(ref).?; - symbol.chunk_index = self.chunk_index; - } - }; - var decls = decls_; - - DeclaredSymbol.forEachTopLevelSymbol(&decls, Iterator{ .map = this, .chunk_index = chunk_index }, Iterator.next); - } - - pub fn merge(this: *Map, old: Ref, new: Ref) Ref { - if (old.eql(new)) { - return new; - } - - var old_symbol = this.get(old).?; - if (old_symbol.hasLink()) { - const old_link = old_symbol.link; - old_symbol.link = this.merge(old_link, new); - return old_symbol.link; - } - - var new_symbol = this.get(new).?; - - if (new_symbol.hasLink()) { - const new_link = new_symbol.link; - new_symbol.link = this.merge(old, new_link); - return new_symbol.link; - } - - old_symbol.link = new; - new_symbol.mergeContentsWith(old_symbol); - return new; - } - - pub fn get(self: *const Map, ref: Ref) ?*Symbol { - if (Ref.isSourceIndexNull(ref.sourceIndex()) or ref.isSourceContentsSlice()) { - return null; - } - - return self.symbols_for_source.at(ref.sourceIndex()).mut(ref.innerIndex()); - } - - pub fn getConst(self: *const Map, ref: Ref) ?*const Symbol { - if (Ref.isSourceIndexNull(ref.sourceIndex()) or ref.isSourceContentsSlice()) { - return null; - } - - return self.symbols_for_source.at(ref.sourceIndex()).at(ref.innerIndex()); - } - - pub fn init(sourceCount: usize, allocator: std.mem.Allocator) !Map { - const symbols_for_source: NestedList = NestedList.init(try allocator.alloc([]Symbol, sourceCount)); - return Map{ .symbols_for_source = symbols_for_source }; - } - - pub fn initWithOneList(list: List) Map { - const baby_list = BabyList(List).fromBorrowedSliceDangerous((&list)[0..1]); - return initList(baby_list); - } - - pub fn initList(list: NestedList) Map { - return Map{ .symbols_for_source = list }; - } - - pub fn getWithLink(symbols: *const Map, ref: Ref) ?*Symbol { - var symbol: *Symbol = symbols.get(ref) orelse return null; - if (symbol.hasLink()) { - return symbols.get(symbol.link) orelse symbol; - } - return symbol; - } - - pub fn getWithLinkConst(symbols: *Map, ref: Ref) ?*const Symbol { - var symbol: *const Symbol = symbols.getConst(ref) orelse return null; - if (symbol.hasLink()) { - return symbols.getConst(symbol.link) orelse symbol; - } - return symbol; - } - - pub fn followAll(symbols: *Map) void { - const trace = bun.perf.trace("Symbols.followAll"); - defer trace.end(); - for (symbols.symbols_for_source.slice()) |list| { - for (list.slice()) |*symbol| { - if (!symbol.hasLink()) continue; - symbol.link = follow(symbols, symbol.link); - } - } - } - - /// Equivalent to followSymbols in esbuild - pub fn follow(symbols: *const Map, ref: Ref) Ref { - var symbol = symbols.get(ref) orelse return ref; - if (!symbol.hasLink()) { - return ref; - } - - const link = follow(symbols, symbol.link); - - if (!symbol.link.eql(link)) { - symbol.link = link; - } - - return link; - } -}; - -pub inline fn isHoisted(self: *const Symbol) bool { - return Symbol.isKindHoisted(self.kind); -} - -pub const isKindFunction = Symbol.Kind.isFunction; -pub const isKindHoisted = Symbol.Kind.isHoisted; -pub const isKindHoistedOrFunction = Symbol.Kind.isHoistedOrFunction; -pub const isKindPrivate = Symbol.Kind.isPrivate; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const Output = bun.Output; - -const js_ast = bun.ast; -const DeclaredSymbol = js_ast.DeclaredSymbol; -const G = js_ast.G; -const ImportItemStatus = js_ast.ImportItemStatus; -const Ref = js_ast.Ref; -const Symbol = js_ast.Symbol; diff --git a/src/ast/ts.zig b/src/ast/ts.zig deleted file mode 100644 index 5eba8b444d88..000000000000 --- a/src/ast/ts.zig +++ /dev/null @@ -1,139 +0,0 @@ -/// This is for TypeScript "enum" and "namespace" blocks. Each block can -/// potentially be instantiated multiple times. The exported members of each -/// block are merged into a single namespace while the non-exported code is -/// still scoped to just within that block: -/// -/// let x = 1; -/// namespace Foo { -/// let x = 2; -/// export let y = 3; -/// } -/// namespace Foo { -/// console.log(x); // 1 -/// console.log(y); // 3 -/// } -/// -/// Doing this also works inside an enum: -/// -/// enum Foo { -/// A = 3, -/// B = A + 1, -/// } -/// enum Foo { -/// C = A + 2, -/// } -/// console.log(Foo.B) // 4 -/// console.log(Foo.C) // 5 -/// -/// This is a form of identifier lookup that works differently than the -/// hierarchical scope-based identifier lookup in JavaScript. Lookup now needs -/// to search sibling scopes in addition to parent scopes. This is accomplished -/// by sharing the map of exported members between all matching sibling scopes. -pub const TSNamespaceScope = struct { - /// This is specific to this namespace block. It's the argument of the - /// immediately-invoked function expression that the namespace block is - /// compiled into: - /// - /// var ns; - /// (function (ns2) { - /// ns2.x = 123; - /// })(ns || (ns = {})); - /// - /// This variable is "ns2" in the above example. It's the symbol to use when - /// generating property accesses off of this namespace when it's in scope. - arg_ref: Ref, - - /// This is shared between all sibling namespace blocks - exported_members: *TSNamespaceMemberMap, - - /// This is a lazily-generated map of identifiers that actually represent - /// property accesses to this namespace's properties. For example: - /// - /// namespace x { - /// export let y = 123 - /// } - /// namespace x { - /// export let z = y - /// } - /// - /// This should be compiled into the following code: - /// - /// var x; - /// (function(x2) { - /// x2.y = 123; - /// })(x || (x = {})); - /// (function(x3) { - /// x3.z = x3.y; - /// })(x || (x = {})); - /// - /// When we try to find the symbol "y", we instead return one of these lazily - /// generated proxy symbols that represent the property access "x3.y". This - /// map is unique per namespace block because "x3" is the argument symbol that - /// is specific to that particular namespace block. - property_accesses: bun.StringArrayHashMapUnmanaged(Ref) = .{}, - - /// Even though enums are like namespaces and both enums and namespaces allow - /// implicit references to properties of sibling scopes, they behave like - /// separate, er, namespaces. Implicit references only work namespace-to- - /// namespace and enum-to-enum. They do not work enum-to-namespace. And I'm - /// not sure what's supposed to happen for the namespace-to-enum case because - /// the compiler crashes: https://github.com/microsoft/TypeScript/issues/46891. - /// So basically these both work: - /// - /// enum a { b = 1 } - /// enum a { c = b } - /// - /// namespace x { export let y = 1 } - /// namespace x { export let z = y } - /// - /// This doesn't work: - /// - /// enum a { b = 1 } - /// namespace a { export let c = b } - /// - /// And this crashes the TypeScript compiler: - /// - /// namespace a { export let b = 1 } - /// enum a { c = b } - /// - /// Therefore we only allow enum/enum and namespace/namespace interactions. - is_enum_scope: bool, -}; - -pub const TSNamespaceMemberMap = bun.StringArrayHashMapUnmanaged(TSNamespaceMember); - -pub const TSNamespaceMember = struct { - loc: logger.Loc, - data: Data, - - pub const Data = union(enum) { - /// "namespace ns { export let it }" - property, - /// "namespace ns { export namespace it {} }" - namespace: *TSNamespaceMemberMap, - /// "enum ns { it }" - enum_number: f64, - /// "enum ns { it = 'it' }" - enum_string: *E.String, - /// "enum ns { it = something() }" - enum_property: void, - - pub fn isEnum(data: Data) bool { - return switch (data) { - inline else => |_, tag| comptime std.mem.startsWith(u8, @tagName(tag), "enum_"), - }; - } - }; -}; - -pub const Class = G.Class; - -const std = @import("std"); - -const bun = @import("bun"); -const logger = bun.logger; - -const js_ast = bun.ast; -const E = js_ast.E; -const G = js_ast.G; -const Ref = js_ast.Ref; diff --git a/src/ast/use_directive.zig b/src/ast/use_directive.zig deleted file mode 100644 index 12552cd24d39..000000000000 --- a/src/ast/use_directive.zig +++ /dev/null @@ -1,64 +0,0 @@ -pub const UseDirective = enum(u2) { - // TODO: Remove this, and provide `UseDirective.Optional` instead - none, - /// "use client" - client, - /// "use server" - server, - - pub const Boundering = enum(u2) { - client = @intFromEnum(UseDirective.client), - server = @intFromEnum(UseDirective.server), - }; - - pub const Flags = struct { - has_any_client: bool = false, - }; - - pub fn isBoundary(this: UseDirective, other: UseDirective) bool { - if (this == other or other == .none) - return false; - - return true; - } - - pub fn boundering(this: UseDirective, other: UseDirective) ?Boundering { - if (this == other or other == .none) - return null; - return @enumFromInt(@intFromEnum(other)); - } - - pub fn parse(contents: []const u8) ?UseDirective { - const truncated = std.mem.trimLeft(u8, contents, " \t\n\r;"); - - if (truncated.len < "'use client';".len) - return .none; - - const directive_string = truncated[0.."'use client';".len].*; - - const first_quote = directive_string[0]; - const last_quote = directive_string[directive_string.len - 2]; - if (first_quote != last_quote or (first_quote != '"' and first_quote != '\'' and first_quote != '`')) - return .none; - - const unquoted = directive_string[1 .. directive_string.len - 2]; - - if (strings.eqlComptime(unquoted, "use client")) { - return .client; - } - - if (strings.eqlComptime(unquoted, "use server")) { - return .server; - } - - return null; - } -}; - -const std = @import("std"); - -const bun = @import("bun"); -const strings = bun.strings; - -const js_ast = bun.ast; -const Flags = js_ast.Flags; diff --git a/src/ast_jsc/logger_jsc.zig b/src/ast_jsc/logger_jsc.zig deleted file mode 100644 index abbd52cb3c40..000000000000 --- a/src/ast_jsc/logger_jsc.zig +++ /dev/null @@ -1,93 +0,0 @@ -//! JSC bridge for `bun.logger`. Keeps `src/logger/` free of JSC types. - -pub fn msgFromJS(allocator: std.mem.Allocator, globalObject: *jsc.JSGlobalObject, file: []const u8, err: jsc.JSValue) bun.JSError!Msg { - var zig_exception_holder: jsc.ZigException.Holder = jsc.ZigException.Holder.init(); - if (err.toError()) |value| { - value.toZigException(globalObject, zig_exception_holder.zigException()); - } else { - zig_exception_holder.zigException().message = try err.toBunString(globalObject); - } - - return Msg{ - .data = .{ - .text = try zig_exception_holder.zigException().message.toOwnedSlice(allocator), - .location = logger.Location{ - .file = file, - .line = 0, - .column = 0, - }, - }, - }; -} - -pub fn msgToJS(this: Msg, globalObject: *jsc.JSGlobalObject, allocator: std.mem.Allocator) bun.OOM!jsc.JSValue { - return switch (this.metadata) { - .build => bun.api.BuildMessage.create(globalObject, allocator, this), - .resolve => bun.api.ResolveMessage.create(globalObject, allocator, this, ""), - }; -} - -pub fn levelFromJS(globalThis: *jsc.JSGlobalObject, value: jsc.JSValue) bun.JSError!?Log.Level { - if (value == .zero or value.isUndefined()) { - return null; - } - - if (!value.isString()) { - return globalThis.throwInvalidArguments("Expected logLevel to be a string", .{}); - } - - return Log.Level.Map.fromJS(globalThis, value); -} - -pub fn logToJS(this: Log, global: *jsc.JSGlobalObject, allocator: std.mem.Allocator, message: []const u8) bun.JSError!jsc.JSValue { - const msgs: []const Msg = this.msgs.items; - var errors_stack: [256]jsc.JSValue = undefined; - - const count = @as(u16, @intCast(@min(msgs.len, errors_stack.len))); - switch (count) { - 0 => return .js_undefined, - 1 => { - const msg = msgs[0]; - return switch (msg.metadata) { - .build => bun.api.BuildMessage.create(global, allocator, msg), - .resolve => bun.api.ResolveMessage.create(global, allocator, msg, ""), - }; - }, - else => { - for (msgs[0..count], 0..) |msg, i| { - errors_stack[i] = switch (msg.metadata) { - .build => try bun.api.BuildMessage.create(global, allocator, msg), - .resolve => try bun.api.ResolveMessage.create(global, allocator, msg, ""), - }; - } - const out = jsc.ZigString.init(message); - const agg = try global.createAggregateError(errors_stack[0..count], &out); - return agg; - }, - } -} - -/// unlike toJS, this always produces an AggregateError object -pub fn logToJSAggregateError(this: Log, global: *jsc.JSGlobalObject, message: bun.String) bun.JSError!jsc.JSValue { - return global.createAggregateErrorWithArray(message, try logToJSArray(this, global, bun.default_allocator)); -} - -pub fn logToJSArray(this: Log, global: *jsc.JSGlobalObject, allocator: std.mem.Allocator) bun.JSError!jsc.JSValue { - const msgs: []const Msg = this.msgs.items; - - const arr = try jsc.JSValue.createEmptyArray(global, msgs.len); - for (msgs, 0..) |msg, i| { - try arr.putIndex(global, @as(u32, @intCast(i)), try msgToJS(msg, global, allocator)); - } - - return arr; -} - -const std = @import("std"); - -const bun = @import("bun"); -const jsc = bun.jsc; - -const logger = bun.logger; -const Log = logger.Log; -const Msg = logger.Msg; diff --git a/src/base64/base64.zig b/src/base64/base64.zig deleted file mode 100644 index 5ce27780b24c..000000000000 --- a/src/base64/base64.zig +++ /dev/null @@ -1,558 +0,0 @@ -const mixed_decoder = brk: { - var decoder = zig_base64.standard.decoderWithIgnore("\xff \t\r\n" ++ [_]u8{ - std.ascii.control_code.vt, - std.ascii.control_code.ff, - }); - - for (zig_base64.url_safe_alphabet_chars[62..], 62..) |c, i| { - decoder.decoder.char_to_index[c] = @as(u8, @intCast(i)); - } - - break :brk decoder; -}; - -pub fn decode(destination: []u8, source: []const u8) bun.simdutf.SIMDUTFResult { - const result = bun.simdutf.base64.decode(source, destination, false); - - if (!result.isSuccessful()) { - // The input does not follow the WHATWG forgiving-base64 specification - // https://infra.spec.whatwg.org/#forgiving-base64-decode - // https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/src/string_bytes.cc#L359 - var wrote: usize = 0; - mixed_decoder.decode(destination, source, &wrote) catch { - return .{ - .count = wrote, - .status = .invalid_base64_character, - }; - }; - return .{ .count = wrote, .status = .success }; - } - - return result; -} - -pub fn decodeAlloc(allocator: std.mem.Allocator, input: []const u8) ![]u8 { - var dest = try allocator.alloc(u8, decodeLen(input)); - const result = decode(dest, input); - if (!result.isSuccessful()) { - allocator.free(dest); - return error.DecodingFailed; - } - return dest[0..result.count]; -} - -pub fn encode(destination: []u8, source: []const u8) usize { - return bun.simdutf.base64.encode(source, destination, false); -} - -pub fn encodeAlloc(allocator: std.mem.Allocator, source: []const u8) !bun.ByteList { - const len = encodeLen(source); - const destination = try allocator.alloc(u8, len); - const encoded_len = encode(destination, source); - return .{ - .ptr = destination.ptr, - .len = @truncate(encoded_len), - .cap = @truncate(len), - }; -} - -pub fn simdutfEncodeLenUrlSafe(source_len: usize) usize { - return bun.simdutf.base64.encode_len(source_len, true); -} - -/// Encode with the following differences from regular `encode` function: -/// -/// * No padding is added (the extra `=` characters at the end) -/// * `-` and `_` are used instead of `+` and `/` -/// -/// See the documentation for simdutf's `binary_to_base64` function for more details (simdutf_impl.h). -pub fn simdutfEncodeUrlSafe(destination: []u8, source: []const u8) usize { - return bun.simdutf.base64.encode(source, destination, true); -} - -pub fn decodeLenUpperBound(len: usize) usize { - return zig_base64.standard.Decoder.calcSizeUpperBound(len) catch { - //fallback - return len / 4 * 3; - }; -} - -pub fn decodeLen(source: anytype) usize { - return zig_base64.standard.Decoder.calcSizeForSlice(source) catch { - - //fallback; add 2 to allow for potentially missing padding - return source.len / 4 * 3 + 2; - }; -} - -pub fn encodeLen(source: anytype) usize { - return encodeLenFromSize(source.len); -} - -pub fn encodeLenFromSize(source: usize) usize { - return zig_base64.standard.Encoder.calcSize(source); -} - -pub fn urlSafeEncodeLen(source: anytype) usize { - // Copied from WebKit - return ((source.len * 4) + 2) / 3; -} -extern fn WTF__base64URLEncode(input: [*]const u8, input_len: usize, output: [*]u8, output_len: usize) usize; -pub fn encodeURLSafe(dest: []u8, source: []const u8) usize { - bun.jsc.markBinding(@src()); - return WTF__base64URLEncode(source.ptr, source.len, dest.ptr, dest.len); -} - -const zig_base64 = struct { - const assert = bun.assert; - const testing = std.testing; - const mem = std.mem; - - pub const Error = error{ - InvalidCharacter, - InvalidPadding, - NoSpaceLeft, - }; - - const decoderWithIgnoreProto = *const fn (ignore: []const u8) Base64DecoderWithIgnore; - - /// Base64 codecs - pub const Codecs = struct { - alphabet_chars: [64]u8, - pad_char: ?u8, - decoderWithIgnore: decoderWithIgnoreProto, - Encoder: Base64Encoder, - Decoder: Base64Decoder, - }; - - pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".*; - fn standardBase64DecoderWithIgnore(ignore: []const u8) Base64DecoderWithIgnore { - return Base64DecoderWithIgnore.init(standard_alphabet_chars, '=', ignore); - } - - /// Standard Base64 codecs, with padding - pub const standard = Codecs{ - .alphabet_chars = standard_alphabet_chars, - .pad_char = '=', - .decoderWithIgnore = standardBase64DecoderWithIgnore, - .Encoder = Base64Encoder.init(standard_alphabet_chars, '='), - .Decoder = Base64Decoder.init(standard_alphabet_chars, '='), - }; - - /// Standard Base64 codecs, without padding - pub const standard_no_pad = Codecs{ - .alphabet_chars = standard_alphabet_chars, - .pad_char = null, - .decoderWithIgnore = standardBase64DecoderWithIgnore, - .Encoder = Base64Encoder.init(standard_alphabet_chars, null), - .Decoder = Base64Decoder.init(standard_alphabet_chars, null), - }; - - pub const url_safe_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_".*; - fn urlSafeBase64DecoderWithIgnore(ignore: []const u8) Base64DecoderWithIgnore { - return Base64DecoderWithIgnore.init(url_safe_alphabet_chars, '=', ignore); - } - - /// URL-safe Base64 codecs, with padding - pub const url_safe = Codecs{ - .alphabet_chars = url_safe_alphabet_chars, - .pad_char = '=', - .decoderWithIgnore = urlSafeBase64DecoderWithIgnore, - .Encoder = Base64Encoder.init(url_safe_alphabet_chars, '='), - .Decoder = Base64Decoder.init(url_safe_alphabet_chars, '='), - }; - - /// URL-safe Base64 codecs, without padding - pub const url_safe_no_pad = Codecs{ - .alphabet_chars = url_safe_alphabet_chars, - .pad_char = null, - .decoderWithIgnore = urlSafeBase64DecoderWithIgnore, - .Encoder = Base64Encoder.init(url_safe_alphabet_chars, null), - .Decoder = Base64Decoder.init(url_safe_alphabet_chars, null), - }; - - pub const standard_pad_char = @compileError("deprecated; use standard.pad_char"); - pub const standard_encoder = @compileError("deprecated; use standard.Encoder"); - pub const standard_decoder = @compileError("deprecated; use standard.Decoder"); - - pub const Base64Encoder = struct { - alphabet_chars: [64]u8, - pad_char: ?u8, - - /// A bunch of assertions, then simply pass the data right through. - pub fn init(alphabet_chars: [64]u8, pad_char: ?u8) Base64Encoder { - assert(alphabet_chars.len == 64); - var char_in_alphabet = [_]bool{false} ** 256; - for (alphabet_chars) |c| { - assert(!char_in_alphabet[c]); - assert(pad_char == null or c != pad_char.?); - char_in_alphabet[c] = true; - } - return Base64Encoder{ - .alphabet_chars = alphabet_chars, - .pad_char = pad_char, - }; - } - - /// Compute the encoded length - /// Note: this is wrong for base64url encoding. Do not use it for that. - pub fn calcSize(encoder: *const Base64Encoder, source_len: usize) usize { - if (encoder.pad_char != null) { - return @divTrunc(source_len + 2, 3) * 4; - } else { - const leftover = source_len % 3; - return @divTrunc(source_len, 3) * 4 + @divTrunc(leftover * 4 + 2, 3); - } - } - - /// dest.len must at least be what you get from ::calcSize. - pub fn encode(encoder: *const Base64Encoder, dest: []u8, source: []const u8) []const u8 { - const out_len = encoder.calcSize(source.len); - assert(dest.len >= out_len); - - const out_idx = encoder.encodeWithoutSizeCheck(dest, source); - if (encoder.pad_char) |pad_char| { - for (dest[out_idx..out_len]) |*pad| { - pad.* = pad_char; - } - } - return dest[0..out_len]; - } - - pub fn encodeWithoutSizeCheck(encoder: *const Base64Encoder, dest: []u8, source: []const u8) usize { - var acc: u12 = 0; - var acc_len: u4 = 0; - var out_idx: usize = 0; - for (source) |v| { - acc = (acc << 8) + v; - acc_len += 8; - while (acc_len >= 6) { - acc_len -= 6; - dest[out_idx] = encoder.alphabet_chars[@as(u6, @truncate((acc >> acc_len)))]; - out_idx += 1; - } - } - if (acc_len > 0) { - dest[out_idx] = encoder.alphabet_chars[@as(u6, @truncate((acc << 6 - acc_len)))]; - out_idx += 1; - } - return out_idx; - } - }; - - pub const Base64Decoder = struct { - const invalid_char: u8 = 0xff; - - /// e.g. 'A' => 0. - /// `invalid_char` for any value not in the 64 alphabet chars. - char_to_index: [256]u8, - pad_char: ?u8, - - pub fn init(alphabet_chars: [64]u8, pad_char: ?u8) Base64Decoder { - var result = Base64Decoder{ - .char_to_index = [_]u8{invalid_char} ** 256, - .pad_char = pad_char, - }; - - var char_in_alphabet = [_]bool{false} ** 256; - for (alphabet_chars, 0..) |c, i| { - assert(!char_in_alphabet[c]); - assert(pad_char == null or c != pad_char.?); - - result.char_to_index[c] = @as(u8, @intCast(i)); - char_in_alphabet[c] = true; - } - return result; - } - - /// Return the maximum possible decoded size for a given input length - The actual length may be less if the input includes padding. - /// `InvalidPadding` is returned if the input length is not valid. - pub fn calcSizeUpperBound(decoder: *const Base64Decoder, source_len: usize) Error!usize { - var result = source_len / 4 * 3; - const leftover = source_len % 4; - if (decoder.pad_char != null) { - if (leftover % 4 != 0) return error.InvalidPadding; - } else { - if (leftover % 4 == 1) return error.InvalidPadding; - result += leftover * 3 / 4; - } - return result; - } - - /// Return the exact decoded size for a slice. - /// `InvalidPadding` is returned if the input length is not valid. - pub fn calcSizeForSlice(decoder: *const Base64Decoder, source: []const u8) Error!usize { - const source_len = source.len; - var result = try decoder.calcSizeUpperBound(source_len); - if (decoder.pad_char) |pad_char| { - if (source_len >= 1 and source[source_len - 1] == pad_char) result -= 1; - if (source_len >= 2 and source[source_len - 2] == pad_char) result -= 1; - } - return result; - } - - /// dest.len must be what you get from ::calcSize. - /// invalid characters result in error.InvalidCharacter. - /// invalid padding results in error.InvalidPadding. - pub fn decode(decoder: *const Base64Decoder, dest: []u8, source: []const u8) Error!void { - if (decoder.pad_char != null and source.len % 4 != 0) return error.InvalidPadding; - var acc: u12 = 0; - var acc_len: u4 = 0; - var dest_idx: usize = 0; - var leftover_idx: ?usize = null; - for (source, 0..) |c, src_idx| { - const d = decoder.char_to_index[c]; - if (d == invalid_char) { - if (decoder.pad_char == null or c != decoder.pad_char.?) return error.InvalidCharacter; - leftover_idx = src_idx; - break; - } - acc = (acc << 6) + d; - acc_len += 6; - if (acc_len >= 8) { - acc_len -= 8; - dest[dest_idx] = @as(u8, @truncate(acc >> acc_len)); - dest_idx += 1; - } - } - if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) { - return error.InvalidPadding; - } - if (leftover_idx == null) return; - const leftover = source[leftover_idx.?..]; - if (decoder.pad_char) |pad_char| { - const padding_len = acc_len / 2; - var padding_chars: usize = 0; - for (leftover) |c| { - if (c != pad_char) { - return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding; - } - padding_chars += 1; - } - if (padding_chars != padding_len) return error.InvalidPadding; - } - } - }; - - pub const Base64DecoderWithIgnore = struct { - decoder: Base64Decoder, - char_is_ignored: [256]bool, - - pub fn init(alphabet_chars: [64]u8, pad_char: ?u8, ignore_chars: []const u8) Base64DecoderWithIgnore { - var result = Base64DecoderWithIgnore{ - .decoder = Base64Decoder.init(alphabet_chars, pad_char), - .char_is_ignored = [_]bool{false} ** 256, - }; - for (ignore_chars) |c| { - assert(result.decoder.char_to_index[c] == Base64Decoder.invalid_char); - assert(!result.char_is_ignored[c]); - assert(result.decoder.pad_char != c); - result.char_is_ignored[c] = true; - } - return result; - } - - /// Return the maximum possible decoded size for a given input length - The actual length may be less if the input includes padding - /// `InvalidPadding` is returned if the input length is not valid. - pub fn calcSizeUpperBound(decoder_with_ignore: *const Base64DecoderWithIgnore, source_len: usize) usize { - var result = source_len / 4 * 3; - if (decoder_with_ignore.decoder.pad_char == null) { - const leftover = source_len % 4; - result += leftover * 3 / 4; - } - return result; - } - - /// Invalid characters that are not ignored result in error.InvalidCharacter. - /// Invalid padding results in error.InvalidPadding. - /// Decoding more data than can fit in dest results in error.NoSpaceLeft. See also ::calcSizeUpperBound. - /// Returns the number of bytes written to dest. - pub fn decode(decoder_with_ignore: *const Base64DecoderWithIgnore, dest: []u8, source: []const u8, wrote: *usize) Error!void { - const decoder = &decoder_with_ignore.decoder; - var acc: u12 = 0; - var acc_len: u4 = 0; - var dest_idx: usize = 0; - var leftover_idx: ?usize = null; - - defer { - wrote.* = dest_idx; - } - - for (source, 0..) |c, src_idx| { - if (decoder_with_ignore.char_is_ignored[c]) continue; - const d = decoder.char_to_index[c]; - if (d == Base64Decoder.invalid_char) { - if (decoder.pad_char) |pad_char| { - if (c == pad_char) { - leftover_idx = src_idx; - break; - } - } - if (decoder_with_ignore.char_is_ignored[Base64Decoder.invalid_char]) continue; - return error.InvalidCharacter; - } - acc = (acc << 6) + d; - acc_len += 6; - if (acc_len >= 8) { - if (dest_idx == dest.len) return error.NoSpaceLeft; - acc_len -= 8; - dest[dest_idx] = @as(u8, @truncate(acc >> acc_len)); - dest_idx += 1; - } - } - if (acc_len > 4 or (acc & (@as(u12, 1) << acc_len) - 1) != 0) return error.InvalidPadding; - - if (decoder.pad_char) |pad_char| { - const padding_len = acc_len / 2; - - if (leftover_idx) |idx| { - const leftover = source[idx..]; - var padding_chars: usize = 0; - for (leftover) |c| { - if (decoder_with_ignore.char_is_ignored[c]) continue; - if (c != pad_char) { - return if (c == Base64Decoder.invalid_char) error.InvalidCharacter else error.InvalidPadding; - } - padding_chars += 1; - } - if (padding_chars != padding_len) return error.InvalidPadding; - } else if (padding_len > 0) { - return error.InvalidPadding; - } - } - } - }; - - fn testBase64() !void { - const codecs = standard; - - try testAllApis(codecs, "", ""); - try testAllApis(codecs, "f", "Zg=="); - try testAllApis(codecs, "fo", "Zm8="); - try testAllApis(codecs, "foo", "Zm9v"); - try testAllApis(codecs, "foob", "Zm9vYg=="); - try testAllApis(codecs, "fooba", "Zm9vYmE="); - try testAllApis(codecs, "foobar", "Zm9vYmFy"); - - try testDecodeIgnoreSpace(codecs, "", " "); - try testDecodeIgnoreSpace(codecs, "f", "Z g= ="); - try testDecodeIgnoreSpace(codecs, "fo", " Zm8="); - try testDecodeIgnoreSpace(codecs, "foo", "Zm9v "); - try testDecodeIgnoreSpace(codecs, "foob", "Zm9vYg = = "); - try testDecodeIgnoreSpace(codecs, "fooba", "Zm9v YmE="); - try testDecodeIgnoreSpace(codecs, "foobar", " Z m 9 v Y m F y "); - - // test getting some api errors - try testError(codecs, "A", error.InvalidPadding); - try testError(codecs, "AA", error.InvalidPadding); - try testError(codecs, "AAA", error.InvalidPadding); - try testError(codecs, "A..A", error.InvalidCharacter); - try testError(codecs, "AA=A", error.InvalidPadding); - try testError(codecs, "AA/=", error.InvalidPadding); - try testError(codecs, "A/==", error.InvalidPadding); - try testError(codecs, "A===", error.InvalidPadding); - try testError(codecs, "====", error.InvalidPadding); - - try testNoSpaceLeftError(codecs, "AA=="); - try testNoSpaceLeftError(codecs, "AAA="); - try testNoSpaceLeftError(codecs, "AAAA"); - try testNoSpaceLeftError(codecs, "AAAAAA=="); - } - - fn testBase64UrlSafeNoPad() !void { - const codecs = url_safe_no_pad; - - try testAllApis(codecs, "", ""); - try testAllApis(codecs, "f", "Zg"); - try testAllApis(codecs, "fo", "Zm8"); - try testAllApis(codecs, "foo", "Zm9v"); - try testAllApis(codecs, "foob", "Zm9vYg"); - try testAllApis(codecs, "fooba", "Zm9vYmE"); - try testAllApis(codecs, "foobar", "Zm9vYmFy"); - - try testDecodeIgnoreSpace(codecs, "", " "); - try testDecodeIgnoreSpace(codecs, "f", "Z g "); - try testDecodeIgnoreSpace(codecs, "fo", " Zm8"); - try testDecodeIgnoreSpace(codecs, "foo", "Zm9v "); - try testDecodeIgnoreSpace(codecs, "foob", "Zm9vYg "); - try testDecodeIgnoreSpace(codecs, "fooba", "Zm9v YmE"); - try testDecodeIgnoreSpace(codecs, "foobar", " Z m 9 v Y m F y "); - - // test getting some api errors - try testError(codecs, "A", error.InvalidPadding); - try testError(codecs, "AAA=", error.InvalidCharacter); - try testError(codecs, "A..A", error.InvalidCharacter); - try testError(codecs, "AA=A", error.InvalidCharacter); - try testError(codecs, "AA/=", error.InvalidCharacter); - try testError(codecs, "A/==", error.InvalidCharacter); - try testError(codecs, "A===", error.InvalidCharacter); - try testError(codecs, "====", error.InvalidCharacter); - - try testNoSpaceLeftError(codecs, "AA"); - try testNoSpaceLeftError(codecs, "AAA"); - try testNoSpaceLeftError(codecs, "AAAA"); - try testNoSpaceLeftError(codecs, "AAAAAA"); - } - - fn testAllApis(codecs: Codecs, expected_decoded: []const u8, expected_encoded: []const u8) !void { - // Base64Encoder - { - var buffer: [0x100]u8 = undefined; - const encoded = codecs.Encoder.encode(&buffer, expected_decoded); - try testing.expectEqualSlices(u8, expected_encoded, encoded); - } - - // Base64Decoder - { - var buffer: [0x100]u8 = undefined; - const decoded = buffer[0..try codecs.Decoder.calcSizeForSlice(expected_encoded)]; - try codecs.Decoder.decode(decoded, expected_encoded); - try testing.expectEqualSlices(u8, expected_decoded, decoded); - } - - // Base64DecoderWithIgnore - { - const decoder_ignore_nothing = codecs.decoderWithIgnore(""); - var buffer: [0x100]u8 = undefined; - var decoded = buffer[0..try decoder_ignore_nothing.calcSizeUpperBound(expected_encoded.len)]; - const written = try decoder_ignore_nothing.decode(decoded, expected_encoded); - try testing.expect(written <= decoded.len); - try testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]); - } - } - - fn testDecodeIgnoreSpace(codecs: Codecs, expected_decoded: []const u8, encoded: []const u8) !void { - const decoder_ignore_space = codecs.decoderWithIgnore(" "); - var buffer: [0x100]u8 = undefined; - var decoded = buffer[0..try decoder_ignore_space.calcSizeUpperBound(encoded.len)]; - const written = try decoder_ignore_space.decode(decoded, encoded); - try testing.expectEqualSlices(u8, expected_decoded, decoded[0..written]); - } - - fn testError(codecs: Codecs, encoded: []const u8, expected_err: anyerror) !void { - const decoder_ignore_space = codecs.decoderWithIgnore(" "); - var buffer: [0x100]u8 = undefined; - if (codecs.Decoder.calcSizeForSlice(encoded)) |decoded_size| { - const decoded = buffer[0..decoded_size]; - if (codecs.Decoder.decode(decoded, encoded)) |_| { - return error.ExpectedError; - } else |err| if (err != expected_err) return err; - } else |err| if (err != expected_err) return err; - - if (decoder_ignore_space.decode(buffer[0..], encoded)) |_| { - return error.ExpectedError; - } else |err| if (err != expected_err) return err; - } - - fn testNoSpaceLeftError(codecs: Codecs, encoded: []const u8) !void { - const decoder_ignore_space = codecs.decoderWithIgnore(" "); - var buffer: [0x100]u8 = undefined; - const decoded = buffer[0 .. (try codecs.Decoder.calcSizeForSlice(encoded)) - 1]; - if (decoder_ignore_space.decode(decoded, encoded)) |_| { - return error.ExpectedError; - } else |err| if (err != error.NoSpaceLeft) return err; - } -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/boringssl/boringssl.zig b/src/boringssl/boringssl.zig deleted file mode 100644 index 1b6f7d58ff3b..000000000000 --- a/src/boringssl/boringssl.zig +++ /dev/null @@ -1,272 +0,0 @@ -// TODO: move all custom functions from the translated file into this file, then -// the translated file can be provided by `zig translate-c` -/// BoringSSL's translated C API -pub const c = boring; - -var loaded = false; -pub fn load() void { - if (loaded) return; - loaded = true; - boring.CRYPTO_library_init(); - bun.assert(boring.SSL_library_init() > 0); - boring.SSL_load_error_strings(); - boring.ERR_load_BIO_strings(); - boring.OpenSSL_add_all_algorithms(); - - if (!builtin.is_test) { - std.mem.doNotOptimizeAway(&OPENSSL_memory_alloc); - std.mem.doNotOptimizeAway(&OPENSSL_memory_get_size); - std.mem.doNotOptimizeAway(&OPENSSL_memory_free); - } -} - -var ctx_store: ?*boring.SSL_CTX = null; -pub fn initClient() *boring.SSL { - if (ctx_store != null) _ = boring.SSL_CTX_up_ref(ctx_store.?); - - const ctx = ctx_store orelse brk: { - ctx_store = boring.SSL_CTX.init().?; - break :brk ctx_store.?; - }; - - var ssl = boring.SSL.init(ctx); - ssl.setIsClient(true); - - return ssl; -} - -// void*, OPENSSL_memory_alloc, (size_t size) -// void, OPENSSL_memory_free, (void *ptr) -// size_t, OPENSSL_memory_get_size, (void *ptr) - -// The following three functions can be defined to override default heap -// allocation and freeing. If defined, it is the responsibility of -// |OPENSSL_memory_free| to zero out the memory before returning it to the -// system. |OPENSSL_memory_free| will not be passed NULL pointers. -// -// WARNING: These functions are called on every allocation and free in -// BoringSSL across the entire process. They may be called by any code in the -// process which calls BoringSSL, including in process initializers and thread -// destructors. When called, BoringSSL may hold pthreads locks. Any other code -// in the process which, directly or indirectly, calls BoringSSL may be on the -// call stack and may itself be using arbitrary synchronization primitives. -// -// As a result, these functions may not have the usual programming environment -// available to most C or C++ code. In particular, they may not call into -// BoringSSL, or any library which depends on BoringSSL. Any synchronization -// primitives used must tolerate every other synchronization primitive linked -// into the process, including pthreads locks. Failing to meet these constraints -// may result in deadlocks, crashes, or memory corruption. - -export fn OPENSSL_memory_alloc(size: usize) ?*anyopaque { - return bun.mimalloc.mi_malloc(size); -} - -// BoringSSL always expects memory to be zero'd -export fn OPENSSL_memory_free(ptr: *anyopaque) void { - const len = bun.mimalloc.mi_usable_size(ptr); - @memset(@as([*]u8, @ptrCast(ptr))[0..len], 0); - bun.mimalloc.mi_free(ptr); -} - -export fn OPENSSL_memory_get_size(ptr: ?*const anyopaque) usize { - return bun.mimalloc.mi_usable_size(ptr); -} - -const INET6_ADDRSTRLEN = if (bun.Environment.isWindows) 65 else 46; - -/// converts IP string to canonicalized IP string -/// return null when the IP is invalid -pub fn canonicalizeIP(addr_str: []const u8, outIP: *[INET6_ADDRSTRLEN + 1]u8) ?[]const u8 { - if (addr_str.len >= INET6_ADDRSTRLEN) { - return null; - } - var ip_std_text: [INET6_ADDRSTRLEN + 1]u8 = undefined; - // we need a null terminated string as input - bun.copy(u8, outIP, addr_str); - outIP[addr_str.len] = 0; - - var af: c_int = std.posix.AF.INET; - // get the standard text representation of the IP - if (c_ares.ares_inet_pton(af, outIP, &ip_std_text) <= 0) { - af = std.posix.AF.INET6; - if (c_ares.ares_inet_pton(af, outIP, &ip_std_text) <= 0) { - return null; - } - } - // ip_addr will contain the null-terminated string of the cannonicalized IP - if (c_ares.ares_inet_ntop(af, &ip_std_text, outIP, outIP.len) == null) { - return null; - } - // use the null-terminated size to return the string - const size = bun.len(bun.cast([*:0]u8, outIP)); - return outIP[0..size]; -} - -/// converts ASN1_OCTET_STRING to canonicalized IP string -/// return null when the IP is invalid -pub fn ip2String(ip: *boring.ASN1_OCTET_STRING, outIP: *[INET6_ADDRSTRLEN + 1]u8) ?[]const u8 { - const af: c_int = if (ip.length == 4) std.posix.AF.INET else std.posix.AF.INET6; - if (c_ares.ares_inet_ntop(af, ip.data, outIP, outIP.len) == null) { - return null; - } - - // use the null-terminated size to return the string - const size = bun.len(bun.cast([*:0]u8, outIP)); - return outIP[0..size]; -} - -/// Matches a DNS name pattern (possibly with a leading `*.` wildcard) against -/// `hostname`. Mirrors Node.js `check()` in lib/tls.js for a single pattern. -fn matchDnsName(pattern: []const u8, hostname: []const u8) bool { - if (pattern.len == 0) return false; - if (!X509.isSafeAltName(pattern, false)) return false; - - if (pattern[0] == '*') { - // RFC 6125 Section 6.4.3: Wildcard must match exactly one label. - // Enforce "*." prefix (wildcard must be leftmost and followed by a dot). - if (pattern.len >= 2 and pattern[1] == '.') { - const suffix = pattern[2..]; - // Disallow "*.tld" (suffix must contain at least one dot for proper domain hierarchy) - if (strings.containsChar(suffix, '.')) { - // Host must be at least "label.suffix" (suffix_len + 1 for dot + at least 1 char for label) - if (hostname.len > suffix.len + 1) { - const dot_index = hostname.len - suffix.len - 1; - // The character before suffix must be a dot, and there must be no other - // dots in the prefix (single-label wildcard only). - if (hostname[dot_index] == '.' and !strings.containsChar(hostname[0..dot_index], '.')) { - const host_suffix = hostname[dot_index + 1 ..]; - // RFC 4343: DNS names are case-insensitive - if (strings.eqlCaseInsensitiveASCII(suffix, host_suffix, true)) { - return true; - } - } - } - } - } - } - // RFC 4343: DNS names are case-insensitive - return strings.eqlCaseInsensitiveASCII(pattern, hostname, true); -} - -pub fn checkX509ServerIdentity( - x509: *boring.X509, - hostname: []const u8, -) bool { - const host_is_ip = strings.isIPAddress(hostname); - // Node.js: CN is consulted only when the certificate carries no - // DNS / IP / URI subjectAltName entries. Track whether any were seen. - var has_identifier_san = false; - - // we check with native code if the cert is valid - const index = boring.X509_get_ext_by_NID(x509, boring.NID_subject_alt_name, -1); - if (index >= 0) { - // we can check hostname - if (boring.X509_get_ext(x509, index)) |ext| { - const method = boring.X509V3_EXT_get(ext); - if (method != boring.X509V3_EXT_get_nid(boring.NID_subject_alt_name)) { - return false; - } - - if (host_is_ip) { - // we safely ensure buffer size with max len + 1 - var canonicalIPBuf: [INET6_ADDRSTRLEN + 1]u8 = undefined; - var certIPBuf: [INET6_ADDRSTRLEN + 1]u8 = undefined; - // we try to canonicalize the IP before comparing - const host_ip = canonicalizeIP(hostname, &canonicalIPBuf) orelse hostname; - - if (boring.X509V3_EXT_d2i(ext)) |names_| { - const names: *boring.struct_stack_st_GENERAL_NAME = bun.cast(*boring.struct_stack_st_GENERAL_NAME, names_); - defer boring.sk_GENERAL_NAME_pop_free(names, boring.sk_GENERAL_NAME_free); - for (0..boring.sk_GENERAL_NAME_num(names)) |i| { - const gen = boring.sk_GENERAL_NAME_value(names, i); - if (gen) |name| { - switch (name.name_type) { - .GEN_DNS, .GEN_URI => has_identifier_san = true, - .GEN_IPADD => { - has_identifier_san = true; - if (ip2String(name.d.ip, &certIPBuf)) |cert_ip| { - if (strings.eql(host_ip, cert_ip)) { - return true; - } - } - }, - else => {}, - } - } - } - } - } else { - if (boring.X509V3_EXT_d2i(ext)) |names_| { - const names: *boring.struct_stack_st_GENERAL_NAME = bun.cast(*boring.struct_stack_st_GENERAL_NAME, names_); - defer boring.sk_GENERAL_NAME_pop_free(names, boring.sk_GENERAL_NAME_free); - for (0..boring.sk_GENERAL_NAME_num(names)) |i| { - const gen = boring.sk_GENERAL_NAME_value(names, i); - if (gen) |name| { - switch (name.name_type) { - .GEN_IPADD, .GEN_URI => has_identifier_san = true, - .GEN_DNS => { - has_identifier_san = true; - const dnsName = name.d.dNSName; - const dnsNameSlice = dnsName.data[0..@as(usize, @intCast(dnsName.length))]; - if (matchDnsName(dnsNameSlice, hostname)) { - return true; - } - }, - else => {}, - } - } - } - } - } - } - } - - // Node.js tls.checkServerIdentity: when the certificate has no - // DNS/IP/URI subjectAltName entries, fall back to the Subject - // Common Name. Never for IP-literal hosts (RFC 2818 §3.1). - if (!host_is_ip and !has_identifier_san) { - if (boring.X509_get_subject_name(x509)) |subject| { - var last: c_int = -1; - while (true) { - const entry_idx = boring.X509_NAME_get_index_by_NID(subject, boring.NID_commonName, last); - if (entry_idx < 0) break; - last = entry_idx; - const entry = boring.X509_NAME_get_entry(subject, entry_idx) orelse continue; - const data = boring.X509_NAME_ENTRY_get_data(entry) orelse continue; - const cn_ptr = boring.ASN1_STRING_get0_data(data); - const cn_len = boring.ASN1_STRING_length(data); - if (cn_ptr == null or cn_len <= 0) continue; - const cn = cn_ptr[0..@intCast(cn_len)]; - if (matchDnsName(cn, hostname)) { - return true; - } - } - } - } - - return false; -} - -pub fn checkServerIdentity( - ssl_ptr: *boring.SSL, - hostname: []const u8, -) bool { - if (boring.SSL_get_peer_cert_chain(ssl_ptr)) |cert_chain| { - if (boring.sk_X509_value(cert_chain, 0)) |x509| { - return checkX509ServerIdentity(x509, hostname); - } - } - return false; -} - -pub const ERR_toJS = @import("../runtime/crypto/boringssl_jsc.zig").ERR_toJS; - -const X509 = @import("../runtime/api/bun/x509.zig"); -const boring = @import("../boringssl_sys/boringssl.zig"); -const builtin = @import("builtin"); -const c_ares = @import("../cares_sys/c_ares.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const strings = bun.strings; diff --git a/src/boringssl_sys/boringssl.zig b/src/boringssl_sys/boringssl.zig deleted file mode 100644 index 3b1f7f91547c..000000000000 --- a/src/boringssl_sys/boringssl.zig +++ /dev/null @@ -1,19306 +0,0 @@ -const pthread_rwlock_t = if (bun.Environment.isPosix) std.c.pthread_rwlock_t else *anyopaque; -/// `isize` alias. Kept for clarity. -/// -/// Docs from OpenSSL: -/// > ossl_ssize_t is a signed type which is large enough to fit the size of any -/// > valid memory allocation. We prefer using |size_t|, but sometimes we need a -/// > signed type for OpenSSL API compatibility. This type can be used in such -/// > cases to avoid overflow. -/// > -/// > Not all |size_t| values fit in |ossl_ssize_t|, but all |size_t| values that -/// > are sizes of or indices into C objects, can be converted without overflow. -const ossl_ssize_t = isize; - -pub const CRYPTO_THREADID = c_int; -pub const struct_asn1_null_st = opaque {}; -pub const ASN1_NULL = struct_asn1_null_st; -pub const ASN1_BOOLEAN = c_int; -pub const struct_ASN1_ITEM_st = opaque {}; -pub const ASN1_ITEM = struct_ASN1_ITEM_st; -pub const struct_asn1_object_st = opaque {}; -pub const ASN1_OBJECT = struct_asn1_object_st; -pub const struct_asn1_pctx_st = opaque {}; -pub const ASN1_PCTX = struct_asn1_pctx_st; -pub const struct_asn1_string_st = extern struct { - length: c_int, - type: c_int, - data: [*c]u8, - flags: c_long, -}; -pub const ASN1_BIT_STRING = struct_asn1_string_st; -pub const ASN1_BMPSTRING = struct_asn1_string_st; -pub const ASN1_ENUMERATED = struct_asn1_string_st; -pub const ASN1_GENERALIZEDTIME = struct_asn1_string_st; -pub const ASN1_GENERALSTRING = struct_asn1_string_st; -pub const ASN1_IA5STRING = struct_asn1_string_st; -pub const ASN1_INTEGER = struct_asn1_string_st; -pub const ASN1_OCTET_STRING = struct_asn1_string_st; -pub const ASN1_PRINTABLESTRING = struct_asn1_string_st; -pub const ASN1_STRING = struct_asn1_string_st; -pub const ASN1_T61STRING = struct_asn1_string_st; -pub const ASN1_TIME = struct_asn1_string_st; -pub const ASN1_UNIVERSALSTRING = struct_asn1_string_st; -pub const ASN1_UTCTIME = struct_asn1_string_st; -pub const ASN1_UTF8STRING = struct_asn1_string_st; -pub const ASN1_VISIBLESTRING = struct_asn1_string_st; -pub const struct_ASN1_VALUE_st = opaque {}; -pub const ASN1_VALUE = struct_ASN1_VALUE_st; -const union_unnamed_1 = extern union { - ptr: [*c]u8, - boolean: ASN1_BOOLEAN, - asn1_string: [*c]ASN1_STRING, - object: ?*ASN1_OBJECT, - integer: [*c]ASN1_INTEGER, - enumerated: [*c]ASN1_ENUMERATED, - bit_string: [*c]ASN1_BIT_STRING, - octet_string: [*c]ASN1_OCTET_STRING, - printablestring: [*c]ASN1_PRINTABLESTRING, - t61string: [*c]ASN1_T61STRING, - ia5string: [*c]ASN1_IA5STRING, - generalstring: [*c]ASN1_GENERALSTRING, - bmpstring: [*c]ASN1_BMPSTRING, - universalstring: [*c]ASN1_UNIVERSALSTRING, - utctime: [*c]ASN1_UTCTIME, - generalizedtime: [*c]ASN1_GENERALIZEDTIME, - visiblestring: [*c]ASN1_VISIBLESTRING, - utf8string: [*c]ASN1_UTF8STRING, - set: [*c]ASN1_STRING, - sequence: [*c]ASN1_STRING, - asn1_value: ?*ASN1_VALUE, -}; -pub const struct_asn1_type_st = extern struct { - type: c_int, - value: union_unnamed_1, -}; -pub const ASN1_TYPE = struct_asn1_type_st; -pub const struct_AUTHORITY_KEYID_st = opaque {}; -pub const AUTHORITY_KEYID = struct_AUTHORITY_KEYID_st; -pub const struct_BASIC_CONSTRAINTS_st = opaque {}; -pub const BASIC_CONSTRAINTS = struct_BASIC_CONSTRAINTS_st; -pub const struct_DIST_POINT_st = opaque {}; -pub const DIST_POINT = struct_DIST_POINT_st; -pub const BN_ULONG = u64; -pub const struct_bignum_st = extern struct { - d: [*c]BN_ULONG, - width: c_int, - dmax: c_int, - neg: c_int, - flags: c_int, -}; -pub const BIGNUM = struct_bignum_st; -pub const struct_DSA_SIG_st = extern struct { - r: [*c]BIGNUM, - s: [*c]BIGNUM, -}; -pub const DSA_SIG = struct_DSA_SIG_st; -pub const struct_ISSUING_DIST_POINT_st = opaque {}; -pub const ISSUING_DIST_POINT = struct_ISSUING_DIST_POINT_st; -pub const struct_NAME_CONSTRAINTS_st = opaque {}; -pub const NAME_CONSTRAINTS = struct_NAME_CONSTRAINTS_st; -pub const struct_X509_pubkey_st = opaque {}; -pub const X509_PUBKEY = struct_X509_pubkey_st; -pub const struct_Netscape_spkac_st = extern struct { - pubkey: ?*X509_PUBKEY, - challenge: [*c]ASN1_IA5STRING, -}; -pub const NETSCAPE_SPKAC = struct_Netscape_spkac_st; -pub const struct_X509_algor_st = extern struct { - algorithm: ?*ASN1_OBJECT, - parameter: [*c]ASN1_TYPE, -}; -pub const X509_ALGOR = struct_X509_algor_st; -pub const struct_Netscape_spki_st = extern struct { - spkac: [*c]NETSCAPE_SPKAC, - sig_algor: [*c]X509_ALGOR, - signature: [*c]ASN1_BIT_STRING, -}; -pub const NETSCAPE_SPKI = struct_Netscape_spki_st; -pub const struct_RIPEMD160state_st = opaque {}; -pub const RIPEMD160_CTX = struct_RIPEMD160state_st; -pub const struct_X509_VERIFY_PARAM_st = opaque {}; -pub const X509_VERIFY_PARAM = struct_X509_VERIFY_PARAM_st; -pub const struct_X509_crl_st = opaque {}; -pub const X509_CRL = struct_X509_crl_st; -pub const struct_X509_extension_st = opaque {}; -pub const X509_EXTENSION = struct_X509_extension_st; -pub const struct_x509_st = opaque { - pub fn dup(this: *X509) ?*X509 { - return X509_dup(this); - } - - pub fn ref(this: *X509) *X509 { - _ = X509_up_ref(this); - return this; - } - - pub fn free(this: *X509) void { - X509_free(this); - } -}; -pub const X509 = struct_x509_st; -pub const CRYPTO_refcount_t = u32; -pub const struct_openssl_method_common_st = extern struct { - references: c_int, - is_static: u8, -}; -pub const struct_rsa_meth_st = extern struct { - common: struct_openssl_method_common_st, - app_data: ?*anyopaque, - init: ?*const fn (?*RSA) callconv(.c) c_int, - finish: ?*const fn (?*RSA) callconv(.c) c_int, - size: ?*const fn (?*const RSA) callconv(.c) usize, - sign: ?*const fn (c_int, [*c]const u8, c_uint, [*c]u8, [*c]c_uint, ?*const RSA) callconv(.c) c_int, - sign_raw: ?*const fn (?*RSA, [*c]usize, [*c]u8, usize, [*c]const u8, usize, c_int) callconv(.c) c_int, - decrypt: ?*const fn (?*RSA, [*c]usize, [*c]u8, usize, [*c]const u8, usize, c_int) callconv(.c) c_int, - private_transform: ?*const fn (?*RSA, [*c]u8, [*c]const u8, usize) callconv(.c) c_int, - flags: c_int, -}; -pub const RSA_METHOD = struct_rsa_meth_st; -pub const struct_stack_st_void = opaque {}; -pub const struct_crypto_ex_data_st = extern struct { - sk: ?*struct_stack_st_void, -}; -pub const CRYPTO_EX_DATA = struct_crypto_ex_data_st; -pub const CRYPTO_MUTEX = pthread_rwlock_t; -pub const struct_bn_mont_ctx_st = extern struct { - RR: BIGNUM, - N: BIGNUM, - n0: [2]BN_ULONG, -}; -pub const BN_MONT_CTX = struct_bn_mont_ctx_st; -pub const struct_bn_blinding_st = opaque {}; -pub const BN_BLINDING = struct_bn_blinding_st; // boringssl/include/openssl/rsa.h:788:12: warning: struct demoted to opaque type - has bitfield -pub const struct_rsa_st = opaque {}; -pub const RSA = struct_rsa_st; -pub const struct_dsa_st = extern struct { - version: c_long, - p: [*c]BIGNUM, - q: [*c]BIGNUM, - g: [*c]BIGNUM, - pub_key: [*c]BIGNUM, - priv_key: [*c]BIGNUM, - flags: c_int, - method_mont_lock: CRYPTO_MUTEX, - method_mont_p: [*c]BN_MONT_CTX, - method_mont_q: [*c]BN_MONT_CTX, - references: CRYPTO_refcount_t, - ex_data: CRYPTO_EX_DATA, -}; -pub const DSA = struct_dsa_st; -pub const struct_dh_st = opaque {}; -pub const DH = struct_dh_st; -pub const struct_ec_key_st = opaque {}; -pub const EC_KEY = struct_ec_key_st; -const union_unnamed_2 = extern union { - ptr: ?*anyopaque, - rsa: ?*RSA, - dsa: [*c]DSA, - dh: ?*DH, - ec: ?*EC_KEY, -}; -pub const struct_evp_pkey_asn1_method_st = opaque {}; -pub const EVP_PKEY_ASN1_METHOD = struct_evp_pkey_asn1_method_st; -pub const struct_evp_pkey_st = extern struct { - references: CRYPTO_refcount_t, - type: c_int, - pkey: union_unnamed_2, - ameth: ?*const EVP_PKEY_ASN1_METHOD, -}; -pub const EVP_PKEY = struct_evp_pkey_st; -pub const struct_evp_cipher_st = opaque {}; -pub const EVP_CIPHER = struct_evp_cipher_st; -pub const struct_evp_cipher_info_st = extern struct { - cipher: ?*const EVP_CIPHER, - iv: [16]u8, -}; -pub const EVP_CIPHER_INFO = struct_evp_cipher_info_st; -pub const struct_private_key_st = extern struct { - version: c_int, - enc_algor: [*c]X509_ALGOR, - enc_pkey: [*c]ASN1_OCTET_STRING, - dec_pkey: [*c]EVP_PKEY, - key_length: c_int, - key_data: [*c]u8, - key_free: c_int, - cipher: EVP_CIPHER_INFO, -}; -pub const X509_PKEY = struct_private_key_st; -pub const struct_X509_info_st = extern struct { - x509: ?*X509, - crl: ?*X509_CRL, - x_pkey: [*c]X509_PKEY, - enc_cipher: EVP_CIPHER_INFO, - enc_len: c_int, - enc_data: [*c]u8, -}; -pub const X509_INFO = struct_X509_info_st; -pub const struct_X509_name_entry_st = opaque {}; -pub const X509_NAME_ENTRY = struct_X509_name_entry_st; -pub const struct_X509_name_st = opaque {}; -pub const X509_NAME = struct_X509_name_st; -pub const struct_X509_req_st = opaque {}; -pub const X509_REQ = struct_X509_req_st; -pub const struct_X509_sig_st = opaque {}; -pub const X509_SIG = struct_X509_sig_st; -pub const struct_bignum_ctx = opaque {}; -pub const BN_CTX = struct_bignum_ctx; -pub const BIO_METHOD = struct_bio_method_st; -// pub const struct_bio_st = extern struct { -// method: [*c]const BIO_METHOD, -// init: c_int, -// shutdown: c_int, -// flags: c_int, -// retry_reason: c_int, -// num: c_int, -// references: CRYPTO_refcount_t, -// ptr: ?*anyopaque, -// next_bio: [*c]BIO, -// num_read: usize, -// num_write: usize, -// }; -pub const BIO = struct_bio_st; -pub const bio_info_cb = ?*const fn ([*c]BIO, c_int, [*c]const u8, c_int, c_long, c_long) callconv(.c) c_long; -pub const struct_bio_method_st = extern struct { - type: c_int, - name: [*c]const u8, - bwrite: ?*const fn ([*c]BIO, [*c]const u8, c_int) callconv(.c) c_int, - bread: ?*const fn ([*c]BIO, [*c]u8, c_int) callconv(.c) c_int, - bputs: ?*const fn ([*c]BIO, [*c]const u8) callconv(.c) c_int, - bgets: ?*const fn ([*c]BIO, [*c]u8, c_int) callconv(.c) c_int, - ctrl: ?*const fn ([*c]BIO, c_int, c_long, ?*anyopaque) callconv(.c) c_long, - create: ?*const fn ([*c]BIO) callconv(.c) c_int, - destroy: ?*const fn ([*c]BIO) callconv(.c) c_int, - callback_ctrl: ?*const fn ([*c]BIO, c_int, bio_info_cb) callconv(.c) c_long, -}; -pub const struct_blake2b_state_st = opaque {}; -pub const BLAKE2B_CTX = struct_blake2b_state_st; -pub const struct_bn_gencb_st = extern struct { - arg: ?*anyopaque, - callback: ?*const fn (c_int, c_int, [*c]struct_bn_gencb_st) callconv(.c) c_int, -}; -pub const BN_GENCB = struct_bn_gencb_st; -pub const struct_buf_mem_st = extern struct { - length: usize, - data: [*c]u8, - max: usize, -}; -pub const BUF_MEM = struct_buf_mem_st; -pub const CBB = struct_cbb_st; // boringssl/include/openssl/bytestring.h:403:12: warning: struct demoted to opaque type - has bitfield -pub const struct_cbb_buffer_st = opaque {}; // boringssl/include/openssl/bytestring.h:418:12: warning: struct demoted to opaque type - has bitfield -pub const struct_cbb_child_st = opaque {}; -const union_unnamed_3 = extern union { - base: struct_cbb_buffer_st, - child: struct_cbb_child_st, -}; -pub const struct_cbb_st = extern struct { - child: [*c]CBB, - is_child: u8, - u: union_unnamed_3, -}; -pub const struct_cbs_st = extern struct { - data: [*c]const u8, - len: usize, -}; -pub const CBS = struct_cbs_st; -pub const struct_cmac_ctx_st = opaque {}; -pub const CMAC_CTX = struct_cmac_ctx_st; -pub const struct_conf_st = opaque {}; -pub const CONF = struct_conf_st; -pub const struct_conf_value_st = opaque {}; -pub const CONF_VALUE = struct_conf_value_st; -pub const struct_crypto_buffer_pool_st = opaque {}; -pub const CRYPTO_BUFFER_POOL = struct_crypto_buffer_pool_st; -pub const struct_crypto_buffer_st = opaque {}; -pub const CRYPTO_BUFFER = struct_crypto_buffer_st; -pub const struct_ctr_drbg_state_st = opaque {}; -pub const CTR_DRBG_STATE = struct_ctr_drbg_state_st; -pub const struct_ec_group_st = opaque {}; -pub const EC_GROUP = struct_ec_group_st; -pub const struct_ec_point_st = opaque {}; -pub const EC_POINT = struct_ec_point_st; -pub const struct_ecdsa_method_st = extern struct { - common: struct_openssl_method_common_st, - app_data: ?*anyopaque, - init: ?*const fn (?*EC_KEY) callconv(.c) c_int, - finish: ?*const fn (?*EC_KEY) callconv(.c) c_int, - group_order_size: ?*const fn (?*const EC_KEY) callconv(.c) usize, - sign: ?*const fn ([*c]const u8, usize, [*c]u8, [*c]c_uint, ?*EC_KEY) callconv(.c) c_int, - flags: c_int, -}; -pub const ECDSA_METHOD = struct_ecdsa_method_st; -pub const struct_ecdsa_sig_st = extern struct { - r: [*c]BIGNUM, - s: [*c]BIGNUM, -}; -pub const ECDSA_SIG = struct_ecdsa_sig_st; -pub const struct_engine_st = opaque {}; -pub const ENGINE = struct_engine_st; -pub const struct_env_md_st = opaque {}; -pub const EVP_MD = struct_env_md_st; -pub const struct_evp_pkey_ctx_st = opaque {}; -pub const EVP_PKEY_CTX = struct_evp_pkey_ctx_st; -pub const struct_evp_md_pctx_ops = opaque {}; -pub const struct_env_md_ctx_st = extern struct { - // md_data contains the hash-specific context - md_data: extern union { - data: [240]u8, - alignment: u64, - }, - // digest is the underlying digest function, or NULL if not set - digest: ?*const EVP_MD, - // pctx is an opaque pointer to additional context - pctx: ?*EVP_PKEY_CTX, - // pctx_ops points to a vtable that contains functions to manipulate pctx - pctx_ops: ?*const struct_evp_md_pctx_ops, -}; -pub const EVP_MD_CTX = struct_env_md_ctx_st; -pub const struct_evp_aead_st = opaque {}; -pub const EVP_AEAD = struct_evp_aead_st; -pub const union_evp_aead_ctx_st_state = extern union { - @"opaque": [560]u8, - alignment: u64, -}; -pub const struct_evp_aead_ctx_st = extern struct { - aead: ?*const EVP_AEAD, - state: union_evp_aead_ctx_st_state, - tag_len: u8, -}; -pub const EVP_AEAD_CTX = struct_evp_aead_ctx_st; -pub const struct_evp_cipher_ctx_st = extern struct { - cipher: ?*const EVP_CIPHER, - app_data: ?*anyopaque, - cipher_data: ?*anyopaque, - key_len: c_uint, - encrypt: c_int, - flags: u32, - oiv: [16]u8, - iv: [16]u8, - buf: [32]u8, - buf_len: c_int, - num: c_uint, - final_used: c_int, - final: [32]u8, - poisoned: c_int, -}; -pub const EVP_CIPHER_CTX = struct_evp_cipher_ctx_st; -pub const struct_evp_encode_ctx_st = extern struct { - data_used: c_uint, - data: [48]u8, - eof_seen: u8, - error_encountered: u8, -}; -pub const EVP_ENCODE_CTX = struct_evp_encode_ctx_st; -pub const struct_evp_hpke_aead_st = opaque {}; -pub const EVP_HPKE_AEAD = struct_evp_hpke_aead_st; -pub const struct_evp_hpke_ctx_st = opaque {}; -pub const EVP_HPKE_CTX = struct_evp_hpke_ctx_st; -pub const struct_evp_hpke_kdf_st = opaque {}; -pub const EVP_HPKE_KDF = struct_evp_hpke_kdf_st; -pub const struct_evp_hpke_kem_st = opaque {}; -pub const EVP_HPKE_KEM = struct_evp_hpke_kem_st; -pub const struct_evp_hpke_key_st = opaque {}; -pub const EVP_HPKE_KEY = struct_evp_hpke_key_st; -pub const struct_evp_pkey_method_st = opaque {}; -pub const EVP_PKEY_METHOD = struct_evp_pkey_method_st; -pub const struct_hmac_ctx_st = extern struct { - md: ?*const EVP_MD, - md_ctx: EVP_MD_CTX, - i_ctx: EVP_MD_CTX, - o_ctx: EVP_MD_CTX, -}; -pub const HMAC_CTX = struct_hmac_ctx_st; -pub const struct_md4_state_st = opaque {}; -pub const MD4_CTX = struct_md4_state_st; -pub const struct_md5_state_st = opaque {}; -pub const MD5_CTX = struct_md5_state_st; -pub const struct_ossl_init_settings_st = opaque {}; -pub const OPENSSL_INIT_SETTINGS = struct_ossl_init_settings_st; -pub const struct_pkcs12_st = opaque {}; -pub const PKCS12 = struct_pkcs12_st; -pub const struct_pkcs8_priv_key_info_st = opaque {}; -pub const PKCS8_PRIV_KEY_INFO = struct_pkcs8_priv_key_info_st; -pub const struct_rand_meth_st = opaque {}; -pub const RAND_METHOD = struct_rand_meth_st; -pub const struct_rc4_key_st = opaque {}; -pub const RC4_KEY = struct_rc4_key_st; -pub const struct_rsa_pss_params_st = extern struct { - hashAlgorithm: [*c]X509_ALGOR, - maskGenAlgorithm: [*c]X509_ALGOR, - saltLength: [*c]ASN1_INTEGER, - trailerField: [*c]ASN1_INTEGER, - maskHash: [*c]X509_ALGOR, -}; -pub const RSA_PSS_PARAMS = struct_rsa_pss_params_st; -pub const struct_sha256_state_st = extern struct { - h: [8]u32, - Nl: u32, - Nh: u32, - data: [64]u8, - num: c_uint, - md_len: c_uint, -}; -pub const SHA256_CTX = struct_sha256_state_st; -pub const struct_sha512_state_st = extern struct { - h: [8]u64, - num: u16, - md_len: u16, - bytes_so_far_high: u32, - bytes_so_far_low: u64, - p: [128]u8, -}; -pub const SHA512_CTX = struct_sha512_state_st; -const struct_unnamed_5 = extern struct { - h0: u32, - h1: u32, - h2: u32, - h3: u32, - h4: u32, -}; -const union_unnamed_4 = extern union { - h: [5]u32, - unnamed_0: struct_unnamed_5, -}; -pub const struct_sha_state_st = extern struct { - unnamed_0: union_unnamed_4, - Nl: u32, - Nh: u32, - data: [64]u8, - num: c_uint, -}; -pub const SHA_CTX = struct_sha_state_st; -pub const struct_spake2_ctx_st = opaque {}; -pub const SPAKE2_CTX = struct_spake2_ctx_st; -pub const struct_srtp_protection_profile_st = extern struct { - name: [*c]const u8, - id: c_ulong, -}; -pub const SRTP_PROTECTION_PROFILE = struct_srtp_protection_profile_st; -pub const struct_ssl_cipher_st = opaque {}; -pub const SSL_CIPHER = struct_ssl_cipher_st; -// pub const struct_ssl_ctx_st = opaque {}; -// pub const SSL_CTX = struct_ssl_ctx_st; -// pub const struct_ssl_st = opaque {}; -// pub const SSL = struct_ssl_st; -pub const struct_ssl_early_callback_ctx = extern struct { - ssl: ?*SSL, - client_hello: [*c]const u8, - client_hello_len: usize, - version: u16, - random: [*c]const u8, - random_len: usize, - session_id: [*c]const u8, - session_id_len: usize, - cipher_suites: [*c]const u8, - cipher_suites_len: usize, - compression_methods: [*c]const u8, - compression_methods_len: usize, - extensions: [*c]const u8, - extensions_len: usize, -}; -pub const SSL_CLIENT_HELLO = struct_ssl_early_callback_ctx; -pub const struct_ssl_ech_keys_st = opaque {}; -pub const SSL_ECH_KEYS = struct_ssl_ech_keys_st; -pub const struct_ssl_method_st = opaque {}; -pub const SSL_METHOD = struct_ssl_method_st; -pub const ssl_private_key_success: c_int = 0; -pub const ssl_private_key_retry: c_int = 1; -pub const ssl_private_key_failure: c_int = 2; -pub const enum_ssl_private_key_result_t = c_uint; -pub const struct_ssl_private_key_method_st = extern struct { - sign: ?*const fn (?*SSL, [*c]u8, [*c]usize, usize, u16, [*c]const u8, usize) callconv(.c) enum_ssl_private_key_result_t, - decrypt: ?*const fn (?*SSL, [*c]u8, [*c]usize, usize, [*c]const u8, usize) callconv(.c) enum_ssl_private_key_result_t, - complete: ?*const fn (?*SSL, [*c]u8, [*c]usize, usize) callconv(.c) enum_ssl_private_key_result_t, -}; -pub const SSL_PRIVATE_KEY_METHOD = struct_ssl_private_key_method_st; -pub const ssl_encryption_initial: c_int = 0; -pub const ssl_encryption_early_data: c_int = 1; -pub const ssl_encryption_handshake: c_int = 2; -pub const ssl_encryption_application: c_int = 3; -pub const enum_ssl_encryption_level_t = c_uint; -pub const struct_ssl_quic_method_st = extern struct { - set_read_secret: ?*const fn (?*SSL, enum_ssl_encryption_level_t, ?*const SSL_CIPHER, [*c]const u8, usize) callconv(.c) c_int, - set_write_secret: ?*const fn (?*SSL, enum_ssl_encryption_level_t, ?*const SSL_CIPHER, [*c]const u8, usize) callconv(.c) c_int, - add_handshake_data: ?*const fn (?*SSL, enum_ssl_encryption_level_t, [*c]const u8, usize) callconv(.c) c_int, - flush_flight: ?*const fn (?*SSL) callconv(.c) c_int, - send_alert: ?*const fn (?*SSL, enum_ssl_encryption_level_t, u8) callconv(.c) c_int, -}; -pub const SSL_QUIC_METHOD = struct_ssl_quic_method_st; -pub const struct_ssl_session_st = opaque {}; -pub const SSL_SESSION = struct_ssl_session_st; -pub const ssl_ticket_aead_success: c_int = 0; -pub const ssl_ticket_aead_retry: c_int = 1; -pub const ssl_ticket_aead_ignore_ticket: c_int = 2; -pub const ssl_ticket_aead_error: c_int = 3; -pub const enum_ssl_ticket_aead_result_t = c_uint; -pub const struct_ssl_ticket_aead_method_st = extern struct { - max_overhead: ?*const fn (?*SSL) callconv(.c) usize, - seal: ?*const fn (?*SSL, [*c]u8, [*c]usize, usize, [*c]const u8, usize) callconv(.c) c_int, - open: ?*const fn (?*SSL, [*c]u8, [*c]usize, usize, [*c]const u8, usize) callconv(.c) enum_ssl_ticket_aead_result_t, -}; -pub const SSL_TICKET_AEAD_METHOD = struct_ssl_ticket_aead_method_st; -pub const struct_st_ERR_FNS = opaque {}; -pub const ERR_FNS = struct_st_ERR_FNS; -pub const struct_trust_token_st = opaque {}; -pub const TRUST_TOKEN = struct_trust_token_st; -pub const struct_trust_token_client_st = opaque {}; -pub const TRUST_TOKEN_CLIENT = struct_trust_token_client_st; -pub const struct_trust_token_issuer_st = opaque {}; -pub const TRUST_TOKEN_ISSUER = struct_trust_token_issuer_st; -pub const struct_trust_token_method_st = opaque {}; -pub const TRUST_TOKEN_METHOD = struct_trust_token_method_st; -pub const struct_v3_ext_ctx = opaque {}; -pub const X509V3_CTX = struct_v3_ext_ctx; -pub const struct_x509_attributes_st = opaque {}; -pub const X509_ATTRIBUTE = struct_x509_attributes_st; -pub const struct_x509_lookup_st = opaque {}; -pub const X509_LOOKUP = struct_x509_lookup_st; -pub const struct_x509_lookup_method_st = opaque {}; -pub const X509_LOOKUP_METHOD = struct_x509_lookup_method_st; -pub const struct_x509_object_st = opaque {}; -pub const X509_OBJECT = struct_x509_object_st; -pub const struct_x509_revoked_st = opaque {}; -pub const X509_REVOKED = struct_x509_revoked_st; -pub const struct_x509_store_ctx_st = opaque {}; -pub const X509_STORE_CTX = struct_x509_store_ctx_st; -pub const struct_x509_store_st = opaque {}; -pub const X509_STORE = struct_x509_store_st; -pub const struct_x509_trust_st = extern struct { - trust: c_int, - flags: c_int, - check_trust: ?*const fn ([*c]struct_x509_trust_st, ?*X509, c_int) callconv(.c) c_int, - name: [*c]u8, - arg1: c_int, - arg2: ?*anyopaque, -}; -pub const X509_TRUST = struct_x509_trust_st; -pub const OPENSSL_BLOCK = ?*anyopaque; -pub const struct___sbuf = extern struct { - _base: [*c]u8, - _size: c_int, -}; -pub extern fn BUF_MEM_new() [*c]BUF_MEM; -pub extern fn BUF_MEM_free(buf: [*c]BUF_MEM) void; -pub extern fn BUF_MEM_reserve(buf: [*c]BUF_MEM, cap: usize) c_int; -pub extern fn BUF_MEM_grow(buf: [*c]BUF_MEM, len: usize) usize; -pub extern fn BUF_MEM_grow_clean(buf: [*c]BUF_MEM, len: usize) usize; -pub extern fn BUF_MEM_append(buf: [*c]BUF_MEM, in: ?*const anyopaque, len: usize) c_int; -pub extern fn BUF_strdup(str: [*c]const u8) [*c]u8; -pub extern fn BUF_strnlen(str: [*c]const u8, max_len: usize) usize; -pub extern fn BUF_strndup(str: [*c]const u8, size: usize) [*c]u8; -pub extern fn BUF_memdup(data: ?*const anyopaque, size: usize) ?*anyopaque; -pub extern fn BUF_strlcpy(dst: [*c]u8, src: [*c]const u8, dst_size: usize) usize; -pub extern fn BUF_strlcat(dst: [*c]u8, src: [*c]const u8, dst_size: usize) usize; -pub extern fn ERR_load_BIO_strings() void; -pub extern fn ERR_load_ERR_strings() void; -pub extern fn ERR_load_crypto_strings() void; -pub extern fn ERR_load_RAND_strings() void; -pub extern fn ERR_free_strings() void; -pub extern fn ERR_get_error() u32; -// pub extern fn ERR_get_error_line(file: [*c][*c]const u8, line: [*c]c_int) u32; -// pub extern fn ERR_get_error_line_data(file: [*c][*c]const u8, line: [*c]c_int, data: [*c][*c]const u8, flags: [*c]c_int) u32; -pub extern fn ERR_peek_error() u32; -// pub extern fn ERR_peek_error_line(file: [*c][*c]const u8, line: [*c]c_int) u32; -// pub extern fn ERR_peek_error_line_data(file: [*c][*c]const u8, line: [*c]c_int, data: [*c][*c]const u8, flags: [*c]c_int) u32; -pub extern fn ERR_peek_last_error() u32; -// pub extern fn ERR_peek_last_error_line(file: [*c][*c]const u8, line: [*c]c_int) u32; -// pub extern fn ERR_peek_last_error_line_data(file: [*c][*c]const u8, line: [*c]c_int, data: [*c][*c]const u8, flags: [*c]c_int) u32; -pub extern fn ERR_error_string_n(packed_error: u32, buf: [*c]u8, len: usize) [*c]u8; -pub extern fn ERR_lib_error_string(packed_error: u32) [*c]const u8; -pub extern fn ERR_reason_error_string(packed_error: u32) [*c]const u8; -pub const ERR_print_errors_callback_t = ?*const fn ([*c]const u8, usize, ?*anyopaque) callconv(.c) c_int; -pub const ERR_LIB_NONE: c_int = 1; -pub const ERR_LIB_SYS: c_int = 2; -pub const ERR_LIB_BN: c_int = 3; -pub const ERR_LIB_RSA: c_int = 4; -pub const ERR_LIB_DH: c_int = 5; -pub const ERR_LIB_EVP: c_int = 6; -pub const ERR_LIB_BUF: c_int = 7; -pub const ERR_LIB_OBJ: c_int = 8; -pub const ERR_LIB_PEM: c_int = 9; -pub const ERR_LIB_DSA: c_int = 10; -pub const ERR_LIB_X509: c_int = 11; -pub const ERR_LIB_ASN1: c_int = 12; -pub const ERR_LIB_CONF: c_int = 13; -pub const ERR_LIB_CRYPTO: c_int = 14; -pub const ERR_LIB_EC: c_int = 15; -pub const ERR_LIB_SSL: c_int = 16; -pub const ERR_LIB_BIO: c_int = 17; -pub const ERR_LIB_PKCS7: c_int = 18; -pub const ERR_LIB_PKCS8: c_int = 19; -pub const ERR_LIB_X509V3: c_int = 20; -pub const ERR_LIB_RAND: c_int = 21; -pub const ERR_LIB_ENGINE: c_int = 22; -pub const ERR_LIB_OCSP: c_int = 23; -pub const ERR_LIB_UI: c_int = 24; -pub const ERR_LIB_COMP: c_int = 25; -pub const ERR_LIB_ECDSA: c_int = 26; -pub const ERR_LIB_ECDH: c_int = 27; -pub const ERR_LIB_HMAC: c_int = 28; -pub const ERR_LIB_DIGEST: c_int = 29; -pub const ERR_LIB_CIPHER: c_int = 30; -pub const ERR_LIB_HKDF: c_int = 31; -pub const ERR_LIB_TRUST_TOKEN: c_int = 32; -pub const ERR_LIB_USER: c_int = 33; -pub const ERR_NUM_LIBS: c_int = 34; -pub extern fn ERR_remove_state(pid: c_ulong) void; -pub extern fn ERR_remove_thread_state(tid: [*c]const CRYPTO_THREADID) void; -pub extern fn ERR_func_error_string(packed_error: u32) [*c]const u8; -pub extern fn ERR_error_string(packed_error: u32, buf: [*c]u8) [*c]u8; -pub extern fn ERR_clear_system_error() void; -pub extern fn ERR_put_error(library: c_int, unused: c_int, reason: c_int, file: [*c]const u8, line: u32) void; -pub extern fn ERR_add_error_data(count: c_uint, ...) void; -pub extern fn ERR_add_error_dataf(format: [*c]const u8, ...) void; -pub extern fn ERR_set_error_data(data: [*c]u8, flags: c_int) void; -pub const OPENSSL_sk_free_func = ?*const fn (?*anyopaque) callconv(.c) void; -pub const OPENSSL_sk_copy_func = ?*const fn (?*anyopaque) callconv(.c) ?*anyopaque; -pub const OPENSSL_sk_cmp_func = ?*const fn ([*c]?*const anyopaque, [*c]?*const anyopaque) callconv(.c) c_int; -pub const OPENSSL_sk_call_free_func = ?*const fn (OPENSSL_sk_free_func, ?*anyopaque) callconv(.c) void; -pub const OPENSSL_sk_call_copy_func = ?*const fn (OPENSSL_sk_copy_func, ?*anyopaque) callconv(.c) ?*anyopaque; -pub const OPENSSL_sk_call_cmp_func = ?*const fn (OPENSSL_sk_cmp_func, [*c]const ?*const anyopaque, [*c]const ?*const anyopaque) callconv(.c) c_int; -pub const struct_stack_st = extern struct { - num: usize, - data: [*c]?*anyopaque, - sorted: c_int, - num_alloc: usize, - comp: OPENSSL_sk_cmp_func, -}; -pub const _STACK = struct_stack_st; -pub extern fn sk_new(comp: OPENSSL_sk_cmp_func) [*c]_STACK; -pub extern fn sk_new_null() [*c]_STACK; -pub extern fn sk_num(sk: [*c]const _STACK) usize; -pub extern fn sk_zero(sk: [*c]_STACK) void; -pub extern fn sk_value(sk: [*c]const _STACK, i: usize) ?*anyopaque; -pub extern fn sk_set(sk: [*c]_STACK, i: usize, p: ?*anyopaque) ?*anyopaque; -pub extern fn sk_free(sk: [*c]_STACK) void; -pub extern fn sk_pop_free_ex(sk: [*c]_STACK, call_free_func: OPENSSL_sk_call_free_func, free_func: OPENSSL_sk_free_func) void; -pub extern fn sk_insert(sk: [*c]_STACK, p: ?*anyopaque, where: usize) usize; -pub extern fn sk_delete(sk: [*c]_STACK, where: usize) ?*anyopaque; -pub extern fn sk_delete_ptr(sk: [*c]_STACK, p: ?*const anyopaque) ?*anyopaque; -pub extern fn sk_find(sk: [*c]const _STACK, out_index: [*c]usize, p: ?*const anyopaque, call_cmp_func: OPENSSL_sk_call_cmp_func) c_int; -pub extern fn sk_shift(sk: [*c]_STACK) ?*anyopaque; -pub extern fn sk_push(sk: [*c]_STACK, p: ?*anyopaque) usize; -pub extern fn sk_pop(sk: [*c]_STACK) ?*anyopaque; -pub extern fn sk_dup(sk: [*c]const _STACK) [*c]_STACK; -pub extern fn sk_sort(sk: [*c]_STACK, call_cmp_func: OPENSSL_sk_call_cmp_func) void; -pub extern fn sk_is_sorted(sk: [*c]const _STACK) c_int; -pub extern fn sk_set_cmp_func(sk: [*c]_STACK, comp: OPENSSL_sk_cmp_func) OPENSSL_sk_cmp_func; -pub extern fn sk_deep_copy(sk: [*c]const _STACK, call_copy_func: OPENSSL_sk_call_copy_func, copy_func: OPENSSL_sk_copy_func, call_free_func: OPENSSL_sk_call_free_func, free_func: OPENSSL_sk_free_func) [*c]_STACK; -pub extern fn sk_pop_free(sk: [*c]_STACK, free_func: OPENSSL_sk_free_func) void; -pub const OPENSSL_STRING = [*c]u8; -pub const sk_void_free_func = ?*const fn (?*anyopaque) callconv(.c) void; -pub const sk_void_copy_func = ?*const fn (?*anyopaque) callconv(.c) ?*anyopaque; -pub const sk_void_cmp_func = ?*const fn ([*c]?*const anyopaque, [*c]?*const anyopaque) callconv(.c) c_int; -pub fn sk_void_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_void_free_func, @ptrCast(@alignCast(free_func))).?(ptr); -} -pub fn sk_void_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(sk_void_copy_func, @ptrCast(@alignCast(copy_func))).?(ptr); -} -pub fn sk_void_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const anyopaque = a.*; - var b_ptr: ?*const anyopaque = b.*; - return @as(sk_void_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_void_new(arg_comp: sk_void_cmp_func) callconv(.c) ?*struct_stack_st_void { - const comp = arg_comp; - return @as(?*struct_stack_st_void, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_void_new_null() callconv(.c) ?*struct_stack_st_void { - return @as(?*struct_stack_st_void, @ptrCast(sk_new_null())); -} -pub fn sk_void_num(arg_sk: ?*const struct_stack_st_void) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_void_zero(arg_sk: ?*struct_stack_st_void) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_void_value(arg_sk: ?*const struct_stack_st_void, arg_i: usize) callconv(.c) ?*anyopaque { - const sk = arg_sk; - const i = arg_i; - return @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_void_set(arg_sk: ?*struct_stack_st_void, arg_i: usize, arg_p: ?*anyopaque) callconv(.c) ?*anyopaque { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, p); -} -pub fn sk_void_free(arg_sk: ?*struct_stack_st_void) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_void_pop_free(arg_sk: ?*struct_stack_st_void, arg_free_func: sk_void_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_void_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_void_insert(arg_sk: ?*struct_stack_st_void, arg_p: ?*anyopaque, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), p, where); -} -pub fn sk_void_delete(arg_sk: ?*struct_stack_st_void, arg_where: usize) callconv(.c) ?*anyopaque { - const sk = arg_sk; - const where = arg_where; - return sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where); -} -pub fn sk_void_delete_ptr(arg_sk: ?*struct_stack_st_void, arg_p: ?*const anyopaque) callconv(.c) ?*anyopaque { - const sk = arg_sk; - const p = arg_p; - return sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), p); -} -pub fn sk_void_find(arg_sk: ?*const struct_stack_st_void, arg_out_index: [*c]usize, arg_p: ?*const anyopaque) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, p, &sk_void_call_cmp_func); -} -pub fn sk_void_shift(arg_sk: ?*struct_stack_st_void) callconv(.c) ?*anyopaque { - const sk = arg_sk; - return sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_void_push(arg_sk: ?*struct_stack_st_void, arg_p: ?*anyopaque) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), p); -} -pub fn sk_void_pop(arg_sk: ?*struct_stack_st_void) callconv(.c) ?*anyopaque { - const sk = arg_sk; - return sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_void_dup(arg_sk: ?*const struct_stack_st_void) callconv(.c) ?*struct_stack_st_void { - const sk = arg_sk; - return @as(?*struct_stack_st_void, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_void_sort(arg_sk: ?*struct_stack_st_void) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_void_call_cmp_func); -} -pub fn sk_void_is_sorted(arg_sk: ?*const struct_stack_st_void) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_void_set_cmp_func(arg_sk: ?*struct_stack_st_void, arg_comp: sk_void_cmp_func) callconv(.c) sk_void_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_void_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_void_deep_copy(arg_sk: ?*const struct_stack_st_void, arg_copy_func: sk_void_copy_func, arg_free_func: sk_void_free_func) callconv(.c) ?*struct_stack_st_void { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_void, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_void_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_void_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const struct_stack_st_OPENSSL_STRING = opaque {}; -pub const sk_OPENSSL_STRING_free_func = ?*const fn ([*c]u8) callconv(.c) void; -pub const sk_OPENSSL_STRING_copy_func = ?*const fn ([*c]u8) callconv(.c) [*c]u8; -pub const sk_OPENSSL_STRING_cmp_func = ?*const fn ([*c][*c]const u8, [*c][*c]const u8) callconv(.c) c_int; -pub fn sk_OPENSSL_STRING_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_OPENSSL_STRING_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]u8, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_OPENSSL_STRING_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_OPENSSL_STRING_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]u8, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_OPENSSL_STRING_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const u8 = @as([*c]const u8, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const u8 = @as([*c]const u8, @ptrCast(@alignCast(b.*))); - return @as(sk_OPENSSL_STRING_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_OPENSSL_STRING_new(arg_comp: sk_OPENSSL_STRING_cmp_func) callconv(.c) ?*struct_stack_st_OPENSSL_STRING { - const comp = arg_comp; - return @as(?*struct_stack_st_OPENSSL_STRING, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_OPENSSL_STRING_new_null() callconv(.c) ?*struct_stack_st_OPENSSL_STRING { - return @as(?*struct_stack_st_OPENSSL_STRING, @ptrCast(sk_new_null())); -} -pub fn sk_OPENSSL_STRING_num(arg_sk: ?*const struct_stack_st_OPENSSL_STRING) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_OPENSSL_STRING_zero(arg_sk: ?*struct_stack_st_OPENSSL_STRING) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_OPENSSL_STRING_value(arg_sk: ?*const struct_stack_st_OPENSSL_STRING, arg_i: usize) callconv(.c) [*c]u8 { - const sk = arg_sk; - const i = arg_i; - return @as([*c]u8, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_OPENSSL_STRING_set(arg_sk: ?*struct_stack_st_OPENSSL_STRING, arg_i: usize, arg_p: [*c]u8) callconv(.c) [*c]u8 { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]u8, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_OPENSSL_STRING_free(arg_sk: ?*struct_stack_st_OPENSSL_STRING) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_OPENSSL_STRING_pop_free(arg_sk: ?*struct_stack_st_OPENSSL_STRING, arg_free_func: sk_OPENSSL_STRING_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_OPENSSL_STRING_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_OPENSSL_STRING_insert(arg_sk: ?*struct_stack_st_OPENSSL_STRING, arg_p: [*c]u8, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_OPENSSL_STRING_delete(arg_sk: ?*struct_stack_st_OPENSSL_STRING, arg_where: usize) callconv(.c) [*c]u8 { - const sk = arg_sk; - const where = arg_where; - return @as([*c]u8, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_OPENSSL_STRING_delete_ptr(arg_sk: ?*struct_stack_st_OPENSSL_STRING, arg_p: [*c]const u8) callconv(.c) [*c]u8 { - const sk = arg_sk; - const p = arg_p; - return @as([*c]u8, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_OPENSSL_STRING_find(arg_sk: ?*const struct_stack_st_OPENSSL_STRING, arg_out_index: [*c]usize, arg_p: [*c]const u8) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_OPENSSL_STRING_call_cmp_func); -} -pub fn sk_OPENSSL_STRING_shift(arg_sk: ?*struct_stack_st_OPENSSL_STRING) callconv(.c) [*c]u8 { - const sk = arg_sk; - return @as([*c]u8, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_OPENSSL_STRING_push(arg_sk: ?*struct_stack_st_OPENSSL_STRING, arg_p: [*c]u8) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_OPENSSL_STRING_pop(arg_sk: ?*struct_stack_st_OPENSSL_STRING) callconv(.c) [*c]u8 { - const sk = arg_sk; - return @as([*c]u8, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_OPENSSL_STRING_dup(arg_sk: ?*const struct_stack_st_OPENSSL_STRING) callconv(.c) ?*struct_stack_st_OPENSSL_STRING { - const sk = arg_sk; - return @as(?*struct_stack_st_OPENSSL_STRING, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_OPENSSL_STRING_sort(arg_sk: ?*struct_stack_st_OPENSSL_STRING) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_OPENSSL_STRING_call_cmp_func); -} -pub fn sk_OPENSSL_STRING_is_sorted(arg_sk: ?*const struct_stack_st_OPENSSL_STRING) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_OPENSSL_STRING_set_cmp_func(arg_sk: ?*struct_stack_st_OPENSSL_STRING, arg_comp: sk_OPENSSL_STRING_cmp_func) callconv(.c) sk_OPENSSL_STRING_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_OPENSSL_STRING_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_OPENSSL_STRING_deep_copy(arg_sk: ?*const struct_stack_st_OPENSSL_STRING, arg_copy_func: sk_OPENSSL_STRING_copy_func, arg_free_func: sk_OPENSSL_STRING_free_func) callconv(.c) ?*struct_stack_st_OPENSSL_STRING { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_OPENSSL_STRING, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_OPENSSL_STRING_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_OPENSSL_STRING_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const CRYPTO_EX_free = fn (?*anyopaque, ?*anyopaque, [*c]CRYPTO_EX_DATA, c_int, c_long, ?*anyopaque) callconv(.c) void; -pub extern fn CRYPTO_cleanup_all_ex_data() void; -pub const CRYPTO_EX_dup = fn ([*c]CRYPTO_EX_DATA, [*c]const CRYPTO_EX_DATA, [*c]?*anyopaque, c_int, c_long, ?*anyopaque) callconv(.c) c_int; -pub const CRYPTO_EX_unused = c_int; -pub extern fn CRYPTO_num_locks() c_int; -pub extern fn CRYPTO_set_locking_callback(func: ?*const fn (c_int, c_int, [*c]const u8, c_int) callconv(.c) void) void; -pub extern fn CRYPTO_set_add_lock_callback(func: ?*const fn ([*c]c_int, c_int, c_int, [*c]const u8, c_int) callconv(.c) c_int) void; -pub extern fn CRYPTO_get_locking_callback() ?*const fn (c_int, c_int, [*c]const u8, c_int) callconv(.c) void; -pub extern fn CRYPTO_get_lock_name(lock_num: c_int) [*c]const u8; -pub extern fn CRYPTO_THREADID_set_callback(threadid_func: ?*const fn ([*c]CRYPTO_THREADID) callconv(.c) void) c_int; -pub extern fn CRYPTO_THREADID_set_numeric(id: [*c]CRYPTO_THREADID, val: c_ulong) void; -pub extern fn CRYPTO_THREADID_set_pointer(id: [*c]CRYPTO_THREADID, ptr: ?*anyopaque) void; -pub extern fn CRYPTO_THREADID_current(id: [*c]CRYPTO_THREADID) void; -pub extern fn CRYPTO_set_id_callback(func: ?*const fn () callconv(.c) c_ulong) void; -pub const struct_CRYPTO_dynlock_value = opaque {}; -pub const CRYPTO_dynlock = extern struct { - references: c_int, - data: ?*struct_CRYPTO_dynlock_value, -}; -pub extern fn CRYPTO_set_dynlock_create_callback(dyn_create_function: ?*const fn ([*c]const u8, c_int) callconv(.c) ?*struct_CRYPTO_dynlock_value) void; -pub extern fn CRYPTO_set_dynlock_lock_callback(dyn_lock_function: ?*const fn (c_int, ?*struct_CRYPTO_dynlock_value, [*c]const u8, c_int) callconv(.c) void) void; -pub extern fn CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function: ?*const fn (?*struct_CRYPTO_dynlock_value, [*c]const u8, c_int) callconv(.c) void) void; -pub extern fn CRYPTO_get_dynlock_create_callback() ?*const fn ([*c]const u8, c_int) callconv(.c) ?*struct_CRYPTO_dynlock_value; -pub extern fn CRYPTO_get_dynlock_lock_callback() ?*const fn (c_int, ?*struct_CRYPTO_dynlock_value, [*c]const u8, c_int) callconv(.c) void; -pub extern fn CRYPTO_get_dynlock_destroy_callback() ?*const fn (?*struct_CRYPTO_dynlock_value, [*c]const u8, c_int) callconv(.c) void; -pub const struct_stack_st_BIO = opaque {}; -pub const sk_BIO_free_func = ?*const fn ([*c]BIO) callconv(.c) void; -pub const sk_BIO_copy_func = ?*const fn ([*c]BIO) callconv(.c) [*c]BIO; -pub const sk_BIO_cmp_func = ?*const fn ([*c][*c]const BIO, [*c][*c]const BIO) callconv(.c) c_int; -pub fn sk_BIO_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_BIO_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]BIO, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_BIO_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_BIO_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]BIO, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_BIO_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const BIO = @as([*c]const BIO, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const BIO = @as([*c]const BIO, @ptrCast(@alignCast(b.*))); - return @as(sk_BIO_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_BIO_new(arg_comp: sk_BIO_cmp_func) callconv(.c) ?*struct_stack_st_BIO { - const comp = arg_comp; - return @as(?*struct_stack_st_BIO, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_BIO_new_null() callconv(.c) ?*struct_stack_st_BIO { - return @as(?*struct_stack_st_BIO, @ptrCast(sk_new_null())); -} -pub fn sk_BIO_num(arg_sk: ?*const struct_stack_st_BIO) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_BIO_zero(arg_sk: ?*struct_stack_st_BIO) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_BIO_value(arg_sk: ?*const struct_stack_st_BIO, arg_i: usize) callconv(.c) [*c]BIO { - const sk = arg_sk; - const i = arg_i; - return @as([*c]BIO, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_BIO_set(arg_sk: ?*struct_stack_st_BIO, arg_i: usize, arg_p: [*c]BIO) callconv(.c) [*c]BIO { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]BIO, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_BIO_free(arg_sk: ?*struct_stack_st_BIO) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_BIO_pop_free(arg_sk: ?*struct_stack_st_BIO, arg_free_func: sk_BIO_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_BIO_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_BIO_insert(arg_sk: ?*struct_stack_st_BIO, arg_p: [*c]BIO, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_BIO_delete(arg_sk: ?*struct_stack_st_BIO, arg_where: usize) callconv(.c) [*c]BIO { - const sk = arg_sk; - const where = arg_where; - return @as([*c]BIO, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_BIO_delete_ptr(arg_sk: ?*struct_stack_st_BIO, arg_p: [*c]const BIO) callconv(.c) [*c]BIO { - const sk = arg_sk; - const p = arg_p; - return @as([*c]BIO, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_BIO_find(arg_sk: ?*const struct_stack_st_BIO, arg_out_index: [*c]usize, arg_p: [*c]const BIO) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_BIO_call_cmp_func); -} -pub fn sk_BIO_shift(arg_sk: ?*struct_stack_st_BIO) callconv(.c) [*c]BIO { - const sk = arg_sk; - return @as([*c]BIO, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_BIO_push(arg_sk: ?*struct_stack_st_BIO, arg_p: [*c]BIO) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_BIO_pop(arg_sk: ?*struct_stack_st_BIO) callconv(.c) [*c]BIO { - const sk = arg_sk; - return @as([*c]BIO, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_BIO_dup(arg_sk: ?*const struct_stack_st_BIO) callconv(.c) ?*struct_stack_st_BIO { - const sk = arg_sk; - return @as(?*struct_stack_st_BIO, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_BIO_sort(arg_sk: ?*struct_stack_st_BIO) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_BIO_call_cmp_func); -} -pub fn sk_BIO_is_sorted(arg_sk: ?*const struct_stack_st_BIO) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_BIO_set_cmp_func(arg_sk: ?*struct_stack_st_BIO, arg_comp: sk_BIO_cmp_func) callconv(.c) sk_BIO_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_BIO_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_BIO_deep_copy(arg_sk: ?*const struct_stack_st_BIO, arg_copy_func: sk_BIO_copy_func, arg_free_func: sk_BIO_free_func) callconv(.c) ?*struct_stack_st_BIO { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_BIO, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_BIO_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_BIO_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn BIO_new(method: [*c]const BIO_METHOD) ?*BIO; -pub extern fn BIO_free(bio: [*c]BIO) c_int; -pub extern fn BIO_vfree(bio: [*c]BIO) void; -pub extern fn BIO_up_ref(bio: [*c]BIO) c_int; -pub extern fn BIO_read(bio: [*c]BIO, data: ?*anyopaque, len: c_int) c_int; -pub extern fn BIO_gets(bio: [*c]BIO, buf: [*c]u8, size: c_int) c_int; -pub extern fn BIO_write(bio: [*c]BIO, data: ?*const anyopaque, len: c_int) c_int; -pub extern fn BIO_write_all(bio: [*c]BIO, data: ?*const anyopaque, len: usize) c_int; -pub extern fn BIO_puts(bio: [*c]BIO, buf: [*c]const u8) c_int; -pub extern fn BIO_flush(bio: [*c]BIO) c_int; -pub extern fn BIO_ctrl(bio: [*c]BIO, cmd: c_int, larg: c_long, parg: ?*anyopaque) c_long; -pub extern fn BIO_ptr_ctrl(bp: [*c]BIO, cmd: c_int, larg: c_long) [*c]u8; -pub extern fn BIO_int_ctrl(bp: [*c]BIO, cmd: c_int, larg: c_long, iarg: c_int) c_long; -pub extern fn BIO_reset(bio: [*c]BIO) c_int; -pub extern fn BIO_eof(bio: [*c]BIO) c_int; -pub extern fn BIO_set_flags(bio: [*c]BIO, flags: c_int) void; -pub extern fn BIO_test_flags(bio: [*c]const BIO, flags: c_int) c_int; -pub extern fn BIO_should_read(bio: [*c]const BIO) c_int; -pub extern fn BIO_should_write(bio: [*c]const BIO) c_int; -pub extern fn BIO_should_retry(bio: [*c]const BIO) c_int; -pub extern fn BIO_should_io_special(bio: [*c]const BIO) c_int; -pub extern fn BIO_get_retry_reason(bio: [*c]const BIO) c_int; -pub extern fn BIO_set_retry_reason(bio: [*c]BIO, reason: c_int) void; -pub extern fn BIO_clear_flags(bio: [*c]BIO, flags: c_int) void; -pub extern fn BIO_set_retry_read(bio: [*c]BIO) void; -pub extern fn BIO_set_retry_write(bio: [*c]BIO) void; -pub extern fn BIO_get_retry_flags(bio: [*c]BIO) c_int; -pub extern fn BIO_clear_retry_flags(bio: [*c]BIO) void; -pub extern fn BIO_method_type(bio: [*c]const BIO) c_int; -pub extern fn BIO_callback_ctrl(bio: [*c]BIO, cmd: c_int, fp: bio_info_cb) c_long; -pub extern fn BIO_pending(bio: [*c]const BIO) usize; -pub extern fn BIO_ctrl_pending(bio: [*c]const BIO) usize; -pub extern fn BIO_wpending(bio: [*c]const BIO) usize; -pub extern fn BIO_set_close(bio: [*c]BIO, close_flag: c_int) c_int; -pub extern fn BIO_number_read(bio: [*c]const BIO) usize; -pub extern fn BIO_number_written(bio: [*c]const BIO) usize; -pub extern fn BIO_push(bio: [*c]BIO, appended_bio: [*c]BIO) [*c]BIO; -pub extern fn BIO_pop(bio: [*c]BIO) [*c]BIO; -pub extern fn BIO_next(bio: [*c]BIO) [*c]BIO; -pub extern fn BIO_free_all(bio: [*c]BIO) void; -pub extern fn BIO_find_type(bio: [*c]BIO, @"type": c_int) [*c]BIO; -pub extern fn BIO_copy_next_retry(bio: [*c]BIO) void; -pub extern fn BIO_printf(bio: [*c]BIO, format: [*c]const u8, ...) c_int; -pub extern fn BIO_indent(bio: [*c]BIO, indent: c_uint, max_indent: c_uint) c_int; -pub extern fn BIO_hexdump(bio: [*c]BIO, data: [*c]const u8, len: usize, indent: c_uint) c_int; -pub extern fn ERR_print_errors(bio: [*c]BIO) void; -pub extern fn BIO_read_asn1(bio: [*c]BIO, out: [*c][*c]u8, out_len: [*c]usize, max_len: usize) c_int; -pub extern fn BIO_s_mem() ?*const BIO_METHOD; - -/// BIO_new_mem_buf creates read-only BIO that reads from |len| bytes at |buf|. -/// It returns the BIO or NULL on error. This function does not copy or take -/// ownership of |buf|. The caller must ensure the memory pointed to by |buf| -/// outlives the |BIO|. -/// -/// If |len| is negative, then |buf| is treated as a NUL-terminated string, but -/// don't depend on this in new code. -pub extern fn BIO_new_mem_buf(buf: ?*const anyopaque, len: ossl_ssize_t) [*c]BIO; -// pub extern fn BIO_mem_contents(bio: [*c]const BIO, out_contents: [*c][*c]const u8, out_len: [*c]usize) c_int; -pub extern fn BIO_get_mem_data(bio: [*c]BIO, contents: [*c][*c]u8) c_long; -pub extern fn BIO_get_mem_ptr(bio: [*c]BIO, out: [*c][*c]BUF_MEM) c_int; -pub extern fn BIO_set_mem_buf(bio: [*c]BIO, b: [*c]BUF_MEM, take_ownership: c_int) c_int; -pub extern fn BIO_set_mem_eof_return(bio: [*c]BIO, eof_value: c_int) c_int; -pub extern fn BIO_s_fd() [*c]const BIO_METHOD; -pub extern fn BIO_new_fd(fd: c_int, close_flag: c_int) [*c]BIO; -pub extern fn BIO_set_fd(bio: [*c]BIO, fd: c_int, close_flag: c_int) c_int; -pub extern fn BIO_get_fd(bio: [*c]BIO, out_fd: [*c]c_int) c_int; -// pub extern fn BIO_s_file() [*c]const BIO_METHOD; -pub extern fn BIO_new_file(filename: [*c]const u8, mode: [*c]const u8) [*c]BIO; -// pub extern fn BIO_new_fp(stream: [*c]FILE, close_flag: c_int) [*c]BIO; -// pub extern fn BIO_get_fp(bio: [*c]BIO, out_file: [*c][*c]FILE) c_int; -// pub extern fn BIO_set_fp(bio: [*c]BIO, file: [*c]FILE, close_flag: c_int) c_int; -pub extern fn BIO_read_filename(bio: [*c]BIO, filename: [*c]const u8) c_int; -pub extern fn BIO_write_filename(bio: [*c]BIO, filename: [*c]const u8) c_int; -pub extern fn BIO_append_filename(bio: [*c]BIO, filename: [*c]const u8) c_int; -pub extern fn BIO_rw_filename(bio: [*c]BIO, filename: [*c]const u8) c_int; -// pub extern fn BIO_tell(bio: [*c]BIO) c_long; -// pub extern fn BIO_seek(bio: [*c]BIO, offset: c_long) c_long; -// pub extern fn BIO_s_socket() [*c]const BIO_METHOD; -// pub extern fn BIO_new_socket(fd: c_int, close_flag: c_int) [*c]BIO; -// pub extern fn BIO_s_connect() [*c]const BIO_METHOD; -// pub extern fn BIO_new_connect(host_and_optional_port: [*c]const u8) [*c]BIO; -// pub extern fn BIO_set_conn_hostname(bio: [*c]BIO, host_and_optional_port: [*c]const u8) c_int; -// pub extern fn BIO_set_conn_port(bio: [*c]BIO, port_str: [*c]const u8) c_int; -// pub extern fn BIO_set_conn_int_port(bio: [*c]BIO, port: [*c]const c_int) c_int; -// pub extern fn BIO_set_nbio(bio: [*c]BIO, on: c_int) c_int; -// pub extern fn BIO_do_connect(bio: [*c]BIO) c_int; -// pub extern fn BIO_new_bio_pair(out1: [*c][*c]BIO, writebuf1: usize, out2: [*c][*c]BIO, writebuf2: usize) c_int; -// pub extern fn BIO_ctrl_get_read_request(bio: [*c]BIO) usize; -// pub extern fn BIO_ctrl_get_write_guarantee(bio: [*c]BIO) usize; -// pub extern fn BIO_shutdown_wr(bio: [*c]BIO) c_int; -pub extern fn BIO_get_new_index() c_int; -pub extern fn BIO_meth_new(@"type": c_int, name: [*c]const u8) [*c]BIO_METHOD; -pub extern fn BIO_meth_free(method: [*c]BIO_METHOD) void; -pub extern fn BIO_meth_set_create(method: [*c]BIO_METHOD, create: ?*const fn ([*c]BIO) callconv(.c) c_int) c_int; -pub extern fn BIO_meth_set_destroy(method: [*c]BIO_METHOD, destroy: ?*const fn ([*c]BIO) callconv(.c) c_int) c_int; -pub extern fn BIO_meth_set_write(method: [*c]BIO_METHOD, write: ?*const fn ([*c]BIO, [*c]const u8, c_int) callconv(.c) c_int) c_int; -pub extern fn BIO_meth_set_read(method: [*c]BIO_METHOD, read: ?*const fn ([*c]BIO, [*c]u8, c_int) callconv(.c) c_int) c_int; -pub extern fn BIO_meth_set_gets(method: [*c]BIO_METHOD, gets: ?*const fn ([*c]BIO, [*c]u8, c_int) callconv(.c) c_int) c_int; -pub extern fn BIO_meth_set_ctrl(method: [*c]BIO_METHOD, ctrl: ?*const fn ([*c]BIO, c_int, c_long, ?*anyopaque) callconv(.c) c_long) c_int; -pub extern fn BIO_set_data(bio: [*c]BIO, ptr: ?*anyopaque) void; -pub extern fn BIO_get_data(bio: [*c]BIO) ?*anyopaque; -pub extern fn BIO_set_init(bio: [*c]BIO, init: c_int) void; -pub extern fn BIO_get_init(bio: [*c]BIO) c_int; -pub extern fn BIO_f_base64() [*c]const BIO_METHOD; -pub extern fn BIO_set_retry_special(bio: [*c]BIO) void; -pub extern fn BIO_set_write_buffer_size(bio: [*c]BIO, buffer_size: c_int) c_int; -pub extern fn BIO_set_shutdown(bio: [*c]BIO, shutdown: c_int) void; -pub extern fn BIO_get_shutdown(bio: [*c]BIO) c_int; -pub extern fn BIO_meth_set_puts(method: [*c]BIO_METHOD, puts: ?*const fn ([*c]BIO, [*c]const u8) callconv(.c) c_int) c_int; -pub extern fn EVP_EncodeBlock(dst: [*c]u8, src: [*c]const u8, src_len: usize) usize; -pub extern fn EVP_EncodedLength(out_len: [*c]usize, len: usize) c_int; -pub extern fn EVP_DecodedLength(out_len: [*c]usize, len: usize) c_int; -pub extern fn EVP_DecodeBase64(out: [*c]u8, out_len: [*c]usize, max_out: usize, in: [*c]const u8, in_len: usize) c_int; -pub extern fn EVP_ENCODE_CTX_new() [*c]EVP_ENCODE_CTX; -pub extern fn EVP_ENCODE_CTX_free(ctx: [*c]EVP_ENCODE_CTX) void; -pub extern fn EVP_EncodeInit(ctx: [*c]EVP_ENCODE_CTX) void; -pub extern fn EVP_EncodeUpdate(ctx: [*c]EVP_ENCODE_CTX, out: [*c]u8, out_len: [*c]c_int, in: [*c]const u8, in_len: usize) void; -pub extern fn EVP_EncodeFinal(ctx: [*c]EVP_ENCODE_CTX, out: [*c]u8, out_len: [*c]c_int) void; -pub extern fn EVP_DecodeInit(ctx: [*c]EVP_ENCODE_CTX) void; -pub extern fn EVP_DecodeUpdate(ctx: [*c]EVP_ENCODE_CTX, out: [*c]u8, out_len: [*c]c_int, in: [*c]const u8, in_len: usize) c_int; -pub extern fn EVP_DecodeFinal(ctx: [*c]EVP_ENCODE_CTX, out: [*c]u8, out_len: [*c]c_int) c_int; -pub extern fn EVP_DecodeBlock(dst: [*c]u8, src: [*c]const u8, src_len: usize) c_int; -pub extern fn EVP_rc4() ?*const EVP_CIPHER; -pub extern fn EVP_des_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_des_ecb() ?*const EVP_CIPHER; -pub extern fn EVP_des_ede() ?*const EVP_CIPHER; -pub extern fn EVP_des_ede3() ?*const EVP_CIPHER; -pub extern fn EVP_des_ede_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_des_ede3_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_aes_128_ecb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_128_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_aes_128_ctr() ?*const EVP_CIPHER; -pub extern fn EVP_aes_128_ofb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_ecb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_ctr() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_ofb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_xts() ?*const EVP_CIPHER; -pub extern fn EVP_enc_null() ?*const EVP_CIPHER; -pub extern fn EVP_rc2_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_rc2_40_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_get_cipherbynid(nid: c_int) ?*const EVP_CIPHER; -pub extern fn EVP_CIPHER_CTX_init(ctx: [*c]EVP_CIPHER_CTX) void; -pub extern fn EVP_CIPHER_CTX_new() [*c]EVP_CIPHER_CTX; -pub extern fn EVP_CIPHER_CTX_cleanup(ctx: [*c]EVP_CIPHER_CTX) c_int; -pub extern fn EVP_CIPHER_CTX_free(ctx: [*c]EVP_CIPHER_CTX) void; -pub extern fn EVP_CIPHER_CTX_copy(out: [*c]EVP_CIPHER_CTX, in: [*c]const EVP_CIPHER_CTX) c_int; -pub extern fn EVP_CIPHER_CTX_reset(ctx: [*c]EVP_CIPHER_CTX) c_int; -pub extern fn EVP_CipherInit_ex(ctx: [*c]EVP_CIPHER_CTX, cipher: ?*const EVP_CIPHER, engine: ?*ENGINE, key: [*c]const u8, iv: [*c]const u8, enc: c_int) c_int; -pub extern fn EVP_EncryptInit_ex(ctx: [*c]EVP_CIPHER_CTX, cipher: ?*const EVP_CIPHER, impl: ?*ENGINE, key: [*c]const u8, iv: [*c]const u8) c_int; -pub extern fn EVP_DecryptInit_ex(ctx: [*c]EVP_CIPHER_CTX, cipher: ?*const EVP_CIPHER, impl: ?*ENGINE, key: [*c]const u8, iv: [*c]const u8) c_int; -pub extern fn EVP_EncryptUpdate(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int, in: [*c]const u8, in_len: c_int) c_int; -pub extern fn EVP_EncryptFinal_ex(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int) c_int; -pub extern fn EVP_DecryptUpdate(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int, in: [*c]const u8, in_len: c_int) c_int; -pub extern fn EVP_DecryptFinal_ex(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int) c_int; -pub extern fn EVP_CipherUpdate(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int, in: [*c]const u8, in_len: c_int) c_int; -pub extern fn EVP_CipherFinal_ex(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int) c_int; -pub extern fn EVP_CIPHER_CTX_cipher(ctx: [*c]const EVP_CIPHER_CTX) ?*const EVP_CIPHER; -pub extern fn EVP_CIPHER_CTX_nid(ctx: [*c]const EVP_CIPHER_CTX) c_int; -pub extern fn EVP_CIPHER_CTX_encrypting(ctx: [*c]const EVP_CIPHER_CTX) c_int; -pub extern fn EVP_CIPHER_CTX_block_size(ctx: [*c]const EVP_CIPHER_CTX) c_uint; -pub extern fn EVP_CIPHER_CTX_key_length(ctx: [*c]const EVP_CIPHER_CTX) c_uint; -pub extern fn EVP_CIPHER_CTX_iv_length(ctx: [*c]const EVP_CIPHER_CTX) c_uint; -pub extern fn EVP_CIPHER_CTX_get_app_data(ctx: [*c]const EVP_CIPHER_CTX) ?*anyopaque; -pub extern fn EVP_CIPHER_CTX_set_app_data(ctx: [*c]EVP_CIPHER_CTX, data: ?*anyopaque) void; -pub extern fn EVP_CIPHER_CTX_flags(ctx: [*c]const EVP_CIPHER_CTX) u32; -pub extern fn EVP_CIPHER_CTX_mode(ctx: [*c]const EVP_CIPHER_CTX) u32; -pub extern fn EVP_CIPHER_CTX_ctrl(ctx: [*c]EVP_CIPHER_CTX, command: c_int, arg: c_int, ptr: ?*anyopaque) c_int; -pub extern fn EVP_CIPHER_CTX_set_padding(ctx: [*c]EVP_CIPHER_CTX, pad: c_int) c_int; -pub extern fn EVP_CIPHER_CTX_set_key_length(ctx: [*c]EVP_CIPHER_CTX, key_len: c_uint) c_int; -pub extern fn EVP_CIPHER_nid(cipher: ?*const EVP_CIPHER) c_int; -pub extern fn EVP_CIPHER_block_size(cipher: ?*const EVP_CIPHER) c_uint; -pub extern fn EVP_CIPHER_key_length(cipher: ?*const EVP_CIPHER) c_uint; -pub extern fn EVP_CIPHER_iv_length(cipher: ?*const EVP_CIPHER) c_uint; -pub extern fn EVP_CIPHER_flags(cipher: ?*const EVP_CIPHER) u32; -pub extern fn EVP_CIPHER_mode(cipher: ?*const EVP_CIPHER) u32; -pub extern fn EVP_BytesToKey(@"type": ?*const EVP_CIPHER, md: ?*const EVP_MD, salt: [*c]const u8, data: [*c]const u8, data_len: usize, count: c_uint, key: [*c]u8, iv: [*c]u8) c_int; -pub extern fn EVP_CipherInit(ctx: [*c]EVP_CIPHER_CTX, cipher: ?*const EVP_CIPHER, key: [*c]const u8, iv: [*c]const u8, enc: c_int) c_int; -pub extern fn EVP_EncryptInit(ctx: [*c]EVP_CIPHER_CTX, cipher: ?*const EVP_CIPHER, key: [*c]const u8, iv: [*c]const u8) c_int; -pub extern fn EVP_DecryptInit(ctx: [*c]EVP_CIPHER_CTX, cipher: ?*const EVP_CIPHER, key: [*c]const u8, iv: [*c]const u8) c_int; -pub extern fn EVP_CipherFinal(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int) c_int; -pub extern fn EVP_EncryptFinal(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int) c_int; -pub extern fn EVP_DecryptFinal(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, out_len: [*c]c_int) c_int; -pub extern fn EVP_Cipher(ctx: [*c]EVP_CIPHER_CTX, out: [*c]u8, in: [*c]const u8, in_len: usize) c_int; -pub extern fn EVP_add_cipher_alias(a: [*c]const u8, b: [*c]const u8) c_int; -pub extern fn EVP_get_cipherbyname(name: [*c]const u8) ?*const EVP_CIPHER; -pub extern fn EVP_aes_128_gcm() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_gcm() ?*const EVP_CIPHER; -pub extern fn EVP_aes_192_ecb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_192_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_aes_192_ctr() ?*const EVP_CIPHER; -pub extern fn EVP_aes_192_gcm() ?*const EVP_CIPHER; -pub extern fn EVP_aes_192_ofb() ?*const EVP_CIPHER; -pub extern fn EVP_des_ede3_ecb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_128_cfb128() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_cfb128() ?*const EVP_CIPHER; -pub extern fn EVP_aes_128_cfb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_192_cfb128() ?*const EVP_CIPHER; -pub extern fn EVP_aes_192_cfb() ?*const EVP_CIPHER; -pub extern fn EVP_aes_256_cfb() ?*const EVP_CIPHER; -pub extern fn EVP_bf_ecb() ?*const EVP_CIPHER; -pub extern fn EVP_bf_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_bf_cfb() ?*const EVP_CIPHER; -pub extern fn EVP_cast5_ecb() ?*const EVP_CIPHER; -pub extern fn EVP_cast5_cbc() ?*const EVP_CIPHER; -pub extern fn EVP_CIPHER_CTX_set_flags(ctx: [*c]const EVP_CIPHER_CTX, flags: u32) void; -pub extern fn EVP_md5_sha1() ?*const EVP_MD; -pub extern fn EVP_ripemd160() ?*const EVP_MD; -pub extern fn EVP_get_digestbynid(nid: c_int) ?*const EVP_MD; -pub extern fn EVP_get_digestbyobj(obj: ?*const ASN1_OBJECT) ?*const EVP_MD; -pub extern fn EVP_MD_CTX_init(ctx: [*c]EVP_MD_CTX) void; -pub extern fn EVP_MD_CTX_new() [*c]EVP_MD_CTX; -pub extern fn EVP_MD_CTX_cleanup(ctx: [*c]EVP_MD_CTX) c_int; -pub extern fn EVP_MD_CTX_cleanse(ctx: [*c]EVP_MD_CTX) void; -pub extern fn EVP_MD_CTX_free(ctx: [*c]EVP_MD_CTX) void; -pub extern fn EVP_MD_CTX_copy_ex(out: [*c]EVP_MD_CTX, in: [*c]const EVP_MD_CTX) c_int; -pub extern fn EVP_MD_CTX_move(out: [*c]EVP_MD_CTX, in: [*c]EVP_MD_CTX) void; -pub extern fn EVP_MD_CTX_reset(ctx: [*c]EVP_MD_CTX) c_int; -pub extern fn EVP_DigestInit_ex(ctx: [*c]EVP_MD_CTX, @"type": ?*const EVP_MD, engine: ?*ENGINE) c_int; -pub extern fn EVP_DigestInit(ctx: [*c]EVP_MD_CTX, @"type": ?*const EVP_MD) c_int; -pub extern fn EVP_DigestUpdate(ctx: [*c]EVP_MD_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn EVP_DigestFinal_ex(ctx: [*c]EVP_MD_CTX, md_out: [*c]u8, out_size: [*c]c_uint) c_int; -pub extern fn EVP_DigestFinal(ctx: [*c]EVP_MD_CTX, md_out: [*c]u8, out_size: [*c]c_uint) c_int; -pub extern fn EVP_Digest(data: ?*const anyopaque, len: usize, md_out: [*c]u8, md_out_size: [*c]c_uint, @"type": ?*const EVP_MD, impl: ?*ENGINE) c_int; -pub extern fn EVP_MD_type(md: ?*const EVP_MD) c_int; -pub extern fn EVP_MD_flags(md: ?*const EVP_MD) u32; -pub extern fn EVP_MD_size(md: ?*const EVP_MD) usize; -pub extern fn EVP_MD_block_size(md: ?*const EVP_MD) usize; -pub extern fn EVP_MD_CTX_md(ctx: [*c]const EVP_MD_CTX) ?*const EVP_MD; -pub extern fn EVP_MD_CTX_size(ctx: [*c]const EVP_MD_CTX) usize; -pub extern fn EVP_MD_CTX_block_size(ctx: [*c]const EVP_MD_CTX) usize; -pub extern fn EVP_MD_CTX_type(ctx: [*c]const EVP_MD_CTX) c_int; -pub extern fn EVP_parse_digest_algorithm(cbs: [*c]CBS) ?*const EVP_MD; -pub extern fn EVP_marshal_digest_algorithm(cbb: ?*CBB, md: ?*const EVP_MD) c_int; -pub extern fn EVP_MD_CTX_copy(out: [*c]EVP_MD_CTX, in: [*c]const EVP_MD_CTX) c_int; -pub extern fn EVP_add_digest(digest: ?*const EVP_MD) c_int; -pub extern fn EVP_get_digestbyname([*c]const u8) ?*const EVP_MD; -pub extern fn EVP_dss1() ?*const EVP_MD; -pub extern fn EVP_MD_CTX_create() [*c]EVP_MD_CTX; -pub extern fn EVP_MD_CTX_destroy(ctx: [*c]EVP_MD_CTX) void; -pub extern fn EVP_DigestFinalXOF(ctx: [*c]EVP_MD_CTX, out: [*c]u8, len: usize) c_int; -pub extern fn EVP_MD_meth_get_flags(md: ?*const EVP_MD) u32; -pub extern fn EVP_MD_CTX_set_flags(ctx: [*c]EVP_MD_CTX, flags: c_int) void; -pub extern fn EVP_MD_nid(md: ?*const EVP_MD) c_int; -pub extern fn EVP_aead_aes_128_gcm() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_192_gcm() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_gcm() ?*const EVP_AEAD; -pub extern fn EVP_aead_chacha20_poly1305() ?*const EVP_AEAD; -pub extern fn EVP_aead_xchacha20_poly1305() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_ctr_hmac_sha256() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_ctr_hmac_sha256() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_gcm_siv() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_gcm_siv() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_gcm_randnonce() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_gcm_randnonce() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_ccm_bluetooth() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_ccm_bluetooth_8() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_ccm_matter() ?*const EVP_AEAD; -pub extern fn EVP_has_aes_hardware() c_int; -pub extern fn EVP_AEAD_key_length(aead: ?*const EVP_AEAD) usize; -pub extern fn EVP_AEAD_nonce_length(aead: ?*const EVP_AEAD) usize; -pub extern fn EVP_AEAD_max_overhead(aead: ?*const EVP_AEAD) usize; -pub extern fn EVP_AEAD_max_tag_len(aead: ?*const EVP_AEAD) usize; -pub extern fn EVP_AEAD_CTX_zero(ctx: [*c]EVP_AEAD_CTX) void; -pub extern fn EVP_AEAD_CTX_new(aead: ?*const EVP_AEAD, key: [*c]const u8, key_len: usize, tag_len: usize) [*c]EVP_AEAD_CTX; -pub extern fn EVP_AEAD_CTX_free(ctx: [*c]EVP_AEAD_CTX) void; -pub extern fn EVP_AEAD_CTX_init(ctx: [*c]EVP_AEAD_CTX, aead: ?*const EVP_AEAD, key: [*c]const u8, key_len: usize, tag_len: usize, impl: ?*ENGINE) c_int; -pub extern fn EVP_AEAD_CTX_cleanup(ctx: [*c]EVP_AEAD_CTX) void; -pub extern fn EVP_AEAD_CTX_seal(ctx: [*c]const EVP_AEAD_CTX, out: [*c]u8, out_len: [*c]usize, max_out_len: usize, nonce: [*c]const u8, nonce_len: usize, in: [*c]const u8, in_len: usize, ad: [*c]const u8, ad_len: usize) c_int; -pub extern fn EVP_AEAD_CTX_open(ctx: [*c]const EVP_AEAD_CTX, out: [*c]u8, out_len: [*c]usize, max_out_len: usize, nonce: [*c]const u8, nonce_len: usize, in: [*c]const u8, in_len: usize, ad: [*c]const u8, ad_len: usize) c_int; -pub extern fn EVP_AEAD_CTX_seal_scatter(ctx: [*c]const EVP_AEAD_CTX, out: [*c]u8, out_tag: [*c]u8, out_tag_len: [*c]usize, max_out_tag_len: usize, nonce: [*c]const u8, nonce_len: usize, in: [*c]const u8, in_len: usize, extra_in: [*c]const u8, extra_in_len: usize, ad: [*c]const u8, ad_len: usize) c_int; -pub extern fn EVP_AEAD_CTX_open_gather(ctx: [*c]const EVP_AEAD_CTX, out: [*c]u8, nonce: [*c]const u8, nonce_len: usize, in: [*c]const u8, in_len: usize, in_tag: [*c]const u8, in_tag_len: usize, ad: [*c]const u8, ad_len: usize) c_int; -pub extern fn EVP_AEAD_CTX_aead(ctx: [*c]const EVP_AEAD_CTX) ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_cbc_sha1_tls() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_cbc_sha1_tls_implicit_iv() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_cbc_sha1_tls() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_cbc_sha1_tls_implicit_iv() ?*const EVP_AEAD; -pub extern fn EVP_aead_des_ede3_cbc_sha1_tls() ?*const EVP_AEAD; -pub extern fn EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv() ?*const EVP_AEAD; -pub extern fn EVP_aead_null_sha1_tls() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_gcm_tls12() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_gcm_tls12() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_128_gcm_tls13() ?*const EVP_AEAD; -pub extern fn EVP_aead_aes_256_gcm_tls13() ?*const EVP_AEAD; -pub const evp_aead_open: c_int = 0; -pub const evp_aead_seal: c_int = 1; -pub const enum_evp_aead_direction_t = c_uint; -pub extern fn EVP_AEAD_CTX_init_with_direction(ctx: [*c]EVP_AEAD_CTX, aead: ?*const EVP_AEAD, key: [*c]const u8, key_len: usize, tag_len: usize, dir: enum_evp_aead_direction_t) c_int; -pub extern fn EVP_AEAD_CTX_get_iv(ctx: [*c]const EVP_AEAD_CTX, out_iv: [*c][*c]const u8, out_len: [*c]usize) c_int; -pub extern fn EVP_AEAD_CTX_tag_len(ctx: [*c]const EVP_AEAD_CTX, out_tag_len: [*c]usize, in_len: usize, extra_in_len: usize) c_int; -pub extern fn EVP_PKEY_new() [*c]EVP_PKEY; -pub extern fn EVP_PKEY_free(pkey: [*c]EVP_PKEY) void; -pub extern fn EVP_PKEY_up_ref(pkey: [*c]EVP_PKEY) c_int; -pub extern fn EVP_PKEY_is_opaque(pkey: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_cmp(a: [*c]const EVP_PKEY, b: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_copy_parameters(to: [*c]EVP_PKEY, from: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_missing_parameters(pkey: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_size(pkey: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_bits(pkey: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_id(pkey: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_type(nid: c_int) c_int; -pub extern fn EVP_PKEY_set1_RSA(pkey: [*c]EVP_PKEY, key: ?*RSA) c_int; -pub extern fn EVP_PKEY_assign_RSA(pkey: [*c]EVP_PKEY, key: ?*RSA) c_int; -pub extern fn EVP_PKEY_get0_RSA(pkey: [*c]const EVP_PKEY) ?*RSA; -pub extern fn EVP_PKEY_get1_RSA(pkey: [*c]const EVP_PKEY) ?*RSA; -pub extern fn EVP_PKEY_set1_DSA(pkey: [*c]EVP_PKEY, key: [*c]DSA) c_int; -pub extern fn EVP_PKEY_assign_DSA(pkey: [*c]EVP_PKEY, key: [*c]DSA) c_int; -pub extern fn EVP_PKEY_get0_DSA(pkey: [*c]const EVP_PKEY) [*c]DSA; -pub extern fn EVP_PKEY_get1_DSA(pkey: [*c]const EVP_PKEY) [*c]DSA; -pub extern fn EVP_PKEY_set1_EC_KEY(pkey: [*c]EVP_PKEY, key: ?*EC_KEY) c_int; -pub extern fn EVP_PKEY_assign_EC_KEY(pkey: [*c]EVP_PKEY, key: ?*EC_KEY) c_int; -pub extern fn EVP_PKEY_get0_EC_KEY(pkey: [*c]const EVP_PKEY) ?*EC_KEY; -pub extern fn EVP_PKEY_get1_EC_KEY(pkey: [*c]const EVP_PKEY) ?*EC_KEY; -pub extern fn EVP_PKEY_assign(pkey: [*c]EVP_PKEY, @"type": c_int, key: ?*anyopaque) c_int; -pub extern fn EVP_PKEY_set_type(pkey: [*c]EVP_PKEY, @"type": c_int) c_int; -pub extern fn EVP_PKEY_cmp_parameters(a: [*c]const EVP_PKEY, b: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_parse_public_key(cbs: [*c]CBS) [*c]EVP_PKEY; -pub extern fn EVP_marshal_public_key(cbb: ?*CBB, key: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_parse_private_key(cbs: [*c]CBS) [*c]EVP_PKEY; -pub extern fn EVP_marshal_private_key(cbb: ?*CBB, key: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_new_raw_private_key(@"type": c_int, unused: ?*ENGINE, in: [*c]const u8, len: usize) [*c]EVP_PKEY; -pub extern fn EVP_PKEY_new_raw_public_key(@"type": c_int, unused: ?*ENGINE, in: [*c]const u8, len: usize) [*c]EVP_PKEY; -pub extern fn EVP_PKEY_get_raw_private_key(pkey: [*c]const EVP_PKEY, out: [*c]u8, out_len: [*c]usize) c_int; -pub extern fn EVP_PKEY_get_raw_public_key(pkey: [*c]const EVP_PKEY, out: [*c]u8, out_len: [*c]usize) c_int; -pub extern fn EVP_DigestSignInit(ctx: [*c]EVP_MD_CTX, pctx: [*c]?*EVP_PKEY_CTX, @"type": ?*const EVP_MD, e: ?*ENGINE, pkey: [*c]EVP_PKEY) c_int; -pub extern fn EVP_DigestSignUpdate(ctx: [*c]EVP_MD_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn EVP_DigestSignFinal(ctx: [*c]EVP_MD_CTX, out_sig: [*c]u8, out_sig_len: [*c]usize) c_int; -pub extern fn EVP_DigestSign(ctx: [*c]EVP_MD_CTX, out_sig: [*c]u8, out_sig_len: [*c]usize, data: [*c]const u8, data_len: usize) c_int; -pub extern fn EVP_DigestVerifyInit(ctx: [*c]EVP_MD_CTX, pctx: [*c]?*EVP_PKEY_CTX, @"type": ?*const EVP_MD, e: ?*ENGINE, pkey: [*c]EVP_PKEY) c_int; -pub extern fn EVP_DigestVerifyUpdate(ctx: [*c]EVP_MD_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn EVP_DigestVerifyFinal(ctx: [*c]EVP_MD_CTX, sig: [*c]const u8, sig_len: usize) c_int; -pub extern fn EVP_DigestVerify(ctx: [*c]EVP_MD_CTX, sig: [*c]const u8, sig_len: usize, data: [*c]const u8, len: usize) c_int; -pub extern fn EVP_SignInit_ex(ctx: [*c]EVP_MD_CTX, @"type": ?*const EVP_MD, impl: ?*ENGINE) c_int; -pub extern fn EVP_SignInit(ctx: [*c]EVP_MD_CTX, @"type": ?*const EVP_MD) c_int; -pub extern fn EVP_SignUpdate(ctx: [*c]EVP_MD_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn EVP_SignFinal(ctx: [*c]const EVP_MD_CTX, sig: [*c]u8, out_sig_len: [*c]c_uint, pkey: [*c]EVP_PKEY) c_int; -pub extern fn EVP_VerifyInit_ex(ctx: [*c]EVP_MD_CTX, @"type": ?*const EVP_MD, impl: ?*ENGINE) c_int; -pub extern fn EVP_VerifyInit(ctx: [*c]EVP_MD_CTX, @"type": ?*const EVP_MD) c_int; -pub extern fn EVP_VerifyUpdate(ctx: [*c]EVP_MD_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn EVP_VerifyFinal(ctx: [*c]EVP_MD_CTX, sig: [*c]const u8, sig_len: usize, pkey: [*c]EVP_PKEY) c_int; -pub extern fn EVP_PKEY_print_public(out: [*c]BIO, pkey: [*c]const EVP_PKEY, indent: c_int, pctx: ?*ASN1_PCTX) c_int; -pub extern fn EVP_PKEY_print_private(out: [*c]BIO, pkey: [*c]const EVP_PKEY, indent: c_int, pctx: ?*ASN1_PCTX) c_int; -pub extern fn EVP_PKEY_print_params(out: [*c]BIO, pkey: [*c]const EVP_PKEY, indent: c_int, pctx: ?*ASN1_PCTX) c_int; -pub extern fn PKCS5_PBKDF2_HMAC(password: ?[*]const u8, password_len: usize, salt: ?[*]const u8, salt_len: usize, iterations: c_uint, digest: ?*const EVP_MD, key_len: usize, out_key: ?[*]u8) c_int; -pub extern fn PKCS5_PBKDF2_HMAC_SHA1(password: [*c]const u8, password_len: usize, salt: [*c]const u8, salt_len: usize, iterations: c_uint, key_len: usize, out_key: [*c]u8) c_int; -pub extern fn EVP_PBE_validate_scrypt_params(password: [*c]const u8, password_len: usize, salt: [*c]const u8, salt_len: usize, N: u64, r: u64, p: u64, max_mem: usize, out_key: [*c]u8, key_len: usize) c_int; -pub extern fn EVP_PBE_scrypt(password: [*c]const u8, password_len: usize, salt: [*c]const u8, salt_len: usize, N: u64, r: u64, p: u64, max_mem: usize, out_key: [*c]u8, key_len: usize) c_int; -pub extern fn EVP_PKEY_CTX_new(pkey: [*c]EVP_PKEY, e: ?*ENGINE) ?*EVP_PKEY_CTX; -pub extern fn EVP_PKEY_CTX_new_id(id: c_int, e: ?*ENGINE) ?*EVP_PKEY_CTX; -pub extern fn EVP_PKEY_CTX_free(ctx: ?*EVP_PKEY_CTX) void; -pub extern fn EVP_PKEY_CTX_dup(ctx: ?*EVP_PKEY_CTX) ?*EVP_PKEY_CTX; -pub extern fn EVP_PKEY_CTX_get0_pkey(ctx: ?*EVP_PKEY_CTX) [*c]EVP_PKEY; -pub extern fn EVP_PKEY_sign_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_sign(ctx: ?*EVP_PKEY_CTX, sig: [*c]u8, sig_len: [*c]usize, digest: [*c]const u8, digest_len: usize) c_int; -pub extern fn EVP_PKEY_verify_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_verify(ctx: ?*EVP_PKEY_CTX, sig: [*c]const u8, sig_len: usize, digest: [*c]const u8, digest_len: usize) c_int; -pub extern fn EVP_PKEY_encrypt_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_encrypt(ctx: ?*EVP_PKEY_CTX, out: [*c]u8, out_len: [*c]usize, in: [*c]const u8, in_len: usize) c_int; -pub extern fn EVP_PKEY_decrypt_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_decrypt(ctx: ?*EVP_PKEY_CTX, out: [*c]u8, out_len: [*c]usize, in: [*c]const u8, in_len: usize) c_int; -pub extern fn EVP_PKEY_verify_recover_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_verify_recover(ctx: ?*EVP_PKEY_CTX, out: [*c]u8, out_len: [*c]usize, sig: [*c]const u8, siglen: usize) c_int; -pub extern fn EVP_PKEY_derive_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_derive_set_peer(ctx: ?*EVP_PKEY_CTX, peer: [*c]EVP_PKEY) c_int; -pub extern fn EVP_PKEY_derive(ctx: ?*EVP_PKEY_CTX, key: [*c]u8, out_key_len: [*c]usize) c_int; -pub extern fn EVP_PKEY_keygen_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_keygen(ctx: ?*EVP_PKEY_CTX, out_pkey: [*c][*c]EVP_PKEY) c_int; -pub extern fn EVP_PKEY_paramgen_init(ctx: ?*EVP_PKEY_CTX) c_int; -pub extern fn EVP_PKEY_paramgen(ctx: ?*EVP_PKEY_CTX, out_pkey: [*c][*c]EVP_PKEY) c_int; -pub extern fn EVP_PKEY_CTX_set_signature_md(ctx: ?*EVP_PKEY_CTX, md: ?*const EVP_MD) c_int; -pub extern fn EVP_PKEY_CTX_get_signature_md(ctx: ?*EVP_PKEY_CTX, out_md: [*c]?*const EVP_MD) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_padding(ctx: ?*EVP_PKEY_CTX, padding: c_int) c_int; -pub extern fn EVP_PKEY_CTX_get_rsa_padding(ctx: ?*EVP_PKEY_CTX, out_padding: [*c]c_int) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx: ?*EVP_PKEY_CTX, salt_len: c_int) c_int; -pub extern fn EVP_PKEY_CTX_get_rsa_pss_saltlen(ctx: ?*EVP_PKEY_CTX, out_salt_len: [*c]c_int) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_keygen_bits(ctx: ?*EVP_PKEY_CTX, bits: c_int) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_keygen_pubexp(ctx: ?*EVP_PKEY_CTX, e: [*c]BIGNUM) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_oaep_md(ctx: ?*EVP_PKEY_CTX, md: ?*const EVP_MD) c_int; -pub extern fn EVP_PKEY_CTX_get_rsa_oaep_md(ctx: ?*EVP_PKEY_CTX, out_md: [*c]?*const EVP_MD) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_mgf1_md(ctx: ?*EVP_PKEY_CTX, md: ?*const EVP_MD) c_int; -pub extern fn EVP_PKEY_CTX_get_rsa_mgf1_md(ctx: ?*EVP_PKEY_CTX, out_md: [*c]?*const EVP_MD) c_int; -pub extern fn EVP_PKEY_CTX_set0_rsa_oaep_label(ctx: ?*EVP_PKEY_CTX, label: [*c]u8, label_len: usize) c_int; -pub extern fn EVP_PKEY_CTX_get0_rsa_oaep_label(ctx: ?*EVP_PKEY_CTX, out_label: [*c][*c]const u8) c_int; -pub extern fn EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx: ?*EVP_PKEY_CTX, nid: c_int) c_int; -pub extern fn EVP_PKEY_get0(pkey: [*c]const EVP_PKEY) ?*anyopaque; -pub extern fn OpenSSL_add_all_algorithms() void; -pub extern fn OPENSSL_add_all_algorithms_conf() void; -pub extern fn OpenSSL_add_all_ciphers() void; -pub extern fn OpenSSL_add_all_digests() void; -pub extern fn EVP_cleanup() void; -pub extern fn EVP_CIPHER_do_all_sorted(callback: ?*const fn (?*const EVP_CIPHER, [*c]const u8, [*c]const u8, ?*anyopaque) callconv(.c) void, arg: ?*anyopaque) void; -pub extern fn EVP_MD_do_all_sorted(callback: *const fn (*const EVP_MD, ?[*:0]const u8, ?[*:0]const u8, *anyopaque) callconv(.c) void, arg: *anyopaque) void; -pub extern fn EVP_MD_do_all(callback: ?*const fn (?*const EVP_MD, [*c]const u8, [*c]const u8, ?*anyopaque) callconv(.c) void, arg: ?*anyopaque) void; -pub extern fn i2d_PrivateKey(key: [*c]const EVP_PKEY, outp: [*c][*c]u8) c_int; -pub extern fn i2d_PublicKey(key: [*c]const EVP_PKEY, outp: [*c][*c]u8) c_int; -pub extern fn d2i_PrivateKey(@"type": c_int, out: [*c][*c]EVP_PKEY, inp: [*c][*c]const u8, len: c_long) [*c]EVP_PKEY; -pub extern fn d2i_AutoPrivateKey(out: [*c][*c]EVP_PKEY, inp: [*c][*c]const u8, len: c_long) [*c]EVP_PKEY; -pub extern fn d2i_PublicKey(@"type": c_int, out: [*c][*c]EVP_PKEY, inp: [*c][*c]const u8, len: c_long) [*c]EVP_PKEY; -pub extern fn EVP_PKEY_get0_DH(pkey: [*c]const EVP_PKEY) ?*DH; -pub extern fn EVP_PKEY_get1_DH(pkey: [*c]const EVP_PKEY) ?*DH; -pub extern fn EVP_PKEY_CTX_set_ec_param_enc(ctx: ?*EVP_PKEY_CTX, encoding: c_int) c_int; -pub extern fn EVP_PKEY_set1_tls_encodedpoint(pkey: [*c]EVP_PKEY, in: [*c]const u8, len: usize) c_int; -pub extern fn EVP_PKEY_get1_tls_encodedpoint(pkey: [*c]const EVP_PKEY, out_ptr: [*c][*c]u8) usize; -pub extern fn EVP_PKEY_base_id(pkey: [*c]const EVP_PKEY) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_pss_keygen_md(ctx: ?*EVP_PKEY_CTX, md: ?*const EVP_MD) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_pss_keygen_saltlen(ctx: ?*EVP_PKEY_CTX, salt_len: c_int) c_int; -pub extern fn EVP_PKEY_CTX_set_rsa_pss_keygen_mgf1_md(ctx: ?*EVP_PKEY_CTX, md: ?*const EVP_MD) c_int; -pub extern fn i2d_PUBKEY(pkey: [*c]const EVP_PKEY, outp: [*c][*c]u8) c_int; -pub extern fn d2i_PUBKEY(out: [*c][*c]EVP_PKEY, inp: [*c][*c]const u8, len: c_long) [*c]EVP_PKEY; -pub extern fn i2d_RSA_PUBKEY(rsa: ?*const RSA, outp: [*c][*c]u8) c_int; -pub extern fn d2i_RSA_PUBKEY(out: [*c]?*RSA, inp: [*c][*c]const u8, len: c_long) ?*RSA; -pub extern fn i2d_DSA_PUBKEY(dsa: [*c]const DSA, outp: [*c][*c]u8) c_int; -pub extern fn d2i_DSA_PUBKEY(out: [*c][*c]DSA, inp: [*c][*c]const u8, len: c_long) [*c]DSA; -pub extern fn i2d_EC_PUBKEY(ec_key: ?*const EC_KEY, outp: [*c][*c]u8) c_int; -pub extern fn d2i_EC_PUBKEY(out: [*c]?*EC_KEY, inp: [*c][*c]const u8, len: c_long) ?*EC_KEY; -pub extern fn EVP_PKEY_CTX_set_dsa_paramgen_bits(ctx: ?*EVP_PKEY_CTX, nbits: c_int) c_int; -pub extern fn EVP_PKEY_CTX_set_dsa_paramgen_q_bits(ctx: ?*EVP_PKEY_CTX, qbits: c_int) c_int; -pub const struct_stack_st_CRYPTO_BUFFER = opaque {}; -pub const struct_stack_st_X509 = opaque {}; -pub const struct_stack_st_X509_CRL = opaque {}; -pub extern fn PKCS7_get_raw_certificates(out_certs: ?*struct_stack_st_CRYPTO_BUFFER, cbs: [*c]CBS, pool: ?*CRYPTO_BUFFER_POOL) c_int; -pub extern fn PKCS7_get_certificates(out_certs: ?*struct_stack_st_X509, cbs: [*c]CBS) c_int; -pub extern fn PKCS7_bundle_raw_certificates(out: ?*CBB, certs: ?*const struct_stack_st_CRYPTO_BUFFER) c_int; -pub extern fn PKCS7_bundle_certificates(out: ?*CBB, certs: ?*const struct_stack_st_X509) c_int; -pub extern fn PKCS7_get_CRLs(out_crls: ?*struct_stack_st_X509_CRL, cbs: [*c]CBS) c_int; -pub extern fn PKCS7_bundle_CRLs(out: ?*CBB, crls: ?*const struct_stack_st_X509_CRL) c_int; -pub extern fn PKCS7_get_PEM_certificates(out_certs: ?*struct_stack_st_X509, pem_bio: [*c]BIO) c_int; -pub extern fn PKCS7_get_PEM_CRLs(out_crls: ?*struct_stack_st_X509_CRL, pem_bio: [*c]BIO) c_int; -pub const PKCS7_SIGNED = extern struct { - cert: ?*struct_stack_st_X509, - crl: ?*struct_stack_st_X509_CRL, -}; -pub const PKCS7_SIGN_ENVELOPE = extern struct { - cert: ?*struct_stack_st_X509, - crl: ?*struct_stack_st_X509_CRL, -}; -pub const PKCS7_ENVELOPE = anyopaque; -pub const PKCS7_DIGEST = anyopaque; -pub const PKCS7_ENCRYPT = anyopaque; -pub const PKCS7_SIGNER_INFO = anyopaque; -const union_unnamed_7 = extern union { - ptr: [*c]u8, - data: [*c]ASN1_OCTET_STRING, - sign: [*c]PKCS7_SIGNED, - enveloped: ?*PKCS7_ENVELOPE, - signed_and_enveloped: [*c]PKCS7_SIGN_ENVELOPE, - digest: ?*PKCS7_DIGEST, - encrypted: ?*PKCS7_ENCRYPT, - other: [*c]ASN1_TYPE, -}; -pub const PKCS7 = extern struct { - ber_bytes: [*c]u8, - ber_len: usize, - type: ?*ASN1_OBJECT, - d: union_unnamed_7, -}; -pub extern fn d2i_PKCS7(out: [*c][*c]PKCS7, inp: [*c][*c]const u8, len: usize) [*c]PKCS7; -pub extern fn d2i_PKCS7_bio(bio: [*c]BIO, out: [*c][*c]PKCS7) [*c]PKCS7; -pub extern fn i2d_PKCS7(p7: [*c]const PKCS7, out: [*c][*c]u8) c_int; -pub extern fn i2d_PKCS7_bio(bio: [*c]BIO, p7: [*c]const PKCS7) c_int; -pub extern fn PKCS7_free(p7: [*c]PKCS7) void; -pub extern fn PKCS7_type_is_data(p7: [*c]const PKCS7) c_int; -pub extern fn PKCS7_type_is_digest(p7: [*c]const PKCS7) c_int; -pub extern fn PKCS7_type_is_encrypted(p7: [*c]const PKCS7) c_int; -pub extern fn PKCS7_type_is_enveloped(p7: [*c]const PKCS7) c_int; -pub extern fn PKCS7_type_is_signed(p7: [*c]const PKCS7) c_int; -pub extern fn PKCS7_type_is_signedAndEnveloped(p7: [*c]const PKCS7) c_int; -pub extern fn PKCS7_sign(sign_cert: ?*X509, pkey: [*c]EVP_PKEY, certs: ?*struct_stack_st_X509, data: [*c]BIO, flags: c_int) [*c]PKCS7; -pub extern fn BN_new() [*c]BIGNUM; -pub extern fn BN_init(bn: [*c]BIGNUM) void; -pub extern fn BN_free(bn: [*c]BIGNUM) void; -pub extern fn BN_clear_free(bn: [*c]BIGNUM) void; -pub extern fn BN_dup(src: [*c]const BIGNUM) [*c]BIGNUM; -pub extern fn BN_copy(dest: [*c]BIGNUM, src: [*c]const BIGNUM) [*c]BIGNUM; -pub extern fn BN_clear(bn: [*c]BIGNUM) void; -pub extern fn BN_value_one() [*c]const BIGNUM; -pub extern fn BN_num_bits(bn: [*c]const BIGNUM) c_uint; -pub extern fn BN_num_bytes(bn: [*c]const BIGNUM) c_uint; -pub extern fn BN_zero(bn: [*c]BIGNUM) void; -pub extern fn BN_one(bn: [*c]BIGNUM) c_int; -pub extern fn BN_set_word(bn: [*c]BIGNUM, value: BN_ULONG) c_int; -pub extern fn BN_set_u64(bn: [*c]BIGNUM, value: u64) c_int; -pub extern fn BN_set_negative(bn: [*c]BIGNUM, sign: c_int) void; -pub extern fn BN_is_negative(bn: [*c]const BIGNUM) c_int; -pub extern fn BN_bin2bn(in: [*c]const u8, len: usize, ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn BN_bn2bin(in: [*c]const BIGNUM, out: [*c]u8) usize; -pub extern fn BN_le2bn(in: [*c]const u8, len: usize, ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn BN_bn2le_padded(out: [*c]u8, len: usize, in: [*c]const BIGNUM) c_int; -pub extern fn BN_bn2bin_padded(out: [*c]u8, len: usize, in: [*c]const BIGNUM) c_int; -pub extern fn BN_bn2cbb_padded(out: ?*CBB, len: usize, in: [*c]const BIGNUM) c_int; -pub extern fn BN_bn2hex(bn: [*c]const BIGNUM) [*c]u8; -pub extern fn BN_hex2bn(outp: [*c][*c]BIGNUM, in: [*c]const u8) c_int; -pub extern fn BN_bn2dec(a: [*c]const BIGNUM) [*c]u8; -pub extern fn BN_dec2bn(outp: [*c][*c]BIGNUM, in: [*c]const u8) c_int; -pub extern fn BN_asc2bn(outp: [*c][*c]BIGNUM, in: [*c]const u8) c_int; -pub extern fn BN_print(bio: [*c]BIO, a: [*c]const BIGNUM) c_int; -pub extern fn BN_get_word(bn: [*c]const BIGNUM) BN_ULONG; -pub extern fn BN_get_u64(bn: [*c]const BIGNUM, out: [*c]u64) c_int; -pub extern fn BN_parse_asn1_unsigned(cbs: [*c]CBS, ret: [*c]BIGNUM) c_int; -pub extern fn BN_marshal_asn1(cbb: ?*CBB, bn: [*c]const BIGNUM) c_int; -pub extern fn BN_CTX_new() ?*BN_CTX; -pub extern fn BN_CTX_free(ctx: ?*BN_CTX) void; -pub extern fn BN_CTX_start(ctx: ?*BN_CTX) void; -pub extern fn BN_CTX_get(ctx: ?*BN_CTX) [*c]BIGNUM; -pub extern fn BN_CTX_end(ctx: ?*BN_CTX) void; -pub extern fn BN_add(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM) c_int; -pub extern fn BN_uadd(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM) c_int; -pub extern fn BN_add_word(a: [*c]BIGNUM, w: BN_ULONG) c_int; -pub extern fn BN_sub(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM) c_int; -pub extern fn BN_usub(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM) c_int; -pub extern fn BN_sub_word(a: [*c]BIGNUM, w: BN_ULONG) c_int; -pub extern fn BN_mul(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mul_word(bn: [*c]BIGNUM, w: BN_ULONG) c_int; -pub extern fn BN_sqr(r: [*c]BIGNUM, a: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_div(quotient: [*c]BIGNUM, rem: [*c]BIGNUM, numerator: [*c]const BIGNUM, divisor: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_div_word(numerator: [*c]BIGNUM, divisor: BN_ULONG) BN_ULONG; -pub extern fn BN_sqrt(out_sqrt: [*c]BIGNUM, in: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_cmp(a: [*c]const BIGNUM, b: [*c]const BIGNUM) c_int; -pub extern fn BN_cmp_word(a: [*c]const BIGNUM, b: BN_ULONG) c_int; -pub extern fn BN_ucmp(a: [*c]const BIGNUM, b: [*c]const BIGNUM) c_int; -pub extern fn BN_equal_consttime(a: [*c]const BIGNUM, b: [*c]const BIGNUM) c_int; -pub extern fn BN_abs_is_word(bn: [*c]const BIGNUM, w: BN_ULONG) c_int; -pub extern fn BN_is_zero(bn: [*c]const BIGNUM) c_int; -pub extern fn BN_is_one(bn: [*c]const BIGNUM) c_int; -pub extern fn BN_is_word(bn: [*c]const BIGNUM, w: BN_ULONG) c_int; -pub extern fn BN_is_odd(bn: [*c]const BIGNUM) c_int; -pub extern fn BN_is_pow2(a: [*c]const BIGNUM) c_int; -pub extern fn BN_lshift(r: [*c]BIGNUM, a: [*c]const BIGNUM, n: c_int) c_int; -pub extern fn BN_lshift1(r: [*c]BIGNUM, a: [*c]const BIGNUM) c_int; -pub extern fn BN_rshift(r: [*c]BIGNUM, a: [*c]const BIGNUM, n: c_int) c_int; -pub extern fn BN_rshift1(r: [*c]BIGNUM, a: [*c]const BIGNUM) c_int; -pub extern fn BN_set_bit(a: [*c]BIGNUM, n: c_int) c_int; -pub extern fn BN_clear_bit(a: [*c]BIGNUM, n: c_int) c_int; -pub extern fn BN_is_bit_set(a: [*c]const BIGNUM, n: c_int) c_int; -pub extern fn BN_mask_bits(a: [*c]BIGNUM, n: c_int) c_int; -pub extern fn BN_count_low_zero_bits(bn: [*c]const BIGNUM) c_int; -pub extern fn BN_mod_word(a: [*c]const BIGNUM, w: BN_ULONG) BN_ULONG; -pub extern fn BN_mod_pow2(r: [*c]BIGNUM, a: [*c]const BIGNUM, e: usize) c_int; -pub extern fn BN_nnmod_pow2(r: [*c]BIGNUM, a: [*c]const BIGNUM, e: usize) c_int; -pub extern fn BN_nnmod(rem: [*c]BIGNUM, numerator: [*c]const BIGNUM, divisor: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mod_add(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM, m: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mod_add_quick(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM, m: [*c]const BIGNUM) c_int; -pub extern fn BN_mod_sub(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM, m: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mod_sub_quick(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM, m: [*c]const BIGNUM) c_int; -pub extern fn BN_mod_mul(r: [*c]BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM, m: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mod_sqr(r: [*c]BIGNUM, a: [*c]const BIGNUM, m: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mod_lshift(r: [*c]BIGNUM, a: [*c]const BIGNUM, n: c_int, m: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mod_lshift_quick(r: [*c]BIGNUM, a: [*c]const BIGNUM, n: c_int, m: [*c]const BIGNUM) c_int; -pub extern fn BN_mod_lshift1(r: [*c]BIGNUM, a: [*c]const BIGNUM, m: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn BN_mod_lshift1_quick(r: [*c]BIGNUM, a: [*c]const BIGNUM, m: [*c]const BIGNUM) c_int; -pub extern fn BN_mod_sqrt(in: [*c]BIGNUM, a: [*c]const BIGNUM, p: [*c]const BIGNUM, ctx: ?*BN_CTX) [*c]BIGNUM; -pub extern fn BN_rand(rnd: [*c]BIGNUM, bits: c_int, top: c_int, bottom: c_int) c_int; -pub extern fn BN_pseudo_rand(rnd: [*c]BIGNUM, bits: c_int, top: c_int, bottom: c_int) c_int; -pub extern fn BN_rand_range(rnd: [*c]BIGNUM, range: [*c]const BIGNUM) c_int; -pub extern fn BN_rand_range_ex(r: [*c]BIGNUM, min_inclusive: BN_ULONG, max_exclusive: [*c]const BIGNUM) c_int; -pub extern fn BN_pseudo_rand_range(rnd: [*c]BIGNUM, range: [*c]const BIGNUM) c_int; -pub extern fn BN_GENCB_new() [*c]BN_GENCB; -pub extern fn BN_GENCB_free(callback: [*c]BN_GENCB) void; -pub extern fn BN_GENCB_set(callback: [*c]BN_GENCB, f: ?*const fn (c_int, c_int, [*c]BN_GENCB) callconv(.c) c_int, arg: ?*anyopaque) void; -pub extern fn BN_GENCB_call(callback: [*c]BN_GENCB, event: c_int, n: c_int) c_int; -pub extern fn BN_GENCB_get_arg(callback: [*c]const BN_GENCB) ?*anyopaque; -pub extern fn BN_generate_prime_ex(ret: [*c]BIGNUM, bits: c_int, safe: c_int, add: [*c]const BIGNUM, rem: [*c]const BIGNUM, cb: [*c]BN_GENCB) c_int; -pub const bn_probably_prime: c_int = 0; -pub const bn_composite: c_int = 1; -pub const bn_non_prime_power_composite: c_int = 2; -pub const enum_bn_primality_result_t = c_uint; -pub extern fn ASN1_tag2bit(tag: c_int) c_ulong; -pub extern fn ASN1_tag2str(tag: c_int) [*c]const u8; -pub const d2i_of_void = fn ([*c]?*anyopaque, [*c][*c]const u8, c_long) callconv(.c) ?*anyopaque; -pub const i2d_of_void = fn (?*const anyopaque, [*c][*c]u8) callconv(.c) c_int; -pub const ASN1_ITEM_EXP = ASN1_ITEM; -pub extern fn ASN1_item_new(it: ?*const ASN1_ITEM) ?*ASN1_VALUE; -pub extern fn ASN1_item_free(val: ?*ASN1_VALUE, it: ?*const ASN1_ITEM) void; -pub extern fn ASN1_item_d2i(out: [*c]?*ASN1_VALUE, inp: [*c][*c]const u8, len: c_long, it: ?*const ASN1_ITEM) ?*ASN1_VALUE; -pub extern fn ASN1_item_i2d(val: ?*ASN1_VALUE, outp: [*c][*c]u8, it: ?*const ASN1_ITEM) c_int; -pub extern fn ASN1_item_dup(it: ?*const ASN1_ITEM, x: ?*anyopaque) ?*anyopaque; -// pub extern fn ASN1_item_d2i_fp(it: ?*const ASN1_ITEM, in: [*c]FILE, out: ?*anyopaque) ?*anyopaque; -pub extern fn ASN1_item_d2i_bio(it: ?*const ASN1_ITEM, in: [*c]BIO, out: ?*anyopaque) ?*anyopaque; -// pub extern fn ASN1_item_i2d_fp(it: ?*const ASN1_ITEM, out: [*c]FILE, in: ?*anyopaque) c_int; -pub extern fn ASN1_item_i2d_bio(it: ?*const ASN1_ITEM, out: [*c]BIO, in: ?*anyopaque) c_int; -pub extern fn ASN1_item_unpack(oct: [*c]const ASN1_STRING, it: ?*const ASN1_ITEM) ?*anyopaque; -pub extern fn ASN1_item_pack(obj: ?*anyopaque, it: ?*const ASN1_ITEM, out: [*c][*c]ASN1_STRING) [*c]ASN1_STRING; -pub extern fn d2i_ASN1_BOOLEAN(out: [*c]ASN1_BOOLEAN, inp: [*c][*c]const u8, len: c_long) ASN1_BOOLEAN; -pub extern fn i2d_ASN1_BOOLEAN(a: ASN1_BOOLEAN, outp: [*c][*c]u8) c_int; -pub extern const ASN1_BOOLEAN_it: ASN1_ITEM; -pub extern const ASN1_TBOOLEAN_it: ASN1_ITEM; -pub extern const ASN1_FBOOLEAN_it: ASN1_ITEM; -pub extern fn ASN1_STRING_type_new(@"type": c_int) [*c]ASN1_STRING; -pub extern fn ASN1_STRING_new() [*c]ASN1_STRING; -pub extern fn ASN1_STRING_free(str: [*c]ASN1_STRING) void; -pub extern fn ASN1_STRING_copy(dst: [*c]ASN1_STRING, str: [*c]const ASN1_STRING) c_int; -pub extern fn ASN1_STRING_dup(str: [*c]const ASN1_STRING) [*c]ASN1_STRING; -pub extern fn ASN1_STRING_type(str: [*c]const ASN1_STRING) c_int; -pub extern fn ASN1_STRING_get0_data(str: [*c]const ASN1_STRING) [*c]const u8; -pub extern fn ASN1_STRING_data(str: [*c]ASN1_STRING) [*c]u8; -pub extern fn ASN1_STRING_length(str: [*c]const ASN1_STRING) c_int; -pub extern fn ASN1_STRING_cmp(a: [*c]const ASN1_STRING, b: [*c]const ASN1_STRING) c_int; -// pub extern fn ASN1_STRING_set(str: [*c]ASN1_STRING, data: ?*const anyopaque, len: ossl_ssize_t) c_int; -// pub extern fn ASN1_STRING_set0(str: [*c]ASN1_STRING, data: ?*anyopaque, len: c_int) void; -pub extern fn ASN1_BMPSTRING_new() [*c]ASN1_BMPSTRING; -pub extern fn ASN1_GENERALSTRING_new() [*c]ASN1_GENERALSTRING; -pub extern fn ASN1_IA5STRING_new() [*c]ASN1_IA5STRING; -pub extern fn ASN1_OCTET_STRING_new() [*c]ASN1_OCTET_STRING; -pub extern fn ASN1_PRINTABLESTRING_new() [*c]ASN1_PRINTABLESTRING; -pub extern fn ASN1_T61STRING_new() [*c]ASN1_T61STRING; -pub extern fn ASN1_UNIVERSALSTRING_new() [*c]ASN1_UNIVERSALSTRING; -pub extern fn ASN1_UTF8STRING_new() [*c]ASN1_UTF8STRING; -pub extern fn ASN1_VISIBLESTRING_new() [*c]ASN1_VISIBLESTRING; -pub extern fn ASN1_BMPSTRING_free(str: [*c]ASN1_BMPSTRING) void; -pub extern fn ASN1_GENERALSTRING_free(str: [*c]ASN1_GENERALSTRING) void; -pub extern fn ASN1_IA5STRING_free(str: [*c]ASN1_IA5STRING) void; -pub extern fn ASN1_OCTET_STRING_free(str: [*c]ASN1_OCTET_STRING) void; -pub extern fn ASN1_PRINTABLESTRING_free(str: [*c]ASN1_PRINTABLESTRING) void; -pub extern fn ASN1_T61STRING_free(str: [*c]ASN1_T61STRING) void; -pub extern fn ASN1_UNIVERSALSTRING_free(str: [*c]ASN1_UNIVERSALSTRING) void; -pub extern fn ASN1_UTF8STRING_free(str: [*c]ASN1_UTF8STRING) void; -pub extern fn ASN1_VISIBLESTRING_free(str: [*c]ASN1_VISIBLESTRING) void; -pub extern fn d2i_ASN1_BMPSTRING(out: [*c][*c]ASN1_BMPSTRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_BMPSTRING; -pub extern fn d2i_ASN1_GENERALSTRING(out: [*c][*c]ASN1_GENERALSTRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_GENERALSTRING; -pub extern fn d2i_ASN1_IA5STRING(out: [*c][*c]ASN1_IA5STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_IA5STRING; -pub extern fn d2i_ASN1_OCTET_STRING(out: [*c][*c]ASN1_OCTET_STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_OCTET_STRING; -pub extern fn d2i_ASN1_PRINTABLESTRING(out: [*c][*c]ASN1_PRINTABLESTRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_PRINTABLESTRING; -pub extern fn d2i_ASN1_T61STRING(out: [*c][*c]ASN1_T61STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_T61STRING; -pub extern fn d2i_ASN1_UNIVERSALSTRING(out: [*c][*c]ASN1_UNIVERSALSTRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_UNIVERSALSTRING; -pub extern fn d2i_ASN1_UTF8STRING(out: [*c][*c]ASN1_UTF8STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_UTF8STRING; -pub extern fn d2i_ASN1_VISIBLESTRING(out: [*c][*c]ASN1_VISIBLESTRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_VISIBLESTRING; -pub extern fn i2d_ASN1_BMPSTRING(in: [*c]const ASN1_BMPSTRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_GENERALSTRING(in: [*c]const ASN1_GENERALSTRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_IA5STRING(in: [*c]const ASN1_IA5STRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_OCTET_STRING(in: [*c]const ASN1_OCTET_STRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_PRINTABLESTRING(in: [*c]const ASN1_PRINTABLESTRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_T61STRING(in: [*c]const ASN1_T61STRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_UNIVERSALSTRING(in: [*c]const ASN1_UNIVERSALSTRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_UTF8STRING(in: [*c]const ASN1_UTF8STRING, outp: [*c][*c]u8) c_int; -pub extern fn i2d_ASN1_VISIBLESTRING(in: [*c]const ASN1_VISIBLESTRING, outp: [*c][*c]u8) c_int; -pub extern const ASN1_BMPSTRING_it: ASN1_ITEM; -pub extern const ASN1_GENERALSTRING_it: ASN1_ITEM; -pub extern const ASN1_IA5STRING_it: ASN1_ITEM; -pub extern const ASN1_OCTET_STRING_it: ASN1_ITEM; -pub extern const ASN1_PRINTABLESTRING_it: ASN1_ITEM; -pub extern const ASN1_T61STRING_it: ASN1_ITEM; -pub extern const ASN1_UNIVERSALSTRING_it: ASN1_ITEM; -pub extern const ASN1_UTF8STRING_it: ASN1_ITEM; -pub extern const ASN1_VISIBLESTRING_it: ASN1_ITEM; -pub extern fn ASN1_OCTET_STRING_dup(a: [*c]const ASN1_OCTET_STRING) [*c]ASN1_OCTET_STRING; -pub extern fn ASN1_OCTET_STRING_cmp(a: [*c]const ASN1_OCTET_STRING, b: [*c]const ASN1_OCTET_STRING) c_int; -pub extern fn ASN1_OCTET_STRING_set(str: [*c]ASN1_OCTET_STRING, data: [*c]const u8, len: c_int) c_int; -pub extern fn ASN1_STRING_to_UTF8(out: [*c][*c]u8, in: [*c]const ASN1_STRING) c_int; -pub extern fn ASN1_mbstring_copy(out: [*c][*c]ASN1_STRING, in: [*c]const u8, len: c_int, inform: c_int, mask: c_ulong) c_int; -pub extern fn ASN1_mbstring_ncopy(out: [*c][*c]ASN1_STRING, in: [*c]const u8, len: c_int, inform: c_int, mask: c_ulong, minsize: c_long, maxsize: c_long) c_int; -pub extern fn ASN1_STRING_set_by_NID(out: [*c][*c]ASN1_STRING, in: [*c]const u8, len: c_int, inform: c_int, nid: c_int) [*c]ASN1_STRING; -pub extern fn ASN1_STRING_TABLE_add(nid: c_int, minsize: c_long, maxsize: c_long, mask: c_ulong, flags: c_ulong) c_int; -pub extern fn DIRECTORYSTRING_new() [*c]ASN1_STRING; -pub extern fn DIRECTORYSTRING_free(str: [*c]ASN1_STRING) void; -pub extern fn d2i_DIRECTORYSTRING(out: [*c][*c]ASN1_STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_STRING; -pub extern fn i2d_DIRECTORYSTRING(in: [*c]const ASN1_STRING, outp: [*c][*c]u8) c_int; -pub extern const DIRECTORYSTRING_it: ASN1_ITEM; -pub extern fn DISPLAYTEXT_new() [*c]ASN1_STRING; -pub extern fn DISPLAYTEXT_free(str: [*c]ASN1_STRING) void; -pub extern fn d2i_DISPLAYTEXT(out: [*c][*c]ASN1_STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_STRING; -pub extern fn i2d_DISPLAYTEXT(in: [*c]const ASN1_STRING, outp: [*c][*c]u8) c_int; -pub extern const DISPLAYTEXT_it: ASN1_ITEM; -pub extern fn ASN1_BIT_STRING_new() [*c]ASN1_BIT_STRING; -pub extern fn ASN1_BIT_STRING_free(str: [*c]ASN1_BIT_STRING) void; -pub extern fn d2i_ASN1_BIT_STRING(out: [*c][*c]ASN1_BIT_STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_BIT_STRING; -pub extern fn i2d_ASN1_BIT_STRING(in: [*c]const ASN1_BIT_STRING, outp: [*c][*c]u8) c_int; -pub extern fn c2i_ASN1_BIT_STRING(out: [*c][*c]ASN1_BIT_STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_BIT_STRING; -pub extern fn i2c_ASN1_BIT_STRING(in: [*c]const ASN1_BIT_STRING, outp: [*c][*c]u8) c_int; -pub extern const ASN1_BIT_STRING_it: ASN1_ITEM; -pub extern fn ASN1_BIT_STRING_num_bytes(str: [*c]const ASN1_BIT_STRING, out: [*c]usize) c_int; -// pub extern fn ASN1_BIT_STRING_set(str: [*c]ASN1_BIT_STRING, d: [*c]const u8, length: ossl_ssize_t) c_int; -pub extern fn ASN1_BIT_STRING_set_bit(str: [*c]ASN1_BIT_STRING, n: c_int, value: c_int) c_int; -pub extern fn ASN1_BIT_STRING_get_bit(str: [*c]const ASN1_BIT_STRING, n: c_int) c_int; -pub extern fn ASN1_BIT_STRING_check(str: [*c]const ASN1_BIT_STRING, flags: [*c]const u8, flags_len: c_int) c_int; -pub const struct_stack_st_ASN1_INTEGER = opaque {}; -pub const sk_ASN1_INTEGER_free_func = ?*const fn ([*c]ASN1_INTEGER) callconv(.c) void; -pub const sk_ASN1_INTEGER_copy_func = ?*const fn ([*c]ASN1_INTEGER) callconv(.c) [*c]ASN1_INTEGER; -pub const sk_ASN1_INTEGER_cmp_func = ?*const fn ([*c][*c]const ASN1_INTEGER, [*c][*c]const ASN1_INTEGER) callconv(.c) c_int; -pub fn sk_ASN1_INTEGER_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_ASN1_INTEGER_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]ASN1_INTEGER, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_ASN1_INTEGER_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_ASN1_INTEGER_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]ASN1_INTEGER, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_ASN1_INTEGER_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const ASN1_INTEGER = @as([*c]const ASN1_INTEGER, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const ASN1_INTEGER = @as([*c]const ASN1_INTEGER, @ptrCast(@alignCast(b.*))); - return @as(sk_ASN1_INTEGER_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_ASN1_INTEGER_new(arg_comp: sk_ASN1_INTEGER_cmp_func) callconv(.c) ?*struct_stack_st_ASN1_INTEGER { - const comp = arg_comp; - return @as(?*struct_stack_st_ASN1_INTEGER, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_ASN1_INTEGER_new_null() callconv(.c) ?*struct_stack_st_ASN1_INTEGER { - return @as(?*struct_stack_st_ASN1_INTEGER, @ptrCast(sk_new_null())); -} -pub fn sk_ASN1_INTEGER_num(arg_sk: ?*const struct_stack_st_ASN1_INTEGER) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_INTEGER_zero(arg_sk: ?*struct_stack_st_ASN1_INTEGER) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_INTEGER_value(arg_sk: ?*const struct_stack_st_ASN1_INTEGER, arg_i: usize) callconv(.c) [*c]ASN1_INTEGER { - const sk = arg_sk; - const i = arg_i; - return @as([*c]ASN1_INTEGER, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_ASN1_INTEGER_set(arg_sk: ?*struct_stack_st_ASN1_INTEGER, arg_i: usize, arg_p: [*c]ASN1_INTEGER) callconv(.c) [*c]ASN1_INTEGER { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]ASN1_INTEGER, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_ASN1_INTEGER_free(arg_sk: ?*struct_stack_st_ASN1_INTEGER) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_INTEGER_pop_free(arg_sk: ?*struct_stack_st_ASN1_INTEGER, arg_free_func: sk_ASN1_INTEGER_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_INTEGER_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_ASN1_INTEGER_insert(arg_sk: ?*struct_stack_st_ASN1_INTEGER, arg_p: [*c]ASN1_INTEGER, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_ASN1_INTEGER_delete(arg_sk: ?*struct_stack_st_ASN1_INTEGER, arg_where: usize) callconv(.c) [*c]ASN1_INTEGER { - const sk = arg_sk; - const where = arg_where; - return @as([*c]ASN1_INTEGER, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_ASN1_INTEGER_delete_ptr(arg_sk: ?*struct_stack_st_ASN1_INTEGER, arg_p: [*c]const ASN1_INTEGER) callconv(.c) [*c]ASN1_INTEGER { - const sk = arg_sk; - const p = arg_p; - return @as([*c]ASN1_INTEGER, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_ASN1_INTEGER_find(arg_sk: ?*const struct_stack_st_ASN1_INTEGER, arg_out_index: [*c]usize, arg_p: [*c]const ASN1_INTEGER) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_ASN1_INTEGER_call_cmp_func); -} -pub fn sk_ASN1_INTEGER_shift(arg_sk: ?*struct_stack_st_ASN1_INTEGER) callconv(.c) [*c]ASN1_INTEGER { - const sk = arg_sk; - return @as([*c]ASN1_INTEGER, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_ASN1_INTEGER_push(arg_sk: ?*struct_stack_st_ASN1_INTEGER, arg_p: [*c]ASN1_INTEGER) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_ASN1_INTEGER_pop(arg_sk: ?*struct_stack_st_ASN1_INTEGER) callconv(.c) [*c]ASN1_INTEGER { - const sk = arg_sk; - return @as([*c]ASN1_INTEGER, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_ASN1_INTEGER_dup(arg_sk: ?*const struct_stack_st_ASN1_INTEGER) callconv(.c) ?*struct_stack_st_ASN1_INTEGER { - const sk = arg_sk; - return @as(?*struct_stack_st_ASN1_INTEGER, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_ASN1_INTEGER_sort(arg_sk: ?*struct_stack_st_ASN1_INTEGER) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_INTEGER_call_cmp_func); -} -pub fn sk_ASN1_INTEGER_is_sorted(arg_sk: ?*const struct_stack_st_ASN1_INTEGER) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_INTEGER_set_cmp_func(arg_sk: ?*struct_stack_st_ASN1_INTEGER, arg_comp: sk_ASN1_INTEGER_cmp_func) callconv(.c) sk_ASN1_INTEGER_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_ASN1_INTEGER_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_ASN1_INTEGER_deep_copy(arg_sk: ?*const struct_stack_st_ASN1_INTEGER, arg_copy_func: sk_ASN1_INTEGER_copy_func, arg_free_func: sk_ASN1_INTEGER_free_func) callconv(.c) ?*struct_stack_st_ASN1_INTEGER { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_ASN1_INTEGER, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_INTEGER_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_ASN1_INTEGER_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn ASN1_INTEGER_new() [*c]ASN1_INTEGER; -pub extern fn ASN1_INTEGER_free(str: [*c]ASN1_INTEGER) void; -pub extern fn ASN1_INTEGER_dup(x: [*c]const ASN1_INTEGER) [*c]ASN1_INTEGER; -pub extern fn d2i_ASN1_INTEGER(out: [*c][*c]ASN1_INTEGER, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_INTEGER; -pub extern fn i2d_ASN1_INTEGER(in: [*c]const ASN1_INTEGER, outp: [*c][*c]u8) c_int; -pub extern fn c2i_ASN1_INTEGER(in: [*c][*c]ASN1_INTEGER, outp: [*c][*c]const u8, len: c_long) [*c]ASN1_INTEGER; -pub extern fn i2c_ASN1_INTEGER(in: [*c]const ASN1_INTEGER, outp: [*c][*c]u8) c_int; -pub extern const ASN1_INTEGER_it: ASN1_ITEM; -pub extern fn ASN1_INTEGER_set_uint64(out: [*c]ASN1_INTEGER, v: u64) c_int; -pub extern fn ASN1_INTEGER_set_int64(out: [*c]ASN1_INTEGER, v: i64) c_int; -pub extern fn ASN1_INTEGER_get_uint64(out: [*c]u64, a: [*c]const ASN1_INTEGER) c_int; -pub extern fn ASN1_INTEGER_get_int64(out: [*c]i64, a: [*c]const ASN1_INTEGER) c_int; -pub extern fn BN_to_ASN1_INTEGER(bn: [*c]const BIGNUM, ai: [*c]ASN1_INTEGER) [*c]ASN1_INTEGER; -pub extern fn ASN1_INTEGER_to_BN(ai: [*c]const ASN1_INTEGER, bn: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn ASN1_INTEGER_cmp(x: [*c]const ASN1_INTEGER, y: [*c]const ASN1_INTEGER) c_int; -pub extern fn ASN1_ENUMERATED_new() [*c]ASN1_ENUMERATED; -pub extern fn ASN1_ENUMERATED_free(str: [*c]ASN1_ENUMERATED) void; -pub extern fn d2i_ASN1_ENUMERATED(out: [*c][*c]ASN1_ENUMERATED, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_ENUMERATED; -pub extern fn i2d_ASN1_ENUMERATED(in: [*c]const ASN1_ENUMERATED, outp: [*c][*c]u8) c_int; -pub extern const ASN1_ENUMERATED_it: ASN1_ITEM; -pub extern fn ASN1_ENUMERATED_set_uint64(out: [*c]ASN1_ENUMERATED, v: u64) c_int; -pub extern fn ASN1_ENUMERATED_set_int64(out: [*c]ASN1_ENUMERATED, v: i64) c_int; -pub extern fn ASN1_ENUMERATED_get_uint64(out: [*c]u64, a: [*c]const ASN1_ENUMERATED) c_int; -pub extern fn ASN1_ENUMERATED_get_int64(out: [*c]i64, a: [*c]const ASN1_ENUMERATED) c_int; -pub extern fn BN_to_ASN1_ENUMERATED(bn: [*c]const BIGNUM, ai: [*c]ASN1_ENUMERATED) [*c]ASN1_ENUMERATED; -pub extern fn ASN1_ENUMERATED_to_BN(ai: [*c]const ASN1_ENUMERATED, bn: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn ASN1_UTCTIME_new() [*c]ASN1_UTCTIME; -pub extern fn ASN1_UTCTIME_free(str: [*c]ASN1_UTCTIME) void; -pub extern fn d2i_ASN1_UTCTIME(out: [*c][*c]ASN1_UTCTIME, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_UTCTIME; -pub extern fn i2d_ASN1_UTCTIME(in: [*c]const ASN1_UTCTIME, outp: [*c][*c]u8) c_int; -pub extern const ASN1_UTCTIME_it: ASN1_ITEM; -pub extern fn ASN1_UTCTIME_check(a: [*c]const ASN1_UTCTIME) c_int; -pub extern fn ASN1_UTCTIME_set(s: [*c]ASN1_UTCTIME, t: time_t) [*c]ASN1_UTCTIME; -pub extern fn ASN1_UTCTIME_adj(s: [*c]ASN1_UTCTIME, t: time_t, offset_day: c_int, offset_sec: c_long) [*c]ASN1_UTCTIME; -pub extern fn ASN1_UTCTIME_set_string(s: [*c]ASN1_UTCTIME, str: [*c]const u8) c_int; -pub extern fn ASN1_UTCTIME_cmp_time_t(s: [*c]const ASN1_UTCTIME, t: time_t) c_int; -pub extern fn ASN1_GENERALIZEDTIME_new() [*c]ASN1_GENERALIZEDTIME; -pub extern fn ASN1_GENERALIZEDTIME_free(str: [*c]ASN1_GENERALIZEDTIME) void; -pub extern fn d2i_ASN1_GENERALIZEDTIME(out: [*c][*c]ASN1_GENERALIZEDTIME, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_GENERALIZEDTIME; -pub extern fn i2d_ASN1_GENERALIZEDTIME(in: [*c]const ASN1_GENERALIZEDTIME, outp: [*c][*c]u8) c_int; -pub extern const ASN1_GENERALIZEDTIME_it: ASN1_ITEM; -pub extern fn ASN1_GENERALIZEDTIME_check(a: [*c]const ASN1_GENERALIZEDTIME) c_int; -pub extern fn ASN1_GENERALIZEDTIME_set(s: [*c]ASN1_GENERALIZEDTIME, t: time_t) [*c]ASN1_GENERALIZEDTIME; -pub extern fn ASN1_GENERALIZEDTIME_adj(s: [*c]ASN1_GENERALIZEDTIME, t: time_t, offset_day: c_int, offset_sec: c_long) [*c]ASN1_GENERALIZEDTIME; -pub extern fn ASN1_GENERALIZEDTIME_set_string(s: [*c]ASN1_GENERALIZEDTIME, str: [*c]const u8) c_int; -pub extern fn ASN1_TIME_new() [*c]ASN1_TIME; -pub extern fn ASN1_TIME_free(str: [*c]ASN1_TIME) void; -pub extern fn d2i_ASN1_TIME(out: [*c][*c]ASN1_TIME, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_TIME; -pub extern fn i2d_ASN1_TIME(in: [*c]const ASN1_TIME, outp: [*c][*c]u8) c_int; -pub extern const ASN1_TIME_it: ASN1_ITEM; -pub extern fn ASN1_TIME_diff(out_days: [*c]c_int, out_seconds: [*c]c_int, from: [*c]const ASN1_TIME, to: [*c]const ASN1_TIME) c_int; -pub extern fn ASN1_TIME_set(s: [*c]ASN1_TIME, t: time_t) [*c]ASN1_TIME; -pub extern fn ASN1_TIME_adj(s: [*c]ASN1_TIME, t: time_t, offset_day: c_int, offset_sec: c_long) [*c]ASN1_TIME; -pub extern fn ASN1_TIME_check(t: [*c]const ASN1_TIME) c_int; -pub extern fn ASN1_TIME_to_generalizedtime(t: [*c]const ASN1_TIME, out: [*c][*c]ASN1_GENERALIZEDTIME) [*c]ASN1_GENERALIZEDTIME; -pub extern fn ASN1_TIME_set_string(s: [*c]ASN1_TIME, str: [*c]const u8) c_int; -pub extern fn ASN1_TIME_to_time_t(t: [*c]const ASN1_TIME, out: [*c]time_t) c_int; -pub extern fn ASN1_TIME_to_posix(t: [*c]const ASN1_TIME, out: [*c]i64) c_int; -pub extern fn ASN1_NULL_new() ?*ASN1_NULL; -pub extern fn ASN1_NULL_free(@"null": ?*ASN1_NULL) void; -pub extern fn d2i_ASN1_NULL(out: [*c]?*ASN1_NULL, inp: [*c][*c]const u8, len: c_long) ?*ASN1_NULL; -pub extern fn i2d_ASN1_NULL(in: ?*const ASN1_NULL, outp: [*c][*c]u8) c_int; -pub extern const ASN1_NULL_it: ASN1_ITEM; -pub const struct_stack_st_ASN1_OBJECT = opaque {}; -pub const sk_ASN1_OBJECT_free_func = ?*const fn (?*ASN1_OBJECT) callconv(.c) void; -pub const sk_ASN1_OBJECT_copy_func = ?*const fn (?*ASN1_OBJECT) callconv(.c) ?*ASN1_OBJECT; -pub const sk_ASN1_OBJECT_cmp_func = ?*const fn ([*c]?*const ASN1_OBJECT, [*c]?*const ASN1_OBJECT) callconv(.c) c_int; -pub fn sk_ASN1_OBJECT_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_ASN1_OBJECT_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*ASN1_OBJECT, @ptrCast(ptr))); -} -pub fn sk_ASN1_OBJECT_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_ASN1_OBJECT_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*ASN1_OBJECT, @ptrCast(ptr))))); -} -pub fn sk_ASN1_OBJECT_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const ASN1_OBJECT = @as(?*const ASN1_OBJECT, @ptrCast(a.*)); - var b_ptr: ?*const ASN1_OBJECT = @as(?*const ASN1_OBJECT, @ptrCast(b.*)); - return @as(sk_ASN1_OBJECT_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_ASN1_OBJECT_new(arg_comp: sk_ASN1_OBJECT_cmp_func) callconv(.c) ?*struct_stack_st_ASN1_OBJECT { - const comp = arg_comp; - return @as(?*struct_stack_st_ASN1_OBJECT, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_ASN1_OBJECT_new_null() callconv(.c) ?*struct_stack_st_ASN1_OBJECT { - return @as(?*struct_stack_st_ASN1_OBJECT, @ptrCast(sk_new_null())); -} -pub fn sk_ASN1_OBJECT_num(arg_sk: ?*const struct_stack_st_ASN1_OBJECT) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_OBJECT_zero(arg_sk: ?*struct_stack_st_ASN1_OBJECT) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_OBJECT_value(arg_sk: ?*const struct_stack_st_ASN1_OBJECT, arg_i: usize) callconv(.c) ?*ASN1_OBJECT { - const sk = arg_sk; - const i = arg_i; - return @as(?*ASN1_OBJECT, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_ASN1_OBJECT_set(arg_sk: ?*struct_stack_st_ASN1_OBJECT, arg_i: usize, arg_p: ?*ASN1_OBJECT) callconv(.c) ?*ASN1_OBJECT { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*ASN1_OBJECT, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_ASN1_OBJECT_free(arg_sk: ?*struct_stack_st_ASN1_OBJECT) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_OBJECT_pop_free(arg_sk: ?*struct_stack_st_ASN1_OBJECT, arg_free_func: sk_ASN1_OBJECT_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_OBJECT_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_ASN1_OBJECT_insert(arg_sk: ?*struct_stack_st_ASN1_OBJECT, arg_p: ?*ASN1_OBJECT, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_ASN1_OBJECT_delete(arg_sk: ?*struct_stack_st_ASN1_OBJECT, arg_where: usize) callconv(.c) ?*ASN1_OBJECT { - const sk = arg_sk; - const where = arg_where; - return @as(?*ASN1_OBJECT, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_ASN1_OBJECT_delete_ptr(arg_sk: ?*struct_stack_st_ASN1_OBJECT, arg_p: ?*const ASN1_OBJECT) callconv(.c) ?*ASN1_OBJECT { - const sk = arg_sk; - const p = arg_p; - return @as(?*ASN1_OBJECT, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_ASN1_OBJECT_find(arg_sk: ?*const struct_stack_st_ASN1_OBJECT, arg_out_index: [*c]usize, arg_p: ?*const ASN1_OBJECT) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_ASN1_OBJECT_call_cmp_func); -} -pub fn sk_ASN1_OBJECT_shift(arg_sk: ?*struct_stack_st_ASN1_OBJECT) callconv(.c) ?*ASN1_OBJECT { - const sk = arg_sk; - return @as(?*ASN1_OBJECT, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_ASN1_OBJECT_push(arg_sk: ?*struct_stack_st_ASN1_OBJECT, arg_p: ?*ASN1_OBJECT) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_ASN1_OBJECT_pop(arg_sk: ?*struct_stack_st_ASN1_OBJECT) callconv(.c) ?*ASN1_OBJECT { - const sk = arg_sk; - return @as(?*ASN1_OBJECT, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_ASN1_OBJECT_dup(arg_sk: ?*const struct_stack_st_ASN1_OBJECT) callconv(.c) ?*struct_stack_st_ASN1_OBJECT { - const sk = arg_sk; - return @as(?*struct_stack_st_ASN1_OBJECT, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_ASN1_OBJECT_sort(arg_sk: ?*struct_stack_st_ASN1_OBJECT) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_OBJECT_call_cmp_func); -} -pub fn sk_ASN1_OBJECT_is_sorted(arg_sk: ?*const struct_stack_st_ASN1_OBJECT) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_OBJECT_set_cmp_func(arg_sk: ?*struct_stack_st_ASN1_OBJECT, arg_comp: sk_ASN1_OBJECT_cmp_func) callconv(.c) sk_ASN1_OBJECT_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_ASN1_OBJECT_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_ASN1_OBJECT_deep_copy(arg_sk: ?*const struct_stack_st_ASN1_OBJECT, arg_copy_func: sk_ASN1_OBJECT_copy_func, arg_free_func: sk_ASN1_OBJECT_free_func) callconv(.c) ?*struct_stack_st_ASN1_OBJECT { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_ASN1_OBJECT, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_OBJECT_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_ASN1_OBJECT_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn ASN1_OBJECT_create(nid: c_int, data: [*c]const u8, len: c_int, sn: [*c]const u8, ln: [*c]const u8) ?*ASN1_OBJECT; -pub extern fn ASN1_OBJECT_free(a: ?*ASN1_OBJECT) void; -pub extern fn d2i_ASN1_OBJECT(out: [*c]?*ASN1_OBJECT, inp: [*c][*c]const u8, len: c_long) ?*ASN1_OBJECT; -pub extern fn i2d_ASN1_OBJECT(a: ?*const ASN1_OBJECT, outp: [*c][*c]u8) c_int; -pub extern fn c2i_ASN1_OBJECT(out: [*c]?*ASN1_OBJECT, inp: [*c][*c]const u8, len: c_long) ?*ASN1_OBJECT; -pub extern const ASN1_OBJECT_it: ASN1_ITEM; -pub const struct_stack_st_ASN1_TYPE = opaque {}; -pub const sk_ASN1_TYPE_free_func = ?*const fn ([*c]ASN1_TYPE) callconv(.c) void; -pub const sk_ASN1_TYPE_copy_func = ?*const fn ([*c]ASN1_TYPE) callconv(.c) [*c]ASN1_TYPE; -pub const sk_ASN1_TYPE_cmp_func = ?*const fn ([*c][*c]const ASN1_TYPE, [*c][*c]const ASN1_TYPE) callconv(.c) c_int; -pub fn sk_ASN1_TYPE_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_ASN1_TYPE_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]ASN1_TYPE, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_ASN1_TYPE_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_ASN1_TYPE_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]ASN1_TYPE, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_ASN1_TYPE_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const ASN1_TYPE = @as([*c]const ASN1_TYPE, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const ASN1_TYPE = @as([*c]const ASN1_TYPE, @ptrCast(@alignCast(b.*))); - return @as(sk_ASN1_TYPE_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_ASN1_TYPE_new(arg_comp: sk_ASN1_TYPE_cmp_func) callconv(.c) ?*struct_stack_st_ASN1_TYPE { - const comp = arg_comp; - return @as(?*struct_stack_st_ASN1_TYPE, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_ASN1_TYPE_new_null() callconv(.c) ?*struct_stack_st_ASN1_TYPE { - return @as(?*struct_stack_st_ASN1_TYPE, @ptrCast(sk_new_null())); -} -pub fn sk_ASN1_TYPE_num(arg_sk: ?*const struct_stack_st_ASN1_TYPE) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_TYPE_zero(arg_sk: ?*struct_stack_st_ASN1_TYPE) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_TYPE_value(arg_sk: ?*const struct_stack_st_ASN1_TYPE, arg_i: usize) callconv(.c) [*c]ASN1_TYPE { - const sk = arg_sk; - const i = arg_i; - return @as([*c]ASN1_TYPE, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_ASN1_TYPE_set(arg_sk: ?*struct_stack_st_ASN1_TYPE, arg_i: usize, arg_p: [*c]ASN1_TYPE) callconv(.c) [*c]ASN1_TYPE { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]ASN1_TYPE, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_ASN1_TYPE_free(arg_sk: ?*struct_stack_st_ASN1_TYPE) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_TYPE_pop_free(arg_sk: ?*struct_stack_st_ASN1_TYPE, arg_free_func: sk_ASN1_TYPE_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_TYPE_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_ASN1_TYPE_insert(arg_sk: ?*struct_stack_st_ASN1_TYPE, arg_p: [*c]ASN1_TYPE, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_ASN1_TYPE_delete(arg_sk: ?*struct_stack_st_ASN1_TYPE, arg_where: usize) callconv(.c) [*c]ASN1_TYPE { - const sk = arg_sk; - const where = arg_where; - return @as([*c]ASN1_TYPE, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_ASN1_TYPE_delete_ptr(arg_sk: ?*struct_stack_st_ASN1_TYPE, arg_p: [*c]const ASN1_TYPE) callconv(.c) [*c]ASN1_TYPE { - const sk = arg_sk; - const p = arg_p; - return @as([*c]ASN1_TYPE, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_ASN1_TYPE_find(arg_sk: ?*const struct_stack_st_ASN1_TYPE, arg_out_index: [*c]usize, arg_p: [*c]const ASN1_TYPE) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_ASN1_TYPE_call_cmp_func); -} -pub fn sk_ASN1_TYPE_shift(arg_sk: ?*struct_stack_st_ASN1_TYPE) callconv(.c) [*c]ASN1_TYPE { - const sk = arg_sk; - return @as([*c]ASN1_TYPE, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_ASN1_TYPE_push(arg_sk: ?*struct_stack_st_ASN1_TYPE, arg_p: [*c]ASN1_TYPE) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_ASN1_TYPE_pop(arg_sk: ?*struct_stack_st_ASN1_TYPE) callconv(.c) [*c]ASN1_TYPE { - const sk = arg_sk; - return @as([*c]ASN1_TYPE, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_ASN1_TYPE_dup(arg_sk: ?*const struct_stack_st_ASN1_TYPE) callconv(.c) ?*struct_stack_st_ASN1_TYPE { - const sk = arg_sk; - return @as(?*struct_stack_st_ASN1_TYPE, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_ASN1_TYPE_sort(arg_sk: ?*struct_stack_st_ASN1_TYPE) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_TYPE_call_cmp_func); -} -pub fn sk_ASN1_TYPE_is_sorted(arg_sk: ?*const struct_stack_st_ASN1_TYPE) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ASN1_TYPE_set_cmp_func(arg_sk: ?*struct_stack_st_ASN1_TYPE, arg_comp: sk_ASN1_TYPE_cmp_func) callconv(.c) sk_ASN1_TYPE_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_ASN1_TYPE_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_ASN1_TYPE_deep_copy(arg_sk: ?*const struct_stack_st_ASN1_TYPE, arg_copy_func: sk_ASN1_TYPE_copy_func, arg_free_func: sk_ASN1_TYPE_free_func) callconv(.c) ?*struct_stack_st_ASN1_TYPE { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_ASN1_TYPE, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_ASN1_TYPE_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_ASN1_TYPE_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn ASN1_TYPE_new() [*c]ASN1_TYPE; -pub extern fn ASN1_TYPE_free(a: [*c]ASN1_TYPE) void; -pub extern fn d2i_ASN1_TYPE(out: [*c][*c]ASN1_TYPE, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_TYPE; -pub extern fn i2d_ASN1_TYPE(in: [*c]const ASN1_TYPE, outp: [*c][*c]u8) c_int; -pub extern const ASN1_ANY_it: ASN1_ITEM; -pub extern fn ASN1_TYPE_get(a: [*c]const ASN1_TYPE) c_int; -pub extern fn ASN1_TYPE_set(a: [*c]ASN1_TYPE, @"type": c_int, value: ?*anyopaque) void; -pub extern fn ASN1_TYPE_set1(a: [*c]ASN1_TYPE, @"type": c_int, value: ?*const anyopaque) c_int; -pub extern fn ASN1_TYPE_cmp(a: [*c]const ASN1_TYPE, b: [*c]const ASN1_TYPE) c_int; -pub const ASN1_SEQUENCE_ANY = struct_stack_st_ASN1_TYPE; -pub extern fn d2i_ASN1_SEQUENCE_ANY(out: [*c]?*ASN1_SEQUENCE_ANY, inp: [*c][*c]const u8, len: c_long) ?*ASN1_SEQUENCE_ANY; -pub extern fn i2d_ASN1_SEQUENCE_ANY(in: ?*const ASN1_SEQUENCE_ANY, outp: [*c][*c]u8) c_int; -pub extern fn d2i_ASN1_SET_ANY(out: [*c]?*ASN1_SEQUENCE_ANY, inp: [*c][*c]const u8, len: c_long) ?*ASN1_SEQUENCE_ANY; -pub extern fn i2d_ASN1_SET_ANY(in: ?*const ASN1_SEQUENCE_ANY, outp: [*c][*c]u8) c_int; -pub extern fn ASN1_UTCTIME_print(out: [*c]BIO, a: [*c]const ASN1_UTCTIME) c_int; -pub extern fn ASN1_GENERALIZEDTIME_print(out: [*c]BIO, a: [*c]const ASN1_GENERALIZEDTIME) c_int; -pub extern fn ASN1_TIME_print(out: [*c]BIO, a: [*c]const ASN1_TIME) c_int; -pub extern fn ASN1_STRING_print(out: [*c]BIO, str: [*c]const ASN1_STRING) c_int; -pub extern fn ASN1_STRING_print_ex(out: [*c]BIO, str: [*c]const ASN1_STRING, flags: c_ulong) c_int; -// pub extern fn ASN1_STRING_print_ex_fp(fp: [*c]FILE, str: [*c]const ASN1_STRING, flags: c_ulong) c_int; -pub extern fn i2a_ASN1_INTEGER(bp: [*c]BIO, a: [*c]const ASN1_INTEGER) c_int; -pub extern fn i2a_ASN1_ENUMERATED(bp: [*c]BIO, a: [*c]const ASN1_ENUMERATED) c_int; -pub extern fn i2a_ASN1_OBJECT(bp: [*c]BIO, a: ?*const ASN1_OBJECT) c_int; -pub extern fn i2a_ASN1_STRING(bp: [*c]BIO, a: [*c]const ASN1_STRING, @"type": c_int) c_int; -pub extern fn i2t_ASN1_OBJECT(buf: [*c]u8, buf_len: c_int, a: ?*const ASN1_OBJECT) c_int; -pub extern fn ASN1_get_object(inp: [*c][*c]const u8, out_length: [*c]c_long, out_tag: [*c]c_int, out_class: [*c]c_int, max_len: c_long) c_int; -pub extern fn ASN1_put_object(outp: [*c][*c]u8, constructed: c_int, length: c_int, tag: c_int, xclass: c_int) void; -pub extern fn ASN1_put_eoc(outp: [*c][*c]u8) c_int; -pub extern fn ASN1_object_size(constructed: c_int, length: c_int, tag: c_int) c_int; -pub extern fn ASN1_STRING_set_default_mask(mask: c_ulong) void; -pub extern fn ASN1_STRING_set_default_mask_asc(p: [*c]const u8) c_int; -pub extern fn ASN1_STRING_get_default_mask() c_ulong; -pub extern fn ASN1_STRING_TABLE_cleanup() void; -pub extern fn ASN1_PRINTABLE_new() [*c]ASN1_STRING; -pub extern fn ASN1_PRINTABLE_free(str: [*c]ASN1_STRING) void; -pub extern fn d2i_ASN1_PRINTABLE(out: [*c][*c]ASN1_STRING, inp: [*c][*c]const u8, len: c_long) [*c]ASN1_STRING; -pub extern fn i2d_ASN1_PRINTABLE(in: [*c]const ASN1_STRING, outp: [*c][*c]u8) c_int; -pub extern const ASN1_PRINTABLE_it: ASN1_ITEM; -pub extern fn ASN1_INTEGER_set(a: [*c]ASN1_INTEGER, v: c_long) c_int; -pub extern fn ASN1_ENUMERATED_set(a: [*c]ASN1_ENUMERATED, v: c_long) c_int; -pub extern fn ASN1_INTEGER_get(a: [*c]const ASN1_INTEGER) c_long; -pub extern fn ASN1_ENUMERATED_get(a: [*c]const ASN1_ENUMERATED) c_long; -pub extern fn DH_new() ?*DH; -pub extern fn DH_free(dh: ?*DH) void; -pub extern fn DH_up_ref(dh: ?*DH) c_int; -pub extern fn DH_bits(dh: ?*const DH) c_uint; -pub extern fn DH_get0_pub_key(dh: ?*const DH) [*c]const BIGNUM; -pub extern fn DH_get0_priv_key(dh: ?*const DH) [*c]const BIGNUM; -pub extern fn DH_get0_p(dh: ?*const DH) [*c]const BIGNUM; -pub extern fn DH_get0_q(dh: ?*const DH) [*c]const BIGNUM; -pub extern fn DH_get0_g(dh: ?*const DH) [*c]const BIGNUM; -pub extern fn DH_get0_key(dh: ?*const DH, out_pub_key: [*c][*c]const BIGNUM, out_priv_key: [*c][*c]const BIGNUM) void; -pub extern fn DH_set0_key(dh: ?*DH, pub_key: [*c]BIGNUM, priv_key: [*c]BIGNUM) c_int; -pub extern fn DH_get0_pqg(dh: ?*const DH, out_p: [*c][*c]const BIGNUM, out_q: [*c][*c]const BIGNUM, out_g: [*c][*c]const BIGNUM) void; -pub extern fn DH_set0_pqg(dh: ?*DH, p: [*c]BIGNUM, q: [*c]BIGNUM, g: [*c]BIGNUM) c_int; -pub extern fn DH_set_length(dh: ?*DH, priv_length: c_uint) c_int; -pub extern fn DH_get_rfc7919_2048() ?*DH; -pub extern fn BN_get_rfc3526_prime_1536(ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn BN_get_rfc3526_prime_2048(ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn BN_get_rfc3526_prime_3072(ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn BN_get_rfc3526_prime_4096(ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn BN_get_rfc3526_prime_6144(ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn BN_get_rfc3526_prime_8192(ret: [*c]BIGNUM) [*c]BIGNUM; -pub extern fn DH_generate_parameters_ex(dh: ?*DH, prime_bits: c_int, generator: c_int, cb: [*c]BN_GENCB) c_int; -pub extern fn DH_generate_key(dh: ?*DH) c_int; -pub extern fn DH_compute_key_padded(out: [*c]u8, peers_key: [*c]const BIGNUM, dh: ?*DH) c_int; -pub extern fn DH_compute_key_hashed(dh: ?*DH, out: [*c]u8, out_len: [*c]usize, max_out_len: usize, peers_key: [*c]const BIGNUM, digest: ?*const EVP_MD) c_int; -pub extern fn DH_size(dh: ?*const DH) c_int; -pub extern fn DH_num_bits(dh: ?*const DH) c_uint; -pub extern fn DH_check(dh: ?*const DH, out_flags: [*c]c_int) c_int; -pub extern fn DH_check_pub_key(dh: ?*const DH, pub_key: [*c]const BIGNUM, out_flags: [*c]c_int) c_int; -pub extern fn DHparams_dup(dh: ?*const DH) ?*DH; -pub extern fn DH_parse_parameters(cbs: [*c]CBS) ?*DH; -pub extern fn DH_marshal_parameters(cbb: ?*CBB, dh: ?*const DH) c_int; -pub extern fn DH_generate_parameters(prime_len: c_int, generator: c_int, callback: ?*const fn (c_int, c_int, ?*anyopaque) callconv(.c) void, cb_arg: ?*anyopaque) ?*DH; -pub extern fn d2i_DHparams(ret: [*c]?*DH, inp: [*c][*c]const u8, len: c_long) ?*DH; -pub extern fn i2d_DHparams(in: ?*const DH, outp: [*c][*c]u8) c_int; -pub extern fn DH_compute_key(out: [*c]u8, peers_key: [*c]const BIGNUM, dh: ?*DH) c_int; -pub extern fn ENGINE_new() ?*ENGINE; -pub extern fn ENGINE_free(engine: ?*ENGINE) c_int; -pub extern fn ENGINE_set_RSA_method(engine: ?*ENGINE, method: [*c]const RSA_METHOD, method_size: usize) c_int; -pub extern fn ENGINE_get_RSA_method(engine: ?*const ENGINE) [*c]RSA_METHOD; -pub extern fn ENGINE_set_ECDSA_method(engine: ?*ENGINE, method: [*c]const ECDSA_METHOD, method_size: usize) c_int; -pub extern fn ENGINE_get_ECDSA_method(engine: ?*const ENGINE) [*c]ECDSA_METHOD; -pub extern fn METHOD_ref(method: ?*anyopaque) void; -pub extern fn METHOD_unref(method: ?*anyopaque) void; -pub extern fn DSA_new() [*c]DSA; -pub extern fn DSA_free(dsa: [*c]DSA) void; -pub extern fn DSA_up_ref(dsa: [*c]DSA) c_int; -pub extern fn DSA_bits(dsa: [*c]const DSA) c_uint; -pub extern fn DSA_get0_pub_key(dsa: [*c]const DSA) [*c]const BIGNUM; -pub extern fn DSA_get0_priv_key(dsa: [*c]const DSA) [*c]const BIGNUM; -pub extern fn DSA_get0_p(dsa: [*c]const DSA) [*c]const BIGNUM; -pub extern fn DSA_get0_q(dsa: [*c]const DSA) [*c]const BIGNUM; -pub extern fn DSA_get0_g(dsa: [*c]const DSA) [*c]const BIGNUM; -pub extern fn DSA_get0_key(dsa: [*c]const DSA, out_pub_key: [*c][*c]const BIGNUM, out_priv_key: [*c][*c]const BIGNUM) void; -pub extern fn DSA_get0_pqg(dsa: [*c]const DSA, out_p: [*c][*c]const BIGNUM, out_q: [*c][*c]const BIGNUM, out_g: [*c][*c]const BIGNUM) void; -pub extern fn DSA_set0_key(dsa: [*c]DSA, pub_key: [*c]BIGNUM, priv_key: [*c]BIGNUM) c_int; -pub extern fn DSA_set0_pqg(dsa: [*c]DSA, p: [*c]BIGNUM, q: [*c]BIGNUM, g: [*c]BIGNUM) c_int; -pub extern fn DSA_generate_parameters_ex(dsa: [*c]DSA, bits: c_uint, seed: [*c]const u8, seed_len: usize, out_counter: [*c]c_int, out_h: [*c]c_ulong, cb: [*c]BN_GENCB) c_int; -pub extern fn DSAparams_dup(dsa: [*c]const DSA) [*c]DSA; -pub extern fn DSA_generate_key(dsa: [*c]DSA) c_int; -pub extern fn DSA_SIG_new() [*c]DSA_SIG; -pub extern fn DSA_SIG_free(sig: [*c]DSA_SIG) void; -pub extern fn DSA_SIG_get0(sig: [*c]const DSA_SIG, out_r: [*c][*c]const BIGNUM, out_s: [*c][*c]const BIGNUM) void; -pub extern fn DSA_SIG_set0(sig: [*c]DSA_SIG, r: [*c]BIGNUM, s: [*c]BIGNUM) c_int; -pub extern fn DSA_do_sign(digest: [*c]const u8, digest_len: usize, dsa: [*c]const DSA) [*c]DSA_SIG; -pub extern fn DSA_do_verify(digest: [*c]const u8, digest_len: usize, sig: [*c]DSA_SIG, dsa: [*c]const DSA) c_int; -pub extern fn DSA_do_check_signature(out_valid: [*c]c_int, digest: [*c]const u8, digest_len: usize, sig: [*c]DSA_SIG, dsa: [*c]const DSA) c_int; -pub extern fn DSA_sign(@"type": c_int, digest: [*c]const u8, digest_len: usize, out_sig: [*c]u8, out_siglen: [*c]c_uint, dsa: [*c]const DSA) c_int; -pub extern fn DSA_verify(@"type": c_int, digest: [*c]const u8, digest_len: usize, sig: [*c]const u8, sig_len: usize, dsa: [*c]const DSA) c_int; -pub extern fn DSA_check_signature(out_valid: [*c]c_int, digest: [*c]const u8, digest_len: usize, sig: [*c]const u8, sig_len: usize, dsa: [*c]const DSA) c_int; -pub extern fn DSA_size(dsa: [*c]const DSA) c_int; -pub extern fn DSA_SIG_parse(cbs: [*c]CBS) [*c]DSA_SIG; -pub extern fn DSA_SIG_marshal(cbb: ?*CBB, sig: [*c]const DSA_SIG) c_int; -pub extern fn DSA_parse_public_key(cbs: [*c]CBS) [*c]DSA; -pub extern fn DSA_marshal_public_key(cbb: ?*CBB, dsa: [*c]const DSA) c_int; -pub extern fn DSA_parse_private_key(cbs: [*c]CBS) [*c]DSA; -pub extern fn DSA_marshal_private_key(cbb: ?*CBB, dsa: [*c]const DSA) c_int; -pub extern fn DSA_parse_parameters(cbs: [*c]CBS) [*c]DSA; -pub extern fn DSA_marshal_parameters(cbb: ?*CBB, dsa: [*c]const DSA) c_int; -pub extern fn DSA_dup_DH(dsa: [*c]const DSA) ?*DH; -pub extern fn DSA_get_ex_new_index(argl: c_long, argp: ?*anyopaque, unused: [*c]CRYPTO_EX_unused, dup_unused: ?*const CRYPTO_EX_dup, free_func: ?*const CRYPTO_EX_free) c_int; -pub extern fn DSA_set_ex_data(dsa: [*c]DSA, idx: c_int, arg: ?*anyopaque) c_int; -pub extern fn DSA_get_ex_data(dsa: [*c]const DSA, idx: c_int) ?*anyopaque; -pub extern fn d2i_DSA_SIG(out_sig: [*c][*c]DSA_SIG, inp: [*c][*c]const u8, len: c_long) [*c]DSA_SIG; -pub extern fn i2d_DSA_SIG(in: [*c]const DSA_SIG, outp: [*c][*c]u8) c_int; -pub extern fn d2i_DSAPublicKey(out: [*c][*c]DSA, inp: [*c][*c]const u8, len: c_long) [*c]DSA; -pub extern fn i2d_DSAPublicKey(in: [*c]const DSA, outp: [*c][*c]u8) c_int; -pub extern fn d2i_DSAPrivateKey(out: [*c][*c]DSA, inp: [*c][*c]const u8, len: c_long) [*c]DSA; -pub extern fn i2d_DSAPrivateKey(in: [*c]const DSA, outp: [*c][*c]u8) c_int; -pub extern fn d2i_DSAparams(out: [*c][*c]DSA, inp: [*c][*c]const u8, len: c_long) [*c]DSA; -pub extern fn i2d_DSAparams(in: [*c]const DSA, outp: [*c][*c]u8) c_int; -pub extern fn DSA_generate_parameters(bits: c_int, seed: [*c]u8, seed_len: c_int, counter_ret: [*c]c_int, h_ret: [*c]c_ulong, callback: ?*const fn (c_int, c_int, ?*anyopaque) callconv(.c) void, cb_arg: ?*anyopaque) [*c]DSA; -pub const POINT_CONVERSION_COMPRESSED: c_int = 2; -pub const POINT_CONVERSION_UNCOMPRESSED: c_int = 4; -pub const POINT_CONVERSION_HYBRID: c_int = 6; -pub const point_conversion_form_t = c_uint; -pub extern fn EC_GROUP_new_by_curve_name(nid: c_int) ?*EC_GROUP; -pub extern fn EC_GROUP_free(group: ?*EC_GROUP) void; -pub extern fn EC_GROUP_dup(a: ?*const EC_GROUP) ?*EC_GROUP; -pub extern fn EC_GROUP_cmp(a: ?*const EC_GROUP, b: ?*const EC_GROUP, ignored: ?*BN_CTX) c_int; -pub extern fn EC_GROUP_get0_generator(group: ?*const EC_GROUP) ?*const EC_POINT; -pub extern fn EC_GROUP_get0_order(group: ?*const EC_GROUP) [*c]const BIGNUM; -pub extern fn EC_GROUP_order_bits(group: ?*const EC_GROUP) c_int; -pub extern fn EC_GROUP_get_cofactor(group: ?*const EC_GROUP, cofactor: [*c]BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_GROUP_get_curve_GFp(group: ?*const EC_GROUP, out_p: [*c]BIGNUM, out_a: [*c]BIGNUM, out_b: [*c]BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_GROUP_get_curve_name(group: ?*const EC_GROUP) c_int; -pub extern fn EC_GROUP_get_degree(group: ?*const EC_GROUP) c_uint; -pub extern fn EC_curve_nid2nist(nid: c_int) [*c]const u8; -pub extern fn EC_curve_nist2nid(name: [*c]const u8) c_int; -pub extern fn EC_POINT_new(group: ?*const EC_GROUP) ?*EC_POINT; -pub extern fn EC_POINT_free(point: ?*EC_POINT) void; -pub extern fn EC_POINT_copy(dest: ?*EC_POINT, src: ?*const EC_POINT) c_int; -pub extern fn EC_POINT_dup(src: ?*const EC_POINT, group: ?*const EC_GROUP) ?*EC_POINT; -pub extern fn EC_POINT_set_to_infinity(group: ?*const EC_GROUP, point: ?*EC_POINT) c_int; -pub extern fn EC_POINT_is_at_infinity(group: ?*const EC_GROUP, point: ?*const EC_POINT) c_int; -pub extern fn EC_POINT_is_on_curve(group: ?*const EC_GROUP, point: ?*const EC_POINT, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_cmp(group: ?*const EC_GROUP, a: ?*const EC_POINT, b: ?*const EC_POINT, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_get_affine_coordinates_GFp(group: ?*const EC_GROUP, point: ?*const EC_POINT, x: [*c]BIGNUM, y: [*c]BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_get_affine_coordinates(group: ?*const EC_GROUP, point: ?*const EC_POINT, x: [*c]BIGNUM, y: [*c]BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_set_affine_coordinates_GFp(group: ?*const EC_GROUP, point: ?*EC_POINT, x: [*c]const BIGNUM, y: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_set_affine_coordinates(group: ?*const EC_GROUP, point: ?*EC_POINT, x: [*c]const BIGNUM, y: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_point2oct(group: ?*const EC_GROUP, point: ?*const EC_POINT, form: point_conversion_form_t, buf: [*c]u8, max_out: usize, ctx: ?*BN_CTX) usize; -pub extern fn EC_POINT_point2buf(group: ?*const EC_GROUP, point: ?*const EC_POINT, form: point_conversion_form_t, out_buf: [*c][*c]u8, ctx: ?*BN_CTX) usize; -pub extern fn EC_POINT_point2cbb(out: ?*CBB, group: ?*const EC_GROUP, point: ?*const EC_POINT, form: point_conversion_form_t, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_oct2point(group: ?*const EC_GROUP, point: ?*EC_POINT, buf: [*c]const u8, len: usize, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_set_compressed_coordinates_GFp(group: ?*const EC_GROUP, point: ?*EC_POINT, x: [*c]const BIGNUM, y_bit: c_int, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_add(group: ?*const EC_GROUP, r: ?*EC_POINT, a: ?*const EC_POINT, b: ?*const EC_POINT, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_dbl(group: ?*const EC_GROUP, r: ?*EC_POINT, a: ?*const EC_POINT, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_invert(group: ?*const EC_GROUP, a: ?*EC_POINT, ctx: ?*BN_CTX) c_int; -pub extern fn EC_POINT_mul(group: ?*const EC_GROUP, r: ?*EC_POINT, n: [*c]const BIGNUM, q: ?*const EC_POINT, m: [*c]const BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_GROUP_new_curve_GFp(p: [*c]const BIGNUM, a: [*c]const BIGNUM, b: [*c]const BIGNUM, ctx: ?*BN_CTX) ?*EC_GROUP; -pub extern fn EC_GROUP_set_generator(group: ?*EC_GROUP, generator: ?*const EC_POINT, order: [*c]const BIGNUM, cofactor: [*c]const BIGNUM) c_int; -pub extern fn EC_GROUP_get_order(group: ?*const EC_GROUP, order: [*c]BIGNUM, ctx: ?*BN_CTX) c_int; -pub extern fn EC_GROUP_set_asn1_flag(group: ?*EC_GROUP, flag: c_int) void; -pub extern fn EC_GROUP_get_asn1_flag(group: ?*const EC_GROUP) c_int; -pub const struct_ec_method_st = opaque {}; -pub const EC_METHOD = struct_ec_method_st; -pub extern fn EC_GROUP_method_of(group: ?*const EC_GROUP) ?*const EC_METHOD; -pub extern fn EC_METHOD_get_field_type(meth: ?*const EC_METHOD) c_int; -pub extern fn EC_GROUP_set_point_conversion_form(group: ?*EC_GROUP, form: point_conversion_form_t) void; -pub const EC_builtin_curve = extern struct { - nid: c_int, - comment: [*c]const u8, -}; -pub extern fn EC_get_builtin_curves(out_curves: [*c]EC_builtin_curve, max_num_curves: usize) usize; -pub extern fn EC_POINT_clear_free(point: ?*EC_POINT) void; -pub extern fn EC_KEY_new() ?*EC_KEY; -pub extern fn EC_KEY_new_method(engine: ?*const ENGINE) ?*EC_KEY; -pub extern fn EC_KEY_new_by_curve_name(nid: c_int) ?*EC_KEY; -pub extern fn EC_KEY_free(key: ?*EC_KEY) void; -pub extern fn EC_KEY_dup(src: ?*const EC_KEY) ?*EC_KEY; -pub extern fn EC_KEY_up_ref(key: ?*EC_KEY) c_int; -pub extern fn EC_KEY_is_opaque(key: ?*const EC_KEY) c_int; -pub extern fn EC_KEY_get0_group(key: ?*const EC_KEY) ?*const EC_GROUP; -pub extern fn EC_KEY_set_group(key: ?*EC_KEY, group: ?*const EC_GROUP) c_int; -pub extern fn EC_KEY_get0_private_key(key: ?*const EC_KEY) [*c]const BIGNUM; -pub extern fn EC_KEY_set_private_key(key: ?*EC_KEY, priv: [*c]const BIGNUM) c_int; -pub extern fn EC_KEY_get0_public_key(key: ?*const EC_KEY) ?*const EC_POINT; -pub extern fn EC_KEY_set_public_key(key: ?*EC_KEY, @"pub": ?*const EC_POINT) c_int; -pub extern fn EC_KEY_get_enc_flags(key: ?*const EC_KEY) c_uint; -pub extern fn EC_KEY_set_enc_flags(key: ?*EC_KEY, flags: c_uint) void; -pub extern fn EC_KEY_get_conv_form(key: ?*const EC_KEY) point_conversion_form_t; -pub extern fn EC_KEY_set_conv_form(key: ?*EC_KEY, cform: point_conversion_form_t) void; -pub extern fn EC_KEY_check_key(key: ?*const EC_KEY) c_int; -pub extern fn EC_KEY_check_fips(key: ?*const EC_KEY) c_int; -pub extern fn EC_KEY_set_public_key_affine_coordinates(key: ?*EC_KEY, x: [*c]const BIGNUM, y: [*c]const BIGNUM) c_int; -pub extern fn EC_KEY_oct2key(key: ?*EC_KEY, in: [*c]const u8, len: usize, ctx: ?*BN_CTX) c_int; -pub extern fn EC_KEY_key2buf(key: ?*const EC_KEY, form: point_conversion_form_t, out_buf: [*c][*c]u8, ctx: ?*BN_CTX) usize; -pub extern fn EC_KEY_oct2priv(key: ?*EC_KEY, in: [*c]const u8, len: usize) c_int; -pub extern fn EC_KEY_priv2oct(key: ?*const EC_KEY, out: [*c]u8, max_out: usize) usize; -pub extern fn EC_KEY_priv2buf(key: ?*const EC_KEY, out_buf: [*c][*c]u8) usize; -pub extern fn EC_KEY_generate_key(key: ?*EC_KEY) c_int; -pub extern fn EC_KEY_generate_key_fips(key: ?*EC_KEY) c_int; -pub extern fn EC_KEY_derive_from_secret(group: ?*const EC_GROUP, secret: [*c]const u8, secret_len: usize) ?*EC_KEY; -pub extern fn EC_KEY_parse_private_key(cbs: [*c]CBS, group: ?*const EC_GROUP) ?*EC_KEY; -pub extern fn EC_KEY_marshal_private_key(cbb: ?*CBB, key: ?*const EC_KEY, enc_flags: c_uint) c_int; -pub extern fn EC_KEY_parse_curve_name(cbs: [*c]CBS) ?*EC_GROUP; -pub extern fn EC_KEY_marshal_curve_name(cbb: ?*CBB, group: ?*const EC_GROUP) c_int; -pub extern fn EC_KEY_parse_parameters(cbs: [*c]CBS) ?*EC_GROUP; -pub extern fn EC_KEY_get_ex_new_index(argl: c_long, argp: ?*anyopaque, unused: [*c]CRYPTO_EX_unused, dup_unused: ?*const CRYPTO_EX_dup, free_func: ?*const CRYPTO_EX_free) c_int; -pub extern fn EC_KEY_set_ex_data(r: ?*EC_KEY, idx: c_int, arg: ?*anyopaque) c_int; -pub extern fn EC_KEY_get_ex_data(r: ?*const EC_KEY, idx: c_int) ?*anyopaque; -pub extern fn EC_KEY_set_asn1_flag(key: ?*EC_KEY, flag: c_int) void; -pub extern fn d2i_ECPrivateKey(out_key: [*c]?*EC_KEY, inp: [*c][*c]const u8, len: c_long) ?*EC_KEY; -pub extern fn i2d_ECPrivateKey(key: ?*const EC_KEY, outp: [*c][*c]u8) c_int; -pub extern fn d2i_ECParameters(out_key: [*c]?*EC_KEY, inp: [*c][*c]const u8, len: c_long) ?*EC_KEY; -pub extern fn i2d_ECParameters(key: ?*const EC_KEY, outp: [*c][*c]u8) c_int; -pub extern fn o2i_ECPublicKey(out_key: [*c]?*EC_KEY, inp: [*c][*c]const u8, len: c_long) ?*EC_KEY; -pub extern fn i2o_ECPublicKey(key: ?*const EC_KEY, outp: [*c][*c]u8) c_int; -pub extern fn ECDH_compute_key(out: ?*anyopaque, outlen: usize, pub_key: ?*const EC_POINT, priv_key: ?*const EC_KEY, kdf: ?*const fn (?*const anyopaque, usize, ?*anyopaque, [*c]usize) callconv(.c) ?*anyopaque) c_int; -pub extern fn ECDH_compute_key_fips(out: [*c]u8, out_len: usize, pub_key: ?*const EC_POINT, priv_key: ?*const EC_KEY) c_int; -pub extern fn ECDSA_sign(@"type": c_int, digest: [*c]const u8, digest_len: usize, sig: [*c]u8, sig_len: [*c]c_uint, key: ?*const EC_KEY) c_int; -pub extern fn ECDSA_verify(@"type": c_int, digest: [*c]const u8, digest_len: usize, sig: [*c]const u8, sig_len: usize, key: ?*const EC_KEY) c_int; -pub extern fn ECDSA_size(key: ?*const EC_KEY) usize; -pub extern fn ECDSA_SIG_new() [*c]ECDSA_SIG; -pub extern fn ECDSA_SIG_free(sig: [*c]ECDSA_SIG) void; -pub extern fn ECDSA_SIG_get0_r(sig: [*c]const ECDSA_SIG) [*c]const BIGNUM; -pub extern fn ECDSA_SIG_get0_s(sig: [*c]const ECDSA_SIG) [*c]const BIGNUM; -pub extern fn ECDSA_SIG_get0(sig: [*c]const ECDSA_SIG, out_r: [*c][*c]const BIGNUM, out_s: [*c][*c]const BIGNUM) void; -pub extern fn ECDSA_SIG_set0(sig: [*c]ECDSA_SIG, r: [*c]BIGNUM, s: [*c]BIGNUM) c_int; -pub extern fn ECDSA_do_sign(digest: [*c]const u8, digest_len: usize, key: ?*const EC_KEY) [*c]ECDSA_SIG; -pub extern fn ECDSA_do_verify(digest: [*c]const u8, digest_len: usize, sig: [*c]const ECDSA_SIG, key: ?*const EC_KEY) c_int; -pub extern fn ECDSA_SIG_parse(cbs: [*c]CBS) [*c]ECDSA_SIG; -pub extern fn ECDSA_SIG_from_bytes(in: [*c]const u8, in_len: usize) [*c]ECDSA_SIG; -pub extern fn ECDSA_SIG_marshal(cbb: ?*CBB, sig: [*c]const ECDSA_SIG) c_int; -pub extern fn ECDSA_SIG_to_bytes(out_bytes: [*c][*c]u8, out_len: [*c]usize, sig: [*c]const ECDSA_SIG) c_int; -pub extern fn ECDSA_SIG_max_len(order_len: usize) usize; -pub extern fn ECDSA_sign_with_nonce_and_leak_private_key_for_testing(digest: [*c]const u8, digest_len: usize, eckey: ?*const EC_KEY, nonce: [*c]const u8, nonce_len: usize) [*c]ECDSA_SIG; -pub extern fn d2i_ECDSA_SIG(out: [*c][*c]ECDSA_SIG, inp: [*c][*c]const u8, len: c_long) [*c]ECDSA_SIG; -pub extern fn i2d_ECDSA_SIG(sig: [*c]const ECDSA_SIG, outp: [*c][*c]u8) c_int; -// pub extern fn CBS_init(cbs: [*c]CBS, data: [*c]const u8, len: usize) void; -// pub extern fn CBS_skip(cbs: [*c]CBS, len: usize) c_int; -// pub extern fn CBS_data(cbs: [*c]const CBS) [*c]const u8; -// pub extern fn CBS_len(cbs: [*c]const CBS) usize; -// pub extern fn CBS_stow(cbs: [*c]const CBS, out_ptr: [*c][*c]u8, out_len: [*c]usize) c_int; -// pub extern fn CBS_strdup(cbs: [*c]const CBS, out_ptr: [*c][*c]u8) c_int; -// pub extern fn CBS_contains_zero_byte(cbs: [*c]const CBS) c_int; -// pub extern fn CBS_mem_equal(cbs: [*c]const CBS, data: [*c]const u8, len: usize) c_int; -// pub extern fn CBS_get_u8(cbs: [*c]CBS, out: [*c]u8) c_int; -// pub extern fn CBS_get_u16(cbs: [*c]CBS, out: [*c]u16) c_int; -// pub extern fn CBS_get_u16le(cbs: [*c]CBS, out: [*c]u16) c_int; -// pub extern fn CBS_get_u24(cbs: [*c]CBS, out: [*c]u32) c_int; -// pub extern fn CBS_get_u32(cbs: [*c]CBS, out: [*c]u32) c_int; -// pub extern fn CBS_get_u32le(cbs: [*c]CBS, out: [*c]u32) c_int; -// pub extern fn CBS_get_u64(cbs: [*c]CBS, out: [*c]u64) c_int; -// pub extern fn CBS_get_u64le(cbs: [*c]CBS, out: [*c]u64) c_int; -// pub extern fn CBS_get_last_u8(cbs: [*c]CBS, out: [*c]u8) c_int; -// pub extern fn CBS_get_bytes(cbs: [*c]CBS, out: [*c]CBS, len: usize) c_int; -// pub extern fn CBS_copy_bytes(cbs: [*c]CBS, out: [*c]u8, len: usize) c_int; -// pub extern fn CBS_get_u8_length_prefixed(cbs: [*c]CBS, out: [*c]CBS) c_int; -// pub extern fn CBS_get_u16_length_prefixed(cbs: [*c]CBS, out: [*c]CBS) c_int; -// pub extern fn CBS_get_u24_length_prefixed(cbs: [*c]CBS, out: [*c]CBS) c_int; -// pub extern fn CBS_get_until_first(cbs: [*c]CBS, out: [*c]CBS, c: u8) c_int; -// pub extern fn CBS_get_asn1(cbs: [*c]CBS, out: [*c]CBS, tag_value: CBS_ASN1_TAG) c_int; -// pub extern fn CBS_get_asn1_element(cbs: [*c]CBS, out: [*c]CBS, tag_value: CBS_ASN1_TAG) c_int; -// pub extern fn CBS_peek_asn1_tag(cbs: [*c]const CBS, tag_value: CBS_ASN1_TAG) c_int; -// pub extern fn CBS_get_any_asn1(cbs: [*c]CBS, out: [*c]CBS, out_tag: [*c]CBS_ASN1_TAG) c_int; -// pub extern fn CBS_get_any_asn1_element(cbs: [*c]CBS, out: [*c]CBS, out_tag: [*c]CBS_ASN1_TAG, out_header_len: [*c]usize) c_int; -// pub extern fn CBS_get_any_ber_asn1_element(cbs: [*c]CBS, out: [*c]CBS, out_tag: [*c]CBS_ASN1_TAG, out_header_len: [*c]usize, out_ber_found: [*c]c_int, out_indefinite: [*c]c_int) c_int; -// pub extern fn CBS_get_asn1_uint64(cbs: [*c]CBS, out: [*c]u64) c_int; -// pub extern fn CBS_get_asn1_int64(cbs: [*c]CBS, out: [*c]i64) c_int; -// pub extern fn CBS_get_asn1_bool(cbs: [*c]CBS, out: [*c]c_int) c_int; -// pub extern fn CBS_get_optional_asn1(cbs: [*c]CBS, out: [*c]CBS, out_present: [*c]c_int, tag: CBS_ASN1_TAG) c_int; -// pub extern fn CBS_get_optional_asn1_octet_string(cbs: [*c]CBS, out: [*c]CBS, out_present: [*c]c_int, tag: CBS_ASN1_TAG) c_int; -// pub extern fn CBS_get_optional_asn1_uint64(cbs: [*c]CBS, out: [*c]u64, tag: CBS_ASN1_TAG, default_value: u64) c_int; -// pub extern fn CBS_get_optional_asn1_bool(cbs: [*c]CBS, out: [*c]c_int, tag: CBS_ASN1_TAG, default_value: c_int) c_int; -// pub extern fn CBS_is_valid_asn1_bitstring(cbs: [*c]const CBS) c_int; -// pub extern fn CBS_asn1_bitstring_has_bit(cbs: [*c]const CBS, bit: c_uint) c_int; -// pub extern fn CBS_is_valid_asn1_integer(cbs: [*c]const CBS, out_is_negative: [*c]c_int) c_int; -// pub extern fn CBS_is_unsigned_asn1_integer(cbs: [*c]const CBS) c_int; -// pub extern fn CBS_asn1_oid_to_text(cbs: [*c]const CBS) [*c]u8; -// pub extern fn CBS_parse_generalized_time(cbs: [*c]const CBS, out_tm: [*c]struct_tm, allow_timezone_offset: c_int) c_int; -// pub extern fn CBS_parse_utc_time(cbs: [*c]const CBS, out_tm: [*c]struct_tm, allow_timezone_offset: c_int) c_int; -// pub extern fn CBB_zero(cbb: ?*CBB) void; -// pub extern fn CBB_init(cbb: ?*CBB, initial_capacity: usize) c_int; -// pub extern fn CBB_init_fixed(cbb: ?*CBB, buf: [*c]u8, len: usize) c_int; -// pub extern fn CBB_cleanup(cbb: ?*CBB) void; -// pub extern fn CBB_finish(cbb: ?*CBB, out_data: [*c][*c]u8, out_len: [*c]usize) c_int; -// pub extern fn CBB_flush(cbb: ?*CBB) c_int; -// pub extern fn CBB_data(cbb: ?*const CBB) [*c]const u8; -// pub extern fn CBB_len(cbb: ?*const CBB) usize; -// pub extern fn CBB_add_u8_length_prefixed(cbb: ?*CBB, out_contents: ?*CBB) c_int; -// pub extern fn CBB_add_u16_length_prefixed(cbb: ?*CBB, out_contents: ?*CBB) c_int; -// pub extern fn CBB_add_u24_length_prefixed(cbb: ?*CBB, out_contents: ?*CBB) c_int; -// pub extern fn CBB_add_asn1(cbb: ?*CBB, out_contents: ?*CBB, tag: CBS_ASN1_TAG) c_int; -// pub extern fn CBB_add_bytes(cbb: ?*CBB, data: [*c]const u8, len: usize) c_int; -// pub extern fn CBB_add_zeros(cbb: ?*CBB, len: usize) c_int; -// pub extern fn CBB_add_space(cbb: ?*CBB, out_data: [*c][*c]u8, len: usize) c_int; -// pub extern fn CBB_reserve(cbb: ?*CBB, out_data: [*c][*c]u8, len: usize) c_int; -// pub extern fn CBB_did_write(cbb: ?*CBB, len: usize) c_int; -// pub extern fn CBB_add_u8(cbb: ?*CBB, value: u8) c_int; -// pub extern fn CBB_add_u16(cbb: ?*CBB, value: u16) c_int; -// pub extern fn CBB_add_u16le(cbb: ?*CBB, value: u16) c_int; -// pub extern fn CBB_add_u24(cbb: ?*CBB, value: u32) c_int; -// pub extern fn CBB_add_u32(cbb: ?*CBB, value: u32) c_int; -// pub extern fn CBB_add_u32le(cbb: ?*CBB, value: u32) c_int; -// pub extern fn CBB_add_u64(cbb: ?*CBB, value: u64) c_int; -// pub extern fn CBB_add_u64le(cbb: ?*CBB, value: u64) c_int; -// pub extern fn CBB_discard_child(cbb: ?*CBB) void; -// pub extern fn CBB_add_asn1_uint64(cbb: ?*CBB, value: u64) c_int; -// pub extern fn CBB_add_asn1_uint64_with_tag(cbb: ?*CBB, value: u64, tag: CBS_ASN1_TAG) c_int; -// pub extern fn CBB_add_asn1_int64(cbb: ?*CBB, value: i64) c_int; -// pub extern fn CBB_add_asn1_int64_with_tag(cbb: ?*CBB, value: i64, tag: CBS_ASN1_TAG) c_int; -// pub extern fn CBB_add_asn1_octet_string(cbb: ?*CBB, data: [*c]const u8, data_len: usize) c_int; -// pub extern fn CBB_add_asn1_bool(cbb: ?*CBB, value: c_int) c_int; -// pub extern fn CBB_add_asn1_oid_from_text(cbb: ?*CBB, text: [*c]const u8, len: usize) c_int; -// pub extern fn CBB_flush_asn1_set_of(cbb: ?*CBB) c_int; -pub extern fn OBJ_dup(obj: ?*const ASN1_OBJECT) ?*ASN1_OBJECT; -pub extern fn OBJ_cmp(a: ?*const ASN1_OBJECT, b: ?*const ASN1_OBJECT) c_int; -pub extern fn OBJ_get0_data(obj: ?*const ASN1_OBJECT) [*c]const u8; -pub extern fn OBJ_length(obj: ?*const ASN1_OBJECT) usize; -pub extern fn OBJ_obj2nid(obj: ?*const ASN1_OBJECT) c_int; -pub extern fn OBJ_cbs2nid(cbs: [*c]const CBS) c_int; -pub extern fn OBJ_sn2nid(short_name: [*c]const u8) c_int; -pub extern fn OBJ_ln2nid(long_name: [*c]const u8) c_int; -pub extern fn OBJ_txt2nid(s: [*c]const u8) c_int; -pub extern fn OBJ_nid2obj(nid: c_int) ?*ASN1_OBJECT; -pub extern fn OBJ_nid2sn(nid: c_int) [*c]const u8; -pub extern fn OBJ_nid2ln(nid: c_int) [*c]const u8; -pub extern fn OBJ_nid2cbb(out: ?*CBB, nid: c_int) c_int; -pub extern fn OBJ_txt2obj(s: [*c]const u8, dont_search_names: c_int) ?*ASN1_OBJECT; -pub extern fn OBJ_obj2txt(out: [*c]u8, out_len: c_int, obj: ?*const ASN1_OBJECT, always_return_oid: c_int) c_int; -pub extern fn OBJ_create(oid: [*c]const u8, short_name: [*c]const u8, long_name: [*c]const u8) c_int; -pub extern fn OBJ_find_sigid_algs(sign_nid: c_int, out_digest_nid: [*c]c_int, out_pkey_nid: [*c]c_int) c_int; -pub extern fn OBJ_find_sigid_by_algs(out_sign_nid: [*c]c_int, digest_nid: c_int, pkey_nid: c_int) c_int; -pub const struct_obj_name_st = extern struct { - type: c_int, - alias: c_int, - name: [*c]const u8, - data: [*c]const u8, -}; -pub const OBJ_NAME = struct_obj_name_st; -pub extern fn OBJ_NAME_do_all_sorted(@"type": c_int, callback: ?*const fn ([*c]const OBJ_NAME, ?*anyopaque) callconv(.c) void, arg: ?*anyopaque) void; -pub extern fn OBJ_NAME_do_all(@"type": c_int, callback: ?*const fn ([*c]const OBJ_NAME, ?*anyopaque) callconv(.c) void, arg: ?*anyopaque) void; -pub extern fn OBJ_cleanup() void; -pub const sk_CRYPTO_BUFFER_free_func = ?*const fn (?*CRYPTO_BUFFER) callconv(.c) void; -pub const sk_CRYPTO_BUFFER_copy_func = ?*const fn (?*CRYPTO_BUFFER) callconv(.c) ?*CRYPTO_BUFFER; -pub const sk_CRYPTO_BUFFER_cmp_func = ?*const fn ([*c]?*const CRYPTO_BUFFER, [*c]?*const CRYPTO_BUFFER) callconv(.c) c_int; -pub fn sk_CRYPTO_BUFFER_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_CRYPTO_BUFFER_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*CRYPTO_BUFFER, @ptrCast(ptr))); -} -pub fn sk_CRYPTO_BUFFER_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_CRYPTO_BUFFER_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*CRYPTO_BUFFER, @ptrCast(ptr))))); -} -pub fn sk_CRYPTO_BUFFER_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const CRYPTO_BUFFER = @as(?*const CRYPTO_BUFFER, @ptrCast(a.*)); - var b_ptr: ?*const CRYPTO_BUFFER = @as(?*const CRYPTO_BUFFER, @ptrCast(b.*)); - return @as(sk_CRYPTO_BUFFER_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_CRYPTO_BUFFER_new(arg_comp: sk_CRYPTO_BUFFER_cmp_func) callconv(.c) ?*struct_stack_st_CRYPTO_BUFFER { - const comp = arg_comp; - return @as(?*struct_stack_st_CRYPTO_BUFFER, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_CRYPTO_BUFFER_new_null() callconv(.c) ?*struct_stack_st_CRYPTO_BUFFER { - return @as(?*struct_stack_st_CRYPTO_BUFFER, @ptrCast(sk_new_null())); -} -pub fn sk_CRYPTO_BUFFER_num(arg_sk: ?*const struct_stack_st_CRYPTO_BUFFER) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_CRYPTO_BUFFER_zero(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_CRYPTO_BUFFER_value(arg_sk: ?*const struct_stack_st_CRYPTO_BUFFER, arg_i: usize) callconv(.c) ?*CRYPTO_BUFFER { - const sk = arg_sk; - const i = arg_i; - return @as(?*CRYPTO_BUFFER, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_CRYPTO_BUFFER_set(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER, arg_i: usize, arg_p: ?*CRYPTO_BUFFER) callconv(.c) ?*CRYPTO_BUFFER { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*CRYPTO_BUFFER, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_CRYPTO_BUFFER_free(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_CRYPTO_BUFFER_pop_free(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER, arg_free_func: sk_CRYPTO_BUFFER_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_CRYPTO_BUFFER_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_CRYPTO_BUFFER_insert(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER, arg_p: ?*CRYPTO_BUFFER, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_CRYPTO_BUFFER_delete(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER, arg_where: usize) callconv(.c) ?*CRYPTO_BUFFER { - const sk = arg_sk; - const where = arg_where; - return @as(?*CRYPTO_BUFFER, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_CRYPTO_BUFFER_delete_ptr(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER, arg_p: ?*const CRYPTO_BUFFER) callconv(.c) ?*CRYPTO_BUFFER { - const sk = arg_sk; - const p = arg_p; - return @as(?*CRYPTO_BUFFER, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_CRYPTO_BUFFER_find(arg_sk: ?*const struct_stack_st_CRYPTO_BUFFER, arg_out_index: [*c]usize, arg_p: ?*const CRYPTO_BUFFER) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_CRYPTO_BUFFER_call_cmp_func); -} -pub fn sk_CRYPTO_BUFFER_shift(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER) callconv(.c) ?*CRYPTO_BUFFER { - const sk = arg_sk; - return @as(?*CRYPTO_BUFFER, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_CRYPTO_BUFFER_push(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER, arg_p: ?*CRYPTO_BUFFER) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_CRYPTO_BUFFER_pop(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER) callconv(.c) ?*CRYPTO_BUFFER { - const sk = arg_sk; - return @as(?*CRYPTO_BUFFER, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_CRYPTO_BUFFER_dup(arg_sk: ?*const struct_stack_st_CRYPTO_BUFFER) callconv(.c) ?*struct_stack_st_CRYPTO_BUFFER { - const sk = arg_sk; - return @as(?*struct_stack_st_CRYPTO_BUFFER, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_CRYPTO_BUFFER_sort(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_CRYPTO_BUFFER_call_cmp_func); -} -pub fn sk_CRYPTO_BUFFER_is_sorted(arg_sk: ?*const struct_stack_st_CRYPTO_BUFFER) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_CRYPTO_BUFFER_set_cmp_func(arg_sk: ?*struct_stack_st_CRYPTO_BUFFER, arg_comp: sk_CRYPTO_BUFFER_cmp_func) callconv(.c) sk_CRYPTO_BUFFER_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_CRYPTO_BUFFER_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_CRYPTO_BUFFER_deep_copy(arg_sk: ?*const struct_stack_st_CRYPTO_BUFFER, arg_copy_func: sk_CRYPTO_BUFFER_copy_func, arg_free_func: sk_CRYPTO_BUFFER_free_func) callconv(.c) ?*struct_stack_st_CRYPTO_BUFFER { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_CRYPTO_BUFFER, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_CRYPTO_BUFFER_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_CRYPTO_BUFFER_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn CRYPTO_BUFFER_POOL_new() ?*CRYPTO_BUFFER_POOL; -pub extern fn CRYPTO_BUFFER_POOL_free(pool: ?*CRYPTO_BUFFER_POOL) void; -pub extern fn CRYPTO_BUFFER_new(data: [*c]const u8, len: usize, pool: ?*CRYPTO_BUFFER_POOL) ?*CRYPTO_BUFFER; -pub extern fn CRYPTO_BUFFER_alloc(out_data: [*c][*c]u8, len: usize) ?*CRYPTO_BUFFER; -pub extern fn CRYPTO_BUFFER_new_from_CBS(cbs: [*c]const CBS, pool: ?*CRYPTO_BUFFER_POOL) ?*CRYPTO_BUFFER; -pub extern fn CRYPTO_BUFFER_new_from_static_data_unsafe(data: [*c]const u8, len: usize, pool: ?*CRYPTO_BUFFER_POOL) ?*CRYPTO_BUFFER; -pub extern fn CRYPTO_BUFFER_free(buf: ?*CRYPTO_BUFFER) void; -pub extern fn CRYPTO_BUFFER_up_ref(buf: ?*CRYPTO_BUFFER) c_int; -pub extern fn CRYPTO_BUFFER_data(buf: ?*const CRYPTO_BUFFER) [*c]const u8; -pub extern fn CRYPTO_BUFFER_len(buf: ?*const CRYPTO_BUFFER) usize; -pub extern fn CRYPTO_BUFFER_init_CBS(buf: ?*const CRYPTO_BUFFER, out: [*c]CBS) void; -pub extern fn RSA_new() ?*RSA; -pub extern fn RSA_new_method(engine: ?*const ENGINE) ?*RSA; -pub extern fn RSA_free(rsa: ?*RSA) void; -pub extern fn RSA_up_ref(rsa: ?*RSA) c_int; -pub extern fn RSA_bits(rsa: ?*const RSA) c_uint; -pub extern fn RSA_get0_n(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_e(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_d(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_p(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_q(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_dmp1(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_dmq1(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_iqmp(rsa: ?*const RSA) [*c]const BIGNUM; -pub extern fn RSA_get0_key(rsa: ?*const RSA, out_n: [*c][*c]const BIGNUM, out_e: [*c][*c]const BIGNUM, out_d: [*c][*c]const BIGNUM) void; -pub extern fn RSA_get0_factors(rsa: ?*const RSA, out_p: [*c][*c]const BIGNUM, out_q: [*c][*c]const BIGNUM) void; -pub extern fn RSA_get0_crt_params(rsa: ?*const RSA, out_dmp1: [*c][*c]const BIGNUM, out_dmq1: [*c][*c]const BIGNUM, out_iqmp: [*c][*c]const BIGNUM) void; -pub extern fn RSA_set0_key(rsa: ?*RSA, n: [*c]BIGNUM, e: [*c]BIGNUM, d: [*c]BIGNUM) c_int; -pub extern fn RSA_set0_factors(rsa: ?*RSA, p: [*c]BIGNUM, q: [*c]BIGNUM) c_int; -pub extern fn RSA_set0_crt_params(rsa: ?*RSA, dmp1: [*c]BIGNUM, dmq1: [*c]BIGNUM, iqmp: [*c]BIGNUM) c_int; -pub extern fn RSA_generate_key_ex(rsa: ?*RSA, bits: c_int, e: [*c]const BIGNUM, cb: [*c]BN_GENCB) c_int; -pub extern fn RSA_generate_key_fips(rsa: ?*RSA, bits: c_int, cb: [*c]BN_GENCB) c_int; -pub extern fn RSA_encrypt(rsa: ?*RSA, out_len: [*c]usize, out: [*c]u8, max_out: usize, in: [*c]const u8, in_len: usize, padding: c_int) c_int; -pub extern fn RSA_decrypt(rsa: ?*RSA, out_len: [*c]usize, out: [*c]u8, max_out: usize, in: [*c]const u8, in_len: usize, padding: c_int) c_int; -pub extern fn RSA_public_encrypt(flen: usize, from: [*c]const u8, to: [*c]u8, rsa: ?*RSA, padding: c_int) c_int; -pub extern fn RSA_private_decrypt(flen: usize, from: [*c]const u8, to: [*c]u8, rsa: ?*RSA, padding: c_int) c_int; -pub extern fn RSA_sign(hash_nid: c_int, digest: [*c]const u8, digest_len: usize, out: [*c]u8, out_len: [*c]c_uint, rsa: ?*RSA) c_int; -pub extern fn RSA_sign_pss_mgf1(rsa: ?*RSA, out_len: [*c]usize, out: [*c]u8, max_out: usize, digest: [*c]const u8, digest_len: usize, md: ?*const EVP_MD, mgf1_md: ?*const EVP_MD, salt_len: c_int) c_int; -pub extern fn RSA_sign_raw(rsa: ?*RSA, out_len: [*c]usize, out: [*c]u8, max_out: usize, in: [*c]const u8, in_len: usize, padding: c_int) c_int; -pub extern fn RSA_verify(hash_nid: c_int, digest: [*c]const u8, digest_len: usize, sig: [*c]const u8, sig_len: usize, rsa: ?*RSA) c_int; -pub extern fn RSA_verify_pss_mgf1(rsa: ?*RSA, digest: [*c]const u8, digest_len: usize, md: ?*const EVP_MD, mgf1_md: ?*const EVP_MD, salt_len: c_int, sig: [*c]const u8, sig_len: usize) c_int; -pub extern fn RSA_verify_raw(rsa: ?*RSA, out_len: [*c]usize, out: [*c]u8, max_out: usize, in: [*c]const u8, in_len: usize, padding: c_int) c_int; -pub extern fn RSA_private_encrypt(flen: usize, from: [*c]const u8, to: [*c]u8, rsa: ?*RSA, padding: c_int) c_int; -pub extern fn RSA_public_decrypt(flen: usize, from: [*c]const u8, to: [*c]u8, rsa: ?*RSA, padding: c_int) c_int; -pub extern fn RSA_size(rsa: ?*const RSA) c_uint; -pub extern fn RSA_is_opaque(rsa: ?*const RSA) c_int; -pub extern fn RSAPublicKey_dup(rsa: ?*const RSA) ?*RSA; -pub extern fn RSAPrivateKey_dup(rsa: ?*const RSA) ?*RSA; -pub extern fn RSA_check_key(rsa: ?*const RSA) c_int; -pub extern fn RSA_check_fips(key: ?*RSA) c_int; -pub extern fn RSA_verify_PKCS1_PSS_mgf1(rsa: ?*const RSA, mHash: [*c]const u8, Hash: ?*const EVP_MD, mgf1Hash: ?*const EVP_MD, EM: [*c]const u8, sLen: c_int) c_int; -pub extern fn RSA_padding_add_PKCS1_PSS_mgf1(rsa: ?*const RSA, EM: [*c]u8, mHash: [*c]const u8, Hash: ?*const EVP_MD, mgf1Hash: ?*const EVP_MD, sLen: c_int) c_int; -pub extern fn RSA_padding_add_PKCS1_OAEP_mgf1(to: [*c]u8, to_len: usize, from: [*c]const u8, from_len: usize, param: [*c]const u8, param_len: usize, md: ?*const EVP_MD, mgf1md: ?*const EVP_MD) c_int; -pub extern fn RSA_add_pkcs1_prefix(out_msg: [*c][*c]u8, out_msg_len: [*c]usize, is_alloced: [*c]c_int, hash_nid: c_int, digest: [*c]const u8, digest_len: usize) c_int; -pub extern fn RSA_parse_public_key(cbs: [*c]CBS) ?*RSA; -pub extern fn RSA_public_key_from_bytes(in: [*c]const u8, in_len: usize) ?*RSA; -pub extern fn RSA_marshal_public_key(cbb: ?*CBB, rsa: ?*const RSA) c_int; -pub extern fn RSA_public_key_to_bytes(out_bytes: [*c][*c]u8, out_len: [*c]usize, rsa: ?*const RSA) c_int; -pub extern fn RSA_parse_private_key(cbs: [*c]CBS) ?*RSA; -pub extern fn RSA_private_key_from_bytes(in: [*c]const u8, in_len: usize) ?*RSA; -pub extern fn RSA_marshal_private_key(cbb: ?*CBB, rsa: ?*const RSA) c_int; -pub extern fn RSA_private_key_to_bytes(out_bytes: [*c][*c]u8, out_len: [*c]usize, rsa: ?*const RSA) c_int; -pub extern fn RSA_get_ex_new_index(argl: c_long, argp: ?*anyopaque, unused: [*c]CRYPTO_EX_unused, dup_unused: ?*const CRYPTO_EX_dup, free_func: ?*const CRYPTO_EX_free) c_int; -pub extern fn RSA_set_ex_data(rsa: ?*RSA, idx: c_int, arg: ?*anyopaque) c_int; -pub extern fn RSA_get_ex_data(rsa: ?*const RSA, idx: c_int) ?*anyopaque; -pub extern fn RSA_flags(rsa: ?*const RSA) c_int; -pub extern fn RSA_test_flags(rsa: ?*const RSA, flags: c_int) c_int; -pub extern fn RSA_blinding_on(rsa: ?*RSA, ctx: ?*BN_CTX) c_int; -pub extern fn RSA_generate_key(bits: c_int, e: u64, callback: ?*anyopaque, cb_arg: ?*anyopaque) ?*RSA; -pub extern fn d2i_RSAPublicKey(out: [*c]?*RSA, inp: [*c][*c]const u8, len: c_long) ?*RSA; -pub extern fn i2d_RSAPublicKey(in: ?*const RSA, outp: [*c][*c]u8) c_int; -pub extern fn d2i_RSAPrivateKey(out: [*c]?*RSA, inp: [*c][*c]const u8, len: c_long) ?*RSA; -pub extern fn i2d_RSAPrivateKey(in: ?*const RSA, outp: [*c][*c]u8) c_int; -pub extern fn RSA_padding_add_PKCS1_PSS(rsa: ?*const RSA, EM: [*c]u8, mHash: [*c]const u8, Hash: ?*const EVP_MD, sLen: c_int) c_int; -pub extern fn RSA_verify_PKCS1_PSS(rsa: ?*const RSA, mHash: [*c]const u8, Hash: ?*const EVP_MD, EM: [*c]const u8, sLen: c_int) c_int; -pub extern fn RSA_padding_add_PKCS1_OAEP(to: [*c]u8, to_len: usize, from: [*c]const u8, from_len: usize, param: [*c]const u8, param_len: usize) c_int; -pub extern fn RSA_print(bio: [*c]BIO, rsa: ?*const RSA, indent: c_int) c_int; -pub extern fn RSA_get0_pss_params(rsa: ?*const RSA) [*c]const RSA_PSS_PARAMS; -pub extern fn SHA1_Init(sha: [*c]SHA_CTX) c_int; -pub extern fn SHA1_Update(sha: [*c]SHA_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn SHA1_Final(out: [*c]u8, sha: [*c]SHA_CTX) c_int; -pub extern fn SHA1(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8; -pub extern fn SHA1_Transform(sha: [*c]SHA_CTX, block: [*c]const u8) void; -pub extern fn SHA224_Init(sha: [*c]SHA256_CTX) c_int; -pub extern fn SHA224_Update(sha: [*c]SHA256_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn SHA224_Final(out: [*c]u8, sha: [*c]SHA256_CTX) c_int; -pub extern fn SHA224(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8; -pub extern fn SHA256_Init(sha: [*c]SHA256_CTX) c_int; -pub extern fn SHA256_Update(sha: [*c]SHA256_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn SHA256_Final(out: [*c]u8, sha: [*c]SHA256_CTX) c_int; -pub extern fn SHA256(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8; -pub extern fn SHA256_Transform(sha: [*c]SHA256_CTX, block: [*c]const u8) void; -pub extern fn SHA256_TransformBlocks(state: [*c]u32, data: [*c]const u8, num_blocks: usize) void; -pub extern fn SHA384_Init(sha: [*c]SHA512_CTX) c_int; -pub extern fn SHA384_Update(sha: [*c]SHA512_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn SHA384_Final(out: [*c]u8, sha: [*c]SHA512_CTX) c_int; -pub extern fn SHA384(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8; -pub extern fn SHA512_Init(sha: [*c]SHA512_CTX) c_int; -pub extern fn SHA512_Update(sha: [*c]SHA512_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn SHA512_Final(out: [*c]u8, sha: [*c]SHA512_CTX) c_int; -pub extern fn SHA512(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8; -pub extern fn SHA512_Transform(sha: [*c]SHA512_CTX, block: [*c]const u8) void; -pub extern fn SHA512_256_Init(sha: [*c]SHA512_CTX) c_int; -pub extern fn SHA512_256_Update(sha: [*c]SHA512_CTX, data: ?*const anyopaque, len: usize) c_int; -pub extern fn SHA512_256_Final(out: [*c]u8, sha: [*c]SHA512_CTX) c_int; -pub extern fn SHA512_256(data: [*c]const u8, len: usize, out: [*c]u8) [*c]u8; -pub const sk_X509_free_func = ?*const fn (?*X509) callconv(.c) void; -pub const sk_X509_copy_func = ?*const fn (?*X509) callconv(.c) ?*X509; -pub const sk_X509_cmp_func = ?*const fn ([*c]?*const X509, [*c]?*const X509) callconv(.c) c_int; -pub fn sk_X509_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509, @ptrCast(ptr))); -} -pub fn sk_X509_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509, @ptrCast(ptr))))); -} -pub fn sk_X509_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509 = @as(?*const X509, @ptrCast(a.*)); - var b_ptr: ?*const X509 = @as(?*const X509, @ptrCast(b.*)); - return @as(sk_X509_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_new(arg_comp: sk_X509_cmp_func) callconv(.c) ?*struct_stack_st_X509 { - const comp = arg_comp; - return @as(?*struct_stack_st_X509, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_new_null() callconv(.c) ?*struct_stack_st_X509 { - return @as(?*struct_stack_st_X509, @ptrCast(sk_new_null())); -} -pub fn sk_X509_num(arg_sk: ?*const struct_stack_st_X509) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_zero(arg_sk: ?*struct_stack_st_X509) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_value(arg_sk: ?*const struct_stack_st_X509, arg_i: usize) callconv(.c) ?*X509 { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_set(arg_sk: ?*struct_stack_st_X509, arg_i: usize, arg_p: ?*X509) callconv(.c) ?*X509 { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_free(arg_sk: ?*struct_stack_st_X509) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_pop_free(arg_sk: ?*struct_stack_st_X509, arg_free_func: sk_X509_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_insert(arg_sk: ?*struct_stack_st_X509, arg_p: ?*X509, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_delete(arg_sk: ?*struct_stack_st_X509, arg_where: usize) callconv(.c) ?*X509 { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_delete_ptr(arg_sk: ?*struct_stack_st_X509, arg_p: ?*const X509) callconv(.c) ?*X509 { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_find(arg_sk: ?*const struct_stack_st_X509, arg_out_index: [*c]usize, arg_p: ?*const X509) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_call_cmp_func); -} -pub fn sk_X509_shift(arg_sk: ?*struct_stack_st_X509) callconv(.c) ?*X509 { - const sk = arg_sk; - return @as(?*X509, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_push(arg_sk: ?*struct_stack_st_X509, arg_p: ?*X509) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_pop(arg_sk: ?*struct_stack_st_X509) callconv(.c) ?*X509 { - const sk = arg_sk; - return @as(?*X509, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_dup(arg_sk: ?*const struct_stack_st_X509) callconv(.c) ?*struct_stack_st_X509 { - const sk = arg_sk; - return @as(?*struct_stack_st_X509, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_sort(arg_sk: ?*struct_stack_st_X509) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_call_cmp_func); -} -pub fn sk_X509_is_sorted(arg_sk: ?*const struct_stack_st_X509) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_set_cmp_func(arg_sk: ?*struct_stack_st_X509, arg_comp: sk_X509_cmp_func) callconv(.c) sk_X509_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_deep_copy(arg_sk: ?*const struct_stack_st_X509, arg_copy_func: sk_X509_copy_func, arg_free_func: sk_X509_free_func) callconv(.c) ?*struct_stack_st_X509 { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const stack_free_func = ?*const fn (?*anyopaque) callconv(.c) void; -pub const stack_copy_func = ?*const fn (?*anyopaque) callconv(.c) ?*anyopaque; -pub const stack_cmp_func = ?*const fn ([*c]?*const anyopaque, [*c]?*const anyopaque) callconv(.c) c_int; -pub extern const X509_it: ASN1_ITEM; -pub extern fn X509_up_ref(x509: ?*X509) c_int; -pub extern fn X509_chain_up_ref(chain: ?*struct_stack_st_X509) ?*struct_stack_st_X509; -pub extern fn X509_dup(x509: ?*X509) ?*X509; -pub extern fn X509_free(x509: ?*X509) void; -pub extern fn d2i_X509(out: [*c]?*X509, inp: *[*]const u8, len: c_long) ?*X509; -pub extern fn X509_parse_from_buffer(buf: ?*CRYPTO_BUFFER) ?*X509; -pub extern fn i2d_X509(x509: ?*X509, outp: ?*[*]u8) c_int; -pub extern fn X509_get_version(x509: ?*const X509) c_long; -pub extern fn X509_get0_serialNumber(x509: ?*const X509) [*c]const ASN1_INTEGER; -pub extern fn X509_get0_notBefore(x509: ?*const X509) [*c]const ASN1_TIME; -pub extern fn X509_get0_notAfter(x509: ?*const X509) [*c]const ASN1_TIME; -pub extern fn X509_get_issuer_name(x509: ?*const X509) ?*X509_NAME; -pub extern fn X509_get_subject_name(x509: ?*const X509) ?*X509_NAME; -pub extern fn X509_get_X509_PUBKEY(x509: ?*const X509) ?*X509_PUBKEY; -pub extern fn X509_get_pubkey(x509: ?*X509) [*c]EVP_PKEY; -pub extern fn X509_get0_pubkey_bitstr(x509: ?*const X509) [*c]ASN1_BIT_STRING; -pub extern fn X509_get0_uids(x509: ?*const X509, out_issuer_uid: [*c][*c]const ASN1_BIT_STRING, out_subject_uid: [*c][*c]const ASN1_BIT_STRING) void; -pub const struct_stack_st_X509_EXTENSION = opaque {}; -pub extern fn X509_get0_extensions(x509: ?*const X509) ?*const struct_stack_st_X509_EXTENSION; -pub extern fn X509_get_ext_count(x: ?*const X509) c_int; -pub extern fn X509_get_ext_by_NID(x: ?*const X509, nid: c_int, lastpos: c_int) c_int; -pub extern fn X509_get_ext_by_OBJ(x: ?*const X509, obj: ?*const ASN1_OBJECT, lastpos: c_int) c_int; -pub extern fn X509_get_ext_by_critical(x: ?*const X509, crit: c_int, lastpos: c_int) c_int; -pub extern fn X509_get_ext(x: ?*const X509, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509_get0_tbs_sigalg(x509: ?*const X509) [*c]const X509_ALGOR; -pub extern fn X509_get0_signature(out_sig: [*c][*c]const ASN1_BIT_STRING, out_alg: [*c][*c]const X509_ALGOR, x509: ?*const X509) void; -pub extern fn X509_get_signature_nid(x509: ?*const X509) c_int; -pub extern fn i2d_X509_tbs(x509: ?*X509, outp: [*c][*c]u8) c_int; -pub extern fn X509_new() ?*X509; -pub extern fn X509_set_version(x509: ?*X509, version: c_long) c_int; -pub extern fn X509_set_serialNumber(x509: ?*X509, serial: [*c]const ASN1_INTEGER) c_int; -pub extern fn X509_set1_notBefore(x509: ?*X509, tm: [*c]const ASN1_TIME) c_int; -pub extern fn X509_set1_notAfter(x509: ?*X509, tm: [*c]const ASN1_TIME) c_int; -pub extern fn X509_getm_notBefore(x509: ?*X509) [*c]ASN1_TIME; -pub extern fn X509_getm_notAfter(x: ?*X509) [*c]ASN1_TIME; -pub extern fn X509_set_issuer_name(x509: ?*X509, name: ?*X509_NAME) c_int; -pub extern fn X509_set_subject_name(x509: ?*X509, name: ?*X509_NAME) c_int; -pub extern fn X509_set_pubkey(x509: ?*X509, pkey: [*c]EVP_PKEY) c_int; -pub extern fn X509_delete_ext(x: ?*X509, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509_add_ext(x: ?*X509, ex: ?*const X509_EXTENSION, loc: c_int) c_int; -pub extern fn X509_sign(x509: ?*X509, pkey: [*c]EVP_PKEY, md: ?*const EVP_MD) c_int; -pub extern fn X509_sign_ctx(x509: ?*X509, ctx: [*c]EVP_MD_CTX) c_int; -pub extern fn i2d_re_X509_tbs(x509: ?*X509, outp: [*c][*c]u8) c_int; -pub extern fn X509_set1_signature_algo(x509: ?*X509, algo: [*c]const X509_ALGOR) c_int; -pub extern fn X509_set1_signature_value(x509: ?*X509, sig: [*c]const u8, sig_len: usize) c_int; -pub extern fn i2d_X509_AUX(x509: ?*X509, outp: [*c][*c]u8) c_int; -pub extern fn d2i_X509_AUX(x509: [*c]?*X509, inp: [*c][*c]const u8, length: c_long) ?*X509; -pub extern fn X509_alias_set1(x509: ?*X509, name: [*c]const u8, len: c_int) c_int; -pub extern fn X509_keyid_set1(x509: ?*X509, id: [*c]const u8, len: c_int) c_int; -pub extern fn X509_alias_get0(x509: ?*X509, out_len: [*c]c_int) [*c]u8; -pub extern fn X509_keyid_get0(x509: ?*X509, out_len: [*c]c_int) [*c]u8; -pub const sk_X509_CRL_free_func = ?*const fn (?*X509_CRL) callconv(.c) void; -pub const sk_X509_CRL_copy_func = ?*const fn (?*X509_CRL) callconv(.c) ?*X509_CRL; -pub const sk_X509_CRL_cmp_func = ?*const fn ([*c]?*const X509_CRL, [*c]?*const X509_CRL) callconv(.c) c_int; -pub fn sk_X509_CRL_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_CRL_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_CRL, @ptrCast(ptr))); -} -pub extern fn X509V3_EXT_d2i(ex: ?*X509_EXTENSION) ?*anyopaque; -pub extern fn X509V3_EXT_get(ex: ?*X509_EXTENSION) ?*X509V3_EXT_METHOD; -pub const X509V3_EXT_METHOD = opaque {}; -pub extern fn X509V3_EXT_get_nid(ndi: c_int) ?*X509V3_EXT_METHOD; -pub fn sk_X509_CRL_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_CRL = @as(?*const X509_CRL, @ptrCast(a.*)); - var b_ptr: ?*const X509_CRL = @as(?*const X509_CRL, @ptrCast(b.*)); - return @as(sk_X509_CRL_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub const struct_stack_st_X509_REVOKED = opaque {}; -pub const stack_X509_REVOKED_free_func = ?*const fn ([*c]X509_REVOKED) callconv(.c) void; -pub const stack_X509_REVOKED_copy_func = ?*const fn ([*c]X509_REVOKED) callconv(.c) [*c]X509_REVOKED; -pub const stack_X509_REVOKED_cmp_func = ?*const fn ([*c][*c]const X509_REVOKED, [*c][*c]const X509_REVOKED) callconv(.c) c_int; -pub const struct_stack_st_GENERAL_NAMES = opaque {}; -pub const struct_stack_st_ACCESS_DESCRIPTION = opaque {}; - -pub const OTHERNAME = extern struct { - type_id: ?*ASN1_OBJECT, - value: ?*ASN1_TYPE, -}; - -pub const GENERAL_NAME = extern struct { - name_type: enum(c_int) { - GEN_OTHERNAME = 0, - GEN_EMAIL = 1, - GEN_DNS = 2, - GEN_X400 = 3, - GEN_DIRNAME = 4, - GEN_EDIPARTY = 5, - GEN_URI = 6, - GEN_IPADD = 7, - GEN_RID = 8, - }, - d: extern union { - ptr: *c_char, - otherName: *OTHERNAME, - rfc822Name: *ASN1_IA5STRING, - dNSName: *ASN1_IA5STRING, - x400Address: *ASN1_STRING, - directoryName: *X509_NAME, - //EDIPARTYNAME - ediPartyName: *anyopaque, - uniformResourceIdentifier: *ASN1_IA5STRING, - iPAddress: *ASN1_OCTET_STRING, - registeredID: *ASN1_OBJECT, - ip: *ASN1_OCTET_STRING, - dirn: *X509_NAME, - ia5: *ASN1_IA5STRING, - rid: *ASN1_OBJECT, - other: *ASN1_TYPE, - }, -}; - -pub const ACCESS_DESCRIPTION = extern struct { - method: *ASN1_OBJECT, - location: *GENERAL_NAME, -}; - -pub fn sk_GENERAL_NAME_num(arg_sk: ?*const struct_stack_st_GENERAL_NAME) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_GENERAL_NAME_free(arg_sk: ?*struct_stack_st_GENERAL_NAME) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub const stack_GENERAL_NAME_free_func = ?*const fn (?*struct_stack_st_GENERAL_NAME) callconv(.c) void; - -pub fn sk_GENERAL_NAME_call_free_func(arg_free_func: stack_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(stack_GENERAL_NAME_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*struct_stack_st_GENERAL_NAME, @ptrCast(ptr))); -} -pub fn sk_GENERAL_NAME_pop_free(arg_sk: ?*struct_stack_st_GENERAL_NAME, arg_free_func: stack_GENERAL_NAME_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), sk_GENERAL_NAME_call_free_func, @as(stack_free_func, @ptrCast(free_func))); -} -pub fn sk_GENERAL_NAME_value(arg_sk: ?*const struct_stack_st_GENERAL_NAME, arg_i: usize) callconv(.c) ?*GENERAL_NAME { - const sk = arg_sk; - const i = arg_i; - return @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} - -pub fn sk_ACCESS_DESCRIPTION_num(arg_sk: ?*const AUTHORITY_INFO_ACCESS) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_ACCESS_DESCRIPTION_free(arg_sk: ?*AUTHORITY_INFO_ACCESS) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub const stack_ACCESS_DESCRIPTION_free_func = ?*const fn (?*AUTHORITY_INFO_ACCESS) callconv(.c) void; - -pub fn sk_ACCESS_DESCRIPTION_call_free_func(arg_free_func: stack_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(stack_ACCESS_DESCRIPTION_free_func, @ptrCast(free_func)).?(@as(?*AUTHORITY_INFO_ACCESS, @ptrCast(ptr))); -} -pub fn sk_ACCESS_DESCRIPTION_pop_free(arg_sk: ?*AUTHORITY_INFO_ACCESS, arg_free_func: stack_ACCESS_DESCRIPTION_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), sk_ACCESS_DESCRIPTION_call_free_func, @as(stack_free_func, @ptrCast(free_func))); -} -pub extern fn X509_get_serialNumber(x509: ?*X509) [*c]ASN1_INTEGER; -pub fn sk_ACCESS_DESCRIPTION_value(arg_sk: ?*const AUTHORITY_INFO_ACCESS, arg_i: usize) callconv(.c) ?*ACCESS_DESCRIPTION { - const sk = arg_sk; - const i = arg_i; - return @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub const NID_id_on_SmtpUTF8Mailbox = @as(c_int, 1208); -pub const NID_XmppAddr = @as(c_int, 1209); -pub const NID_SRVName = @as(c_int, 1210); -pub const NID_NAIRealm = @as(c_int, 1211); - -pub const stack_X509_CRL_free_func = ?*const fn (?*X509_CRL) callconv(.c) void; -pub const stack_X509_CRL_copy_func = ?*const fn (?*X509_CRL) callconv(.c) ?*X509_CRL; -pub const stack_X509_CRL_cmp_func = ?*const fn ([*c]?*const X509_CRL, [*c]?*const X509_CRL) callconv(.c) c_int; -pub fn sk_X509_CRL_call_copy_func(arg_copy_func: stack_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(stack_X509_CRL_copy_func, @ptrCast(copy_func)).?(@as(?*X509_CRL, @ptrCast(ptr))))); -} -pub fn sk_X509_CRL_new(arg_comp: stack_X509_CRL_cmp_func) callconv(.c) ?*struct_stack_st_X509_CRL { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_CRL, @ptrCast(sk_new(@as(stack_cmp_func, @ptrCast(comp))))); -} -pub fn sk_X509_CRL_new_null() callconv(.c) ?*struct_stack_st_X509_CRL { - return @as(?*struct_stack_st_X509_CRL, @ptrCast(sk_new_null())); -} -pub fn sk_X509_CRL_num(arg_sk: ?*const struct_stack_st_X509_CRL) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_CRL_zero(arg_sk: ?*struct_stack_st_X509_CRL) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_CRL_value(arg_sk: ?*const struct_stack_st_X509_CRL, arg_i: usize) callconv(.c) ?*X509_CRL { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_CRL, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_CRL_set(arg_sk: ?*struct_stack_st_X509_CRL, arg_i: usize, arg_p: ?*X509_CRL) callconv(.c) ?*X509_CRL { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_CRL, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_CRL_free(arg_sk: ?*struct_stack_st_X509_CRL) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_CRL_pop_free(arg_sk: ?*struct_stack_st_X509_CRL, arg_free_func: sk_X509_CRL_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_CRL_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_CRL_insert(arg_sk: ?*struct_stack_st_X509_CRL, arg_p: ?*X509_CRL, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_CRL_delete(arg_sk: ?*struct_stack_st_X509_CRL, arg_where: usize) callconv(.c) ?*X509_CRL { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_CRL, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_CRL_delete_ptr(arg_sk: ?*struct_stack_st_X509_CRL, arg_p: ?*const X509_CRL) callconv(.c) ?*X509_CRL { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_CRL, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_CRL_find(arg_sk: ?*const struct_stack_st_X509_CRL, arg_out_index: [*c]usize, arg_p: ?*const X509_CRL) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_CRL_call_cmp_func); -} -pub fn sk_X509_CRL_shift(arg_sk: ?*struct_stack_st_X509_CRL) callconv(.c) ?*X509_CRL { - const sk = arg_sk; - return @as(?*X509_CRL, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_CRL_push(arg_sk: ?*struct_stack_st_X509_CRL, arg_p: ?*X509_CRL) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_CRL_pop(arg_sk: ?*struct_stack_st_X509_CRL) callconv(.c) ?*X509_CRL { - const sk = arg_sk; - return @as(?*X509_CRL, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_CRL_dup(arg_sk: ?*const struct_stack_st_X509_CRL) callconv(.c) ?*struct_stack_st_X509_CRL { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_CRL, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_CRL_sort(arg_sk: ?*struct_stack_st_X509_CRL) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_CRL_call_cmp_func); -} -pub fn sk_X509_CRL_is_sorted(arg_sk: ?*const struct_stack_st_X509_CRL) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_CRL_set_cmp_func(arg_sk: ?*struct_stack_st_X509_CRL, arg_comp: sk_X509_CRL_cmp_func) callconv(.c) sk_X509_CRL_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_CRL_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_CRL_deep_copy(arg_sk: ?*const struct_stack_st_X509_CRL, arg_copy_func: sk_X509_CRL_copy_func, arg_free_func: sk_X509_CRL_free_func) callconv(.c) ?*struct_stack_st_X509_CRL { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_CRL, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_CRL_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_CRL_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern const X509_CRL_it: ASN1_ITEM; -pub extern fn X509_CRL_up_ref(crl: ?*X509_CRL) c_int; -pub extern fn X509_CRL_dup(crl: ?*X509_CRL) ?*X509_CRL; -pub extern fn X509_CRL_free(crl: ?*X509_CRL) void; -pub extern fn d2i_X509_CRL(out: [*c]?*X509_CRL, inp: [*c][*c]const u8, len: c_long) ?*X509_CRL; -pub extern fn i2d_X509_CRL(crl: ?*X509_CRL, outp: [*c][*c]u8) c_int; -pub extern fn X509_CRL_get_version(crl: ?*const X509_CRL) c_long; -pub extern fn X509_CRL_get0_lastUpdate(crl: ?*const X509_CRL) [*c]const ASN1_TIME; -pub extern fn X509_CRL_get0_nextUpdate(crl: ?*const X509_CRL) [*c]const ASN1_TIME; -pub extern fn X509_CRL_get_issuer(crl: ?*const X509_CRL) ?*X509_NAME; -pub extern fn X509_CRL_get_REVOKED(crl: ?*X509_CRL) ?*struct_stack_st_X509_REVOKED; -pub extern fn X509_CRL_get0_extensions(crl: ?*const X509_CRL) ?*const struct_stack_st_X509_EXTENSION; -pub extern fn X509_CRL_get_ext_count(x: ?*const X509_CRL) c_int; -pub extern fn X509_CRL_get_ext_by_NID(x: ?*const X509_CRL, nid: c_int, lastpos: c_int) c_int; -pub extern fn X509_CRL_get_ext_by_OBJ(x: ?*const X509_CRL, obj: ?*const ASN1_OBJECT, lastpos: c_int) c_int; -pub extern fn X509_CRL_get_ext_by_critical(x: ?*const X509_CRL, crit: c_int, lastpos: c_int) c_int; -pub extern fn X509_CRL_get_ext(x: ?*const X509_CRL, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509_CRL_get0_signature(crl: ?*const X509_CRL, out_sig: [*c][*c]const ASN1_BIT_STRING, out_alg: [*c][*c]const X509_ALGOR) void; -pub extern fn X509_CRL_get_signature_nid(crl: ?*const X509_CRL) c_int; -pub extern fn i2d_X509_CRL_tbs(crl: ?*X509_CRL, outp: [*c][*c]u8) c_int; -pub extern fn X509_CRL_new() ?*X509_CRL; -pub extern fn X509_CRL_set_version(crl: ?*X509_CRL, version: c_long) c_int; -pub extern fn X509_CRL_set_issuer_name(crl: ?*X509_CRL, name: ?*X509_NAME) c_int; -pub extern fn X509_CRL_set1_lastUpdate(crl: ?*X509_CRL, tm: [*c]const ASN1_TIME) c_int; -pub extern fn X509_CRL_set1_nextUpdate(crl: ?*X509_CRL, tm: [*c]const ASN1_TIME) c_int; -pub extern fn X509_CRL_delete_ext(x: ?*X509_CRL, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509_CRL_add_ext(x: ?*X509_CRL, ex: ?*const X509_EXTENSION, loc: c_int) c_int; -pub extern fn X509_CRL_sign(crl: ?*X509_CRL, pkey: [*c]EVP_PKEY, md: ?*const EVP_MD) c_int; -pub extern fn X509_CRL_sign_ctx(crl: ?*X509_CRL, ctx: [*c]EVP_MD_CTX) c_int; -pub extern fn i2d_re_X509_CRL_tbs(crl: ?*X509_CRL, outp: [*c][*c]u8) c_int; -pub extern fn X509_CRL_set1_signature_algo(crl: ?*X509_CRL, algo: [*c]const X509_ALGOR) c_int; -pub extern fn X509_CRL_set1_signature_value(crl: ?*X509_CRL, sig: [*c]const u8, sig_len: usize) c_int; -pub extern const X509_REQ_it: ASN1_ITEM; -pub extern fn X509_REQ_dup(req: ?*X509_REQ) ?*X509_REQ; -pub extern fn X509_REQ_free(req: ?*X509_REQ) void; -pub extern fn d2i_X509_REQ(out: [*c]?*X509_REQ, inp: [*c][*c]const u8, len: c_long) ?*X509_REQ; -pub extern fn i2d_X509_REQ(req: ?*X509_REQ, outp: [*c][*c]u8) c_int; -pub extern fn X509_REQ_get_version(req: ?*const X509_REQ) c_long; -pub extern fn X509_REQ_get_subject_name(req: ?*const X509_REQ) ?*X509_NAME; -pub extern fn X509_REQ_get_pubkey(req: ?*X509_REQ) [*c]EVP_PKEY; -pub extern fn X509_REQ_get0_signature(req: ?*const X509_REQ, out_sig: [*c][*c]const ASN1_BIT_STRING, out_alg: [*c][*c]const X509_ALGOR) void; -pub extern fn X509_REQ_get_signature_nid(req: ?*const X509_REQ) c_int; -pub extern fn X509_REQ_new() ?*X509_REQ; -pub extern fn X509_REQ_set_version(req: ?*X509_REQ, version: c_long) c_int; -pub extern fn X509_REQ_set_subject_name(req: ?*X509_REQ, name: ?*X509_NAME) c_int; -pub extern fn X509_REQ_set_pubkey(req: ?*X509_REQ, pkey: [*c]EVP_PKEY) c_int; -pub extern fn X509_REQ_sign(req: ?*X509_REQ, pkey: [*c]EVP_PKEY, md: ?*const EVP_MD) c_int; -pub extern fn X509_REQ_sign_ctx(req: ?*X509_REQ, ctx: [*c]EVP_MD_CTX) c_int; -pub extern fn i2d_re_X509_REQ_tbs(req: ?*X509_REQ, outp: [*c][*c]u8) c_int; -pub extern fn X509_REQ_set1_signature_algo(req: ?*X509_REQ, algo: [*c]const X509_ALGOR) c_int; -pub extern fn X509_REQ_set1_signature_value(req: ?*X509_REQ, sig: [*c]const u8, sig_len: usize) c_int; -pub const struct_stack_st_X509_NAME_ENTRY = opaque {}; -pub const sk_X509_NAME_ENTRY_free_func = ?*const fn (?*X509_NAME_ENTRY) callconv(.c) void; -pub const sk_X509_NAME_ENTRY_copy_func = ?*const fn (?*X509_NAME_ENTRY) callconv(.c) ?*X509_NAME_ENTRY; -pub const sk_X509_NAME_ENTRY_cmp_func = ?*const fn ([*c]?*const X509_NAME_ENTRY, [*c]?*const X509_NAME_ENTRY) callconv(.c) c_int; -pub fn sk_X509_NAME_ENTRY_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_NAME_ENTRY_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_NAME_ENTRY, @ptrCast(ptr))); -} -pub fn sk_X509_NAME_ENTRY_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_NAME_ENTRY_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_NAME_ENTRY, @ptrCast(ptr))))); -} -pub fn sk_X509_NAME_ENTRY_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_NAME_ENTRY = @as(?*const X509_NAME_ENTRY, @ptrCast(a.*)); - var b_ptr: ?*const X509_NAME_ENTRY = @as(?*const X509_NAME_ENTRY, @ptrCast(b.*)); - return @as(sk_X509_NAME_ENTRY_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_NAME_ENTRY_new(arg_comp: sk_X509_NAME_ENTRY_cmp_func) callconv(.c) ?*struct_stack_st_X509_NAME_ENTRY { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_NAME_ENTRY, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_NAME_ENTRY_new_null() callconv(.c) ?*struct_stack_st_X509_NAME_ENTRY { - return @as(?*struct_stack_st_X509_NAME_ENTRY, @ptrCast(sk_new_null())); -} -pub fn sk_X509_NAME_ENTRY_num(arg_sk: ?*const struct_stack_st_X509_NAME_ENTRY) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_ENTRY_zero(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_ENTRY_value(arg_sk: ?*const struct_stack_st_X509_NAME_ENTRY, arg_i: usize) callconv(.c) ?*X509_NAME_ENTRY { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_NAME_ENTRY, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_NAME_ENTRY_set(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY, arg_i: usize, arg_p: ?*X509_NAME_ENTRY) callconv(.c) ?*X509_NAME_ENTRY { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_NAME_ENTRY, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_NAME_ENTRY_free(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_ENTRY_pop_free(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY, arg_free_func: sk_X509_NAME_ENTRY_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_NAME_ENTRY_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_NAME_ENTRY_insert(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY, arg_p: ?*X509_NAME_ENTRY, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_NAME_ENTRY_delete(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY, arg_where: usize) callconv(.c) ?*X509_NAME_ENTRY { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_NAME_ENTRY, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_NAME_ENTRY_delete_ptr(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY, arg_p: ?*const X509_NAME_ENTRY) callconv(.c) ?*X509_NAME_ENTRY { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_NAME_ENTRY, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_NAME_ENTRY_find(arg_sk: ?*const struct_stack_st_X509_NAME_ENTRY, arg_out_index: [*c]usize, arg_p: ?*const X509_NAME_ENTRY) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_NAME_ENTRY_call_cmp_func); -} -pub fn sk_X509_NAME_ENTRY_shift(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY) callconv(.c) ?*X509_NAME_ENTRY { - const sk = arg_sk; - return @as(?*X509_NAME_ENTRY, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_NAME_ENTRY_push(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY, arg_p: ?*X509_NAME_ENTRY) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_NAME_ENTRY_pop(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY) callconv(.c) ?*X509_NAME_ENTRY { - const sk = arg_sk; - return @as(?*X509_NAME_ENTRY, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_NAME_ENTRY_dup(arg_sk: ?*const struct_stack_st_X509_NAME_ENTRY) callconv(.c) ?*struct_stack_st_X509_NAME_ENTRY { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_NAME_ENTRY, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_NAME_ENTRY_sort(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_NAME_ENTRY_call_cmp_func); -} -pub fn sk_X509_NAME_ENTRY_is_sorted(arg_sk: ?*const struct_stack_st_X509_NAME_ENTRY) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_ENTRY_set_cmp_func(arg_sk: ?*struct_stack_st_X509_NAME_ENTRY, arg_comp: sk_X509_NAME_ENTRY_cmp_func) callconv(.c) sk_X509_NAME_ENTRY_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_NAME_ENTRY_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_NAME_ENTRY_deep_copy(arg_sk: ?*const struct_stack_st_X509_NAME_ENTRY, arg_copy_func: sk_X509_NAME_ENTRY_copy_func, arg_free_func: sk_X509_NAME_ENTRY_free_func) callconv(.c) ?*struct_stack_st_X509_NAME_ENTRY { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_NAME_ENTRY, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_NAME_ENTRY_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_NAME_ENTRY_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const struct_stack_st_X509_NAME = opaque {}; -pub const sk_X509_NAME_free_func = ?*const fn (?*X509_NAME) callconv(.c) void; -pub const sk_X509_NAME_copy_func = ?*const fn (?*X509_NAME) callconv(.c) ?*X509_NAME; -pub const sk_X509_NAME_cmp_func = ?*const fn ([*c]?*const X509_NAME, [*c]?*const X509_NAME) callconv(.c) c_int; -pub fn sk_X509_NAME_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_NAME_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_NAME, @ptrCast(ptr))); -} -pub fn sk_X509_NAME_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_NAME_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_NAME, @ptrCast(ptr))))); -} -pub fn sk_X509_NAME_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_NAME = @as(?*const X509_NAME, @ptrCast(a.*)); - var b_ptr: ?*const X509_NAME = @as(?*const X509_NAME, @ptrCast(b.*)); - return @as(sk_X509_NAME_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_NAME_new(arg_comp: sk_X509_NAME_cmp_func) callconv(.c) ?*struct_stack_st_X509_NAME { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_NAME, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_NAME_new_null() callconv(.c) ?*struct_stack_st_X509_NAME { - return @as(?*struct_stack_st_X509_NAME, @ptrCast(sk_new_null())); -} -pub fn sk_X509_NAME_num(arg_sk: ?*const struct_stack_st_X509_NAME) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_zero(arg_sk: ?*struct_stack_st_X509_NAME) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_value(arg_sk: ?*const struct_stack_st_X509_NAME, arg_i: usize) callconv(.c) ?*X509_NAME { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_NAME, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_NAME_set(arg_sk: ?*struct_stack_st_X509_NAME, arg_i: usize, arg_p: ?*X509_NAME) callconv(.c) ?*X509_NAME { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_NAME, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_NAME_free(arg_sk: ?*struct_stack_st_X509_NAME) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_pop_free(arg_sk: ?*struct_stack_st_X509_NAME, arg_free_func: sk_X509_NAME_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_NAME_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_NAME_insert(arg_sk: ?*struct_stack_st_X509_NAME, arg_p: ?*X509_NAME, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_NAME_delete(arg_sk: ?*struct_stack_st_X509_NAME, arg_where: usize) callconv(.c) ?*X509_NAME { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_NAME, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_NAME_delete_ptr(arg_sk: ?*struct_stack_st_X509_NAME, arg_p: ?*const X509_NAME) callconv(.c) ?*X509_NAME { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_NAME, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_NAME_find(arg_sk: ?*const struct_stack_st_X509_NAME, arg_out_index: [*c]usize, arg_p: ?*const X509_NAME) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_NAME_call_cmp_func); -} -pub fn sk_X509_NAME_shift(arg_sk: ?*struct_stack_st_X509_NAME) callconv(.c) ?*X509_NAME { - const sk = arg_sk; - return @as(?*X509_NAME, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_NAME_push(arg_sk: ?*struct_stack_st_X509_NAME, arg_p: ?*X509_NAME) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_NAME_pop(arg_sk: ?*struct_stack_st_X509_NAME) callconv(.c) ?*X509_NAME { - const sk = arg_sk; - return @as(?*X509_NAME, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_NAME_dup(arg_sk: ?*const struct_stack_st_X509_NAME) callconv(.c) ?*struct_stack_st_X509_NAME { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_NAME, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_NAME_sort(arg_sk: ?*struct_stack_st_X509_NAME) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_NAME_call_cmp_func); -} -pub fn sk_X509_NAME_is_sorted(arg_sk: ?*const struct_stack_st_X509_NAME) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_NAME_set_cmp_func(arg_sk: ?*struct_stack_st_X509_NAME, arg_comp: sk_X509_NAME_cmp_func) callconv(.c) sk_X509_NAME_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_NAME_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_NAME_deep_copy(arg_sk: ?*const struct_stack_st_X509_NAME, arg_copy_func: sk_X509_NAME_copy_func, arg_free_func: sk_X509_NAME_free_func) callconv(.c) ?*struct_stack_st_X509_NAME { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_NAME, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_NAME_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_NAME_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern const X509_NAME_it: ASN1_ITEM; -pub extern fn X509_NAME_new() ?*X509_NAME; -pub extern fn X509_NAME_free(name: ?*X509_NAME) void; -pub extern fn d2i_X509_NAME(out: [*c]?*X509_NAME, inp: [*c][*c]const u8, len: c_long) ?*X509_NAME; -pub extern fn i2d_X509_NAME(in: ?*X509_NAME, outp: [*c][*c]u8) c_int; -pub extern fn X509_NAME_dup(name: ?*X509_NAME) ?*X509_NAME; -pub extern fn X509_NAME_get0_der(name: ?*X509_NAME, out_der: [*c][*c]const u8, out_der_len: [*c]usize) c_int; -pub extern fn X509_NAME_set(xn: [*c]?*X509_NAME, name: ?*X509_NAME) c_int; -pub extern fn X509_NAME_entry_count(name: ?*const X509_NAME) c_int; -pub extern fn X509_NAME_get_index_by_NID(name: ?*const X509_NAME, nid: c_int, lastpos: c_int) c_int; -pub extern fn X509_NAME_get_index_by_OBJ(name: ?*const X509_NAME, obj: ?*const ASN1_OBJECT, lastpos: c_int) c_int; -pub extern fn X509_NAME_get_entry(name: ?*const X509_NAME, loc: c_int) ?*X509_NAME_ENTRY; -pub extern fn X509_NAME_delete_entry(name: ?*X509_NAME, loc: c_int) ?*X509_NAME_ENTRY; -pub extern fn X509_NAME_add_entry(name: ?*X509_NAME, entry: ?*const X509_NAME_ENTRY, loc: c_int, set: c_int) c_int; -pub extern fn X509_NAME_add_entry_by_OBJ(name: ?*X509_NAME, obj: ?*const ASN1_OBJECT, @"type": c_int, bytes: [*c]const u8, len: c_int, loc: c_int, set: c_int) c_int; -pub extern fn X509_NAME_add_entry_by_NID(name: ?*X509_NAME, nid: c_int, @"type": c_int, bytes: [*c]const u8, len: c_int, loc: c_int, set: c_int) c_int; -pub extern fn X509_NAME_add_entry_by_txt(name: ?*X509_NAME, field: [*c]const u8, @"type": c_int, bytes: [*c]const u8, len: c_int, loc: c_int, set: c_int) c_int; -pub extern const X509_NAME_ENTRY_it: ASN1_ITEM; -pub extern fn X509_NAME_ENTRY_new() ?*X509_NAME_ENTRY; -pub extern fn X509_NAME_ENTRY_free(entry: ?*X509_NAME_ENTRY) void; -pub extern fn d2i_X509_NAME_ENTRY(out: [*c]?*X509_NAME_ENTRY, inp: [*c][*c]const u8, len: c_long) ?*X509_NAME_ENTRY; -pub extern fn i2d_X509_NAME_ENTRY(in: ?*const X509_NAME_ENTRY, outp: [*c][*c]u8) c_int; -pub extern fn X509_NAME_ENTRY_dup(entry: ?*const X509_NAME_ENTRY) ?*X509_NAME_ENTRY; -pub extern fn X509_NAME_ENTRY_get_object(entry: ?*const X509_NAME_ENTRY) ?*ASN1_OBJECT; -pub extern fn X509_NAME_ENTRY_set_object(entry: ?*X509_NAME_ENTRY, obj: ?*const ASN1_OBJECT) c_int; -pub extern fn X509_NAME_ENTRY_get_data(entry: ?*const X509_NAME_ENTRY) [*c]ASN1_STRING; -pub extern fn X509_NAME_ENTRY_set_data(entry: ?*X509_NAME_ENTRY, @"type": c_int, bytes: [*c]const u8, len: c_int) c_int; -pub extern fn X509_NAME_ENTRY_set(entry: ?*const X509_NAME_ENTRY) c_int; -pub extern fn X509_NAME_ENTRY_create_by_OBJ(out: [*c]?*X509_NAME_ENTRY, obj: ?*const ASN1_OBJECT, @"type": c_int, bytes: [*c]const u8, len: c_int) ?*X509_NAME_ENTRY; -pub extern fn X509_NAME_ENTRY_create_by_NID(out: [*c]?*X509_NAME_ENTRY, nid: c_int, @"type": c_int, bytes: [*c]const u8, len: c_int) ?*X509_NAME_ENTRY; -pub extern fn X509_NAME_ENTRY_create_by_txt(out: [*c]?*X509_NAME_ENTRY, field: [*c]const u8, @"type": c_int, bytes: [*c]const u8, len: c_int) ?*X509_NAME_ENTRY; -pub extern const X509_EXTENSION_it: ASN1_ITEM; -pub extern fn X509_EXTENSION_new() ?*X509_EXTENSION; -pub extern fn X509_EXTENSION_free(ex: ?*X509_EXTENSION) void; -pub extern fn d2i_X509_EXTENSION(out: [*c]?*X509_EXTENSION, inp: [*c][*c]const u8, len: c_long) ?*X509_EXTENSION; -pub extern fn i2d_X509_EXTENSION(alg: ?*const X509_EXTENSION, outp: [*c][*c]u8) c_int; -pub extern fn X509_EXTENSION_dup(ex: ?*const X509_EXTENSION) ?*X509_EXTENSION; -pub extern fn X509_EXTENSION_create_by_NID(ex: [*c]?*X509_EXTENSION, nid: c_int, crit: c_int, data: [*c]const ASN1_OCTET_STRING) ?*X509_EXTENSION; -pub extern fn X509_EXTENSION_create_by_OBJ(ex: [*c]?*X509_EXTENSION, obj: ?*const ASN1_OBJECT, crit: c_int, data: [*c]const ASN1_OCTET_STRING) ?*X509_EXTENSION; -pub extern fn X509_EXTENSION_get_object(ex: ?*const X509_EXTENSION) ?*ASN1_OBJECT; -pub extern fn X509_EXTENSION_get_data(ne: ?*const X509_EXTENSION) [*c]ASN1_OCTET_STRING; -pub extern fn X509_EXTENSION_get_critical(ex: ?*const X509_EXTENSION) c_int; -pub extern fn X509_EXTENSION_set_object(ex: ?*X509_EXTENSION, obj: ?*const ASN1_OBJECT) c_int; -pub extern fn X509_EXTENSION_set_critical(ex: ?*X509_EXTENSION, crit: c_int) c_int; -pub extern fn X509_EXTENSION_set_data(ex: ?*X509_EXTENSION, data: [*c]const ASN1_OCTET_STRING) c_int; -pub const sk_X509_EXTENSION_free_func = ?*const fn (?*X509_EXTENSION) callconv(.c) void; -pub const sk_X509_EXTENSION_copy_func = ?*const fn (?*X509_EXTENSION) callconv(.c) ?*X509_EXTENSION; -pub const sk_X509_EXTENSION_cmp_func = ?*const fn ([*c]?*const X509_EXTENSION, [*c]?*const X509_EXTENSION) callconv(.c) c_int; -pub fn sk_X509_EXTENSION_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_EXTENSION_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_EXTENSION, @ptrCast(ptr))); -} -pub fn sk_X509_EXTENSION_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_EXTENSION_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_EXTENSION, @ptrCast(ptr))))); -} -pub fn sk_X509_EXTENSION_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_EXTENSION = @as(?*const X509_EXTENSION, @ptrCast(a.*)); - var b_ptr: ?*const X509_EXTENSION = @as(?*const X509_EXTENSION, @ptrCast(b.*)); - return @as(sk_X509_EXTENSION_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_EXTENSION_new(arg_comp: sk_X509_EXTENSION_cmp_func) callconv(.c) ?*struct_stack_st_X509_EXTENSION { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_EXTENSION, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_EXTENSION_new_null() callconv(.c) ?*struct_stack_st_X509_EXTENSION { - return @as(?*struct_stack_st_X509_EXTENSION, @ptrCast(sk_new_null())); -} -pub fn sk_X509_EXTENSION_num(arg_sk: ?*const struct_stack_st_X509_EXTENSION) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_EXTENSION_zero(arg_sk: ?*struct_stack_st_X509_EXTENSION) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_EXTENSION_value(arg_sk: ?*const struct_stack_st_X509_EXTENSION, arg_i: usize) callconv(.c) ?*X509_EXTENSION { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_EXTENSION, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_EXTENSION_set(arg_sk: ?*struct_stack_st_X509_EXTENSION, arg_i: usize, arg_p: ?*X509_EXTENSION) callconv(.c) ?*X509_EXTENSION { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_EXTENSION, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_EXTENSION_free(arg_sk: ?*struct_stack_st_X509_EXTENSION) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_EXTENSION_pop_free(arg_sk: ?*struct_stack_st_X509_EXTENSION, arg_free_func: sk_X509_EXTENSION_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_EXTENSION_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_EXTENSION_insert(arg_sk: ?*struct_stack_st_X509_EXTENSION, arg_p: ?*X509_EXTENSION, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_EXTENSION_delete(arg_sk: ?*struct_stack_st_X509_EXTENSION, arg_where: usize) callconv(.c) ?*X509_EXTENSION { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_EXTENSION, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_EXTENSION_delete_ptr(arg_sk: ?*struct_stack_st_X509_EXTENSION, arg_p: ?*const X509_EXTENSION) callconv(.c) ?*X509_EXTENSION { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_EXTENSION, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_EXTENSION_find(arg_sk: ?*const struct_stack_st_X509_EXTENSION, arg_out_index: [*c]usize, arg_p: ?*const X509_EXTENSION) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_EXTENSION_call_cmp_func); -} -pub fn sk_X509_EXTENSION_shift(arg_sk: ?*struct_stack_st_X509_EXTENSION) callconv(.c) ?*X509_EXTENSION { - const sk = arg_sk; - return @as(?*X509_EXTENSION, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_EXTENSION_push(arg_sk: ?*struct_stack_st_X509_EXTENSION, arg_p: ?*X509_EXTENSION) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_EXTENSION_pop(arg_sk: ?*struct_stack_st_X509_EXTENSION) callconv(.c) ?*X509_EXTENSION { - const sk = arg_sk; - return @as(?*X509_EXTENSION, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_EXTENSION_dup(arg_sk: ?*const struct_stack_st_X509_EXTENSION) callconv(.c) ?*struct_stack_st_X509_EXTENSION { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_EXTENSION, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_EXTENSION_sort(arg_sk: ?*struct_stack_st_X509_EXTENSION) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_EXTENSION_call_cmp_func); -} -pub fn sk_X509_EXTENSION_is_sorted(arg_sk: ?*const struct_stack_st_X509_EXTENSION) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_EXTENSION_set_cmp_func(arg_sk: ?*struct_stack_st_X509_EXTENSION, arg_comp: sk_X509_EXTENSION_cmp_func) callconv(.c) sk_X509_EXTENSION_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_EXTENSION_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_EXTENSION_deep_copy(arg_sk: ?*const struct_stack_st_X509_EXTENSION, arg_copy_func: sk_X509_EXTENSION_copy_func, arg_free_func: sk_X509_EXTENSION_free_func) callconv(.c) ?*struct_stack_st_X509_EXTENSION { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_EXTENSION, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_EXTENSION_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_EXTENSION_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const X509_EXTENSIONS = struct_stack_st_X509_EXTENSION; -pub extern const X509_EXTENSIONS_it: ASN1_ITEM; -pub extern fn d2i_X509_EXTENSIONS(out: [*c]?*X509_EXTENSIONS, inp: [*c][*c]const u8, len: c_long) ?*X509_EXTENSIONS; -pub extern fn i2d_X509_EXTENSIONS(alg: ?*const X509_EXTENSIONS, outp: [*c][*c]u8) c_int; -pub extern fn X509v3_get_ext_count(x: ?*const struct_stack_st_X509_EXTENSION) c_int; -pub extern fn X509v3_get_ext_by_NID(x: ?*const struct_stack_st_X509_EXTENSION, nid: c_int, lastpos: c_int) c_int; -pub extern fn X509v3_get_ext_by_OBJ(x: ?*const struct_stack_st_X509_EXTENSION, obj: ?*const ASN1_OBJECT, lastpos: c_int) c_int; -pub extern fn X509v3_get_ext_by_critical(x: ?*const struct_stack_st_X509_EXTENSION, crit: c_int, lastpos: c_int) c_int; -pub extern fn X509v3_get_ext(x: ?*const struct_stack_st_X509_EXTENSION, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509v3_delete_ext(x: ?*struct_stack_st_X509_EXTENSION, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509v3_add_ext(x: [*c]?*struct_stack_st_X509_EXTENSION, ex: ?*const X509_EXTENSION, loc: c_int) ?*struct_stack_st_X509_EXTENSION; -pub const struct_stack_st_X509_ALGOR = opaque {}; -pub const sk_X509_ALGOR_free_func = ?*const fn ([*c]X509_ALGOR) callconv(.c) void; -pub const sk_X509_ALGOR_copy_func = ?*const fn ([*c]X509_ALGOR) callconv(.c) [*c]X509_ALGOR; -pub const sk_X509_ALGOR_cmp_func = ?*const fn ([*c][*c]const X509_ALGOR, [*c][*c]const X509_ALGOR) callconv(.c) c_int; -pub fn sk_X509_ALGOR_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_ALGOR_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]X509_ALGOR, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_X509_ALGOR_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_ALGOR_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]X509_ALGOR, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_X509_ALGOR_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const X509_ALGOR = @as([*c]const X509_ALGOR, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const X509_ALGOR = @as([*c]const X509_ALGOR, @ptrCast(@alignCast(b.*))); - return @as(sk_X509_ALGOR_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_ALGOR_new(arg_comp: sk_X509_ALGOR_cmp_func) callconv(.c) ?*struct_stack_st_X509_ALGOR { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_ALGOR, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_ALGOR_new_null() callconv(.c) ?*struct_stack_st_X509_ALGOR { - return @as(?*struct_stack_st_X509_ALGOR, @ptrCast(sk_new_null())); -} -pub fn sk_X509_ALGOR_num(arg_sk: ?*const struct_stack_st_X509_ALGOR) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ALGOR_zero(arg_sk: ?*struct_stack_st_X509_ALGOR) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ALGOR_value(arg_sk: ?*const struct_stack_st_X509_ALGOR, arg_i: usize) callconv(.c) [*c]X509_ALGOR { - const sk = arg_sk; - const i = arg_i; - return @as([*c]X509_ALGOR, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_X509_ALGOR_set(arg_sk: ?*struct_stack_st_X509_ALGOR, arg_i: usize, arg_p: [*c]X509_ALGOR) callconv(.c) [*c]X509_ALGOR { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]X509_ALGOR, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_X509_ALGOR_free(arg_sk: ?*struct_stack_st_X509_ALGOR) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ALGOR_pop_free(arg_sk: ?*struct_stack_st_X509_ALGOR, arg_free_func: sk_X509_ALGOR_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_ALGOR_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_ALGOR_insert(arg_sk: ?*struct_stack_st_X509_ALGOR, arg_p: [*c]X509_ALGOR, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_ALGOR_delete(arg_sk: ?*struct_stack_st_X509_ALGOR, arg_where: usize) callconv(.c) [*c]X509_ALGOR { - const sk = arg_sk; - const where = arg_where; - return @as([*c]X509_ALGOR, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_X509_ALGOR_delete_ptr(arg_sk: ?*struct_stack_st_X509_ALGOR, arg_p: [*c]const X509_ALGOR) callconv(.c) [*c]X509_ALGOR { - const sk = arg_sk; - const p = arg_p; - return @as([*c]X509_ALGOR, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_X509_ALGOR_find(arg_sk: ?*const struct_stack_st_X509_ALGOR, arg_out_index: [*c]usize, arg_p: [*c]const X509_ALGOR) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_ALGOR_call_cmp_func); -} -pub fn sk_X509_ALGOR_shift(arg_sk: ?*struct_stack_st_X509_ALGOR) callconv(.c) [*c]X509_ALGOR { - const sk = arg_sk; - return @as([*c]X509_ALGOR, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_X509_ALGOR_push(arg_sk: ?*struct_stack_st_X509_ALGOR, arg_p: [*c]X509_ALGOR) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_ALGOR_pop(arg_sk: ?*struct_stack_st_X509_ALGOR) callconv(.c) [*c]X509_ALGOR { - const sk = arg_sk; - return @as([*c]X509_ALGOR, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_X509_ALGOR_dup(arg_sk: ?*const struct_stack_st_X509_ALGOR) callconv(.c) ?*struct_stack_st_X509_ALGOR { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_ALGOR, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_ALGOR_sort(arg_sk: ?*struct_stack_st_X509_ALGOR) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_ALGOR_call_cmp_func); -} -pub fn sk_X509_ALGOR_is_sorted(arg_sk: ?*const struct_stack_st_X509_ALGOR) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ALGOR_set_cmp_func(arg_sk: ?*struct_stack_st_X509_ALGOR, arg_comp: sk_X509_ALGOR_cmp_func) callconv(.c) sk_X509_ALGOR_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_ALGOR_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_ALGOR_deep_copy(arg_sk: ?*const struct_stack_st_X509_ALGOR, arg_copy_func: sk_X509_ALGOR_copy_func, arg_free_func: sk_X509_ALGOR_free_func) callconv(.c) ?*struct_stack_st_X509_ALGOR { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_ALGOR, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_ALGOR_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_ALGOR_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern const X509_ALGOR_it: ASN1_ITEM; -pub extern fn X509_ALGOR_new() [*c]X509_ALGOR; -pub extern fn X509_ALGOR_dup(alg: [*c]const X509_ALGOR) [*c]X509_ALGOR; -pub extern fn X509_ALGOR_free(alg: [*c]X509_ALGOR) void; -pub extern fn d2i_X509_ALGOR(out: [*c][*c]X509_ALGOR, inp: [*c][*c]const u8, len: c_long) [*c]X509_ALGOR; -pub extern fn i2d_X509_ALGOR(alg: [*c]const X509_ALGOR, outp: [*c][*c]u8) c_int; -pub extern fn X509_ALGOR_set0(alg: [*c]X509_ALGOR, obj: ?*ASN1_OBJECT, param_type: c_int, param_value: ?*anyopaque) c_int; -pub extern fn X509_ALGOR_get0(out_obj: [*c]?*const ASN1_OBJECT, out_param_type: [*c]c_int, out_param_value: [*c]?*const anyopaque, alg: [*c]const X509_ALGOR) void; -pub extern fn X509_ALGOR_set_md(alg: [*c]X509_ALGOR, md: ?*const EVP_MD) void; -pub extern fn X509_ALGOR_cmp(a: [*c]const X509_ALGOR, b: [*c]const X509_ALGOR) c_int; -pub extern fn X509_signature_dump(bio: [*c]BIO, sig: [*c]const ASN1_STRING, indent: c_int) c_int; -pub extern fn X509_signature_print(bio: [*c]BIO, alg: [*c]const X509_ALGOR, sig: [*c]const ASN1_STRING) c_int; -pub extern fn X509_pubkey_digest(x509: ?*const X509, md: ?*const EVP_MD, out: [*c]u8, out_len: [*c]c_uint) c_int; -pub extern fn X509_digest(x509: ?*const X509, md: ?*const EVP_MD, out: [*c]u8, out_len: [*c]c_uint) c_int; -pub extern fn X509_CRL_digest(crl: ?*const X509_CRL, md: ?*const EVP_MD, out: [*c]u8, out_len: [*c]c_uint) c_int; -pub extern fn X509_REQ_digest(req: ?*const X509_REQ, md: ?*const EVP_MD, out: [*c]u8, out_len: [*c]c_uint) c_int; -pub extern fn X509_NAME_digest(name: ?*const X509_NAME, md: ?*const EVP_MD, out: [*c]u8, out_len: [*c]c_uint) c_int; -pub extern fn d2i_X509_bio(bp: [*c]BIO, x509: [*c]?*X509) ?*X509; -pub extern fn d2i_X509_CRL_bio(bp: [*c]BIO, crl: [*c]?*X509_CRL) ?*X509_CRL; -pub extern fn d2i_X509_REQ_bio(bp: [*c]BIO, req: [*c]?*X509_REQ) ?*X509_REQ; -pub extern fn d2i_RSAPrivateKey_bio(bp: [*c]BIO, rsa: [*c]?*RSA) ?*RSA; -pub extern fn d2i_RSAPublicKey_bio(bp: [*c]BIO, rsa: [*c]?*RSA) ?*RSA; -pub extern fn d2i_RSA_PUBKEY_bio(bp: [*c]BIO, rsa: [*c]?*RSA) ?*RSA; -pub extern fn d2i_DSA_PUBKEY_bio(bp: [*c]BIO, dsa: [*c][*c]DSA) [*c]DSA; -pub extern fn d2i_DSAPrivateKey_bio(bp: [*c]BIO, dsa: [*c][*c]DSA) [*c]DSA; -pub extern fn d2i_EC_PUBKEY_bio(bp: [*c]BIO, eckey: [*c]?*EC_KEY) ?*EC_KEY; -pub extern fn d2i_ECPrivateKey_bio(bp: [*c]BIO, eckey: [*c]?*EC_KEY) ?*EC_KEY; -pub extern fn d2i_PKCS8_bio(bp: [*c]BIO, p8: [*c]?*X509_SIG) ?*X509_SIG; -pub extern fn d2i_PKCS8_PRIV_KEY_INFO_bio(bp: [*c]BIO, p8inf: [*c]?*PKCS8_PRIV_KEY_INFO) ?*PKCS8_PRIV_KEY_INFO; -pub extern fn d2i_PUBKEY_bio(bp: [*c]BIO, a: [*c][*c]EVP_PKEY) [*c]EVP_PKEY; -pub extern fn d2i_DHparams_bio(bp: [*c]BIO, dh: [*c]?*DH) ?*DH; -pub extern fn d2i_PrivateKey_bio(bp: [*c]BIO, a: [*c][*c]EVP_PKEY) [*c]EVP_PKEY; -pub extern fn i2d_X509_bio(bp: [*c]BIO, x509: ?*X509) c_int; -pub extern fn i2d_X509_CRL_bio(bp: [*c]BIO, crl: ?*X509_CRL) c_int; -pub extern fn i2d_X509_REQ_bio(bp: [*c]BIO, req: ?*X509_REQ) c_int; -pub extern fn i2d_RSAPrivateKey_bio(bp: [*c]BIO, rsa: ?*RSA) c_int; -pub extern fn i2d_RSAPublicKey_bio(bp: [*c]BIO, rsa: ?*RSA) c_int; -pub extern fn i2d_RSA_PUBKEY_bio(bp: [*c]BIO, rsa: ?*RSA) c_int; -pub extern fn i2d_DSA_PUBKEY_bio(bp: [*c]BIO, dsa: [*c]DSA) c_int; -pub extern fn i2d_DSAPrivateKey_bio(bp: [*c]BIO, dsa: [*c]DSA) c_int; -pub extern fn i2d_EC_PUBKEY_bio(bp: [*c]BIO, eckey: ?*EC_KEY) c_int; -pub extern fn i2d_ECPrivateKey_bio(bp: [*c]BIO, eckey: ?*EC_KEY) c_int; -pub extern fn i2d_PKCS8_bio(bp: [*c]BIO, p8: ?*X509_SIG) c_int; -pub extern fn i2d_PKCS8_PRIV_KEY_INFO_bio(bp: [*c]BIO, p8inf: ?*PKCS8_PRIV_KEY_INFO) c_int; -pub extern fn i2d_PrivateKey_bio(bp: [*c]BIO, pkey: [*c]EVP_PKEY) c_int; -pub extern fn i2d_PUBKEY_bio(bp: [*c]BIO, pkey: [*c]EVP_PKEY) c_int; -pub extern fn i2d_DHparams_bio(bp: [*c]BIO, dh: ?*const DH) c_int; -pub extern fn i2d_PKCS8PrivateKeyInfo_bio(bp: [*c]BIO, key: [*c]EVP_PKEY) c_int; -// pub extern fn d2i_X509_fp(fp: [*c]FILE, x509: [*c]?*X509) ?*X509; -// pub extern fn d2i_X509_CRL_fp(fp: [*c]FILE, crl: [*c]?*X509_CRL) ?*X509_CRL; -// pub extern fn d2i_X509_REQ_fp(fp: [*c]FILE, req: [*c]?*X509_REQ) ?*X509_REQ; -// pub extern fn d2i_RSAPrivateKey_fp(fp: [*c]FILE, rsa: [*c]?*RSA) ?*RSA; -// pub extern fn d2i_RSAPublicKey_fp(fp: [*c]FILE, rsa: [*c]?*RSA) ?*RSA; -// pub extern fn d2i_RSA_PUBKEY_fp(fp: [*c]FILE, rsa: [*c]?*RSA) ?*RSA; -// pub extern fn d2i_DSA_PUBKEY_fp(fp: [*c]FILE, dsa: [*c][*c]DSA) [*c]DSA; -// pub extern fn d2i_DSAPrivateKey_fp(fp: [*c]FILE, dsa: [*c][*c]DSA) [*c]DSA; -// pub extern fn d2i_EC_PUBKEY_fp(fp: [*c]FILE, eckey: [*c]?*EC_KEY) ?*EC_KEY; -// pub extern fn d2i_ECPrivateKey_fp(fp: [*c]FILE, eckey: [*c]?*EC_KEY) ?*EC_KEY; -// pub extern fn d2i_PKCS8_fp(fp: [*c]FILE, p8: [*c]?*X509_SIG) ?*X509_SIG; -// pub extern fn d2i_PKCS8_PRIV_KEY_INFO_fp(fp: [*c]FILE, p8inf: [*c]?*PKCS8_PRIV_KEY_INFO) ?*PKCS8_PRIV_KEY_INFO; -// pub extern fn d2i_PrivateKey_fp(fp: [*c]FILE, a: [*c][*c]EVP_PKEY) [*c]EVP_PKEY; -// pub extern fn d2i_PUBKEY_fp(fp: [*c]FILE, a: [*c][*c]EVP_PKEY) [*c]EVP_PKEY; -// pub extern fn i2d_X509_fp(fp: [*c]FILE, x509: ?*X509) c_int; -// pub extern fn i2d_X509_CRL_fp(fp: [*c]FILE, crl: ?*X509_CRL) c_int; -// pub extern fn i2d_X509_REQ_fp(fp: [*c]FILE, req: ?*X509_REQ) c_int; -// pub extern fn i2d_RSAPrivateKey_fp(fp: [*c]FILE, rsa: ?*RSA) c_int; -// pub extern fn i2d_RSAPublicKey_fp(fp: [*c]FILE, rsa: ?*RSA) c_int; -// pub extern fn i2d_RSA_PUBKEY_fp(fp: [*c]FILE, rsa: ?*RSA) c_int; -// pub extern fn i2d_DSA_PUBKEY_fp(fp: [*c]FILE, dsa: [*c]DSA) c_int; -// pub extern fn i2d_DSAPrivateKey_fp(fp: [*c]FILE, dsa: [*c]DSA) c_int; -// pub extern fn i2d_EC_PUBKEY_fp(fp: [*c]FILE, eckey: ?*EC_KEY) c_int; -// pub extern fn i2d_ECPrivateKey_fp(fp: [*c]FILE, eckey: ?*EC_KEY) c_int; -// pub extern fn i2d_PKCS8_fp(fp: [*c]FILE, p8: ?*X509_SIG) c_int; -// pub extern fn i2d_PKCS8_PRIV_KEY_INFO_fp(fp: [*c]FILE, p8inf: ?*PKCS8_PRIV_KEY_INFO) c_int; -// pub extern fn i2d_PKCS8PrivateKeyInfo_fp(fp: [*c]FILE, key: [*c]EVP_PKEY) c_int; -// pub extern fn i2d_PrivateKey_fp(fp: [*c]FILE, pkey: [*c]EVP_PKEY) c_int; -// pub extern fn i2d_PUBKEY_fp(fp: [*c]FILE, pkey: [*c]EVP_PKEY) c_int; -pub extern fn X509_NAME_get_text_by_OBJ(name: ?*const X509_NAME, obj: ?*const ASN1_OBJECT, buf: [*c]u8, len: c_int) c_int; -pub extern fn X509_NAME_get_text_by_NID(name: ?*const X509_NAME, nid: c_int, buf: [*c]u8, len: c_int) c_int; -pub const struct_stack_st_X509_ATTRIBUTE = opaque {}; -pub const sk_X509_ATTRIBUTE_free_func = ?*const fn (?*X509_ATTRIBUTE) callconv(.c) void; -pub const sk_X509_ATTRIBUTE_copy_func = ?*const fn (?*X509_ATTRIBUTE) callconv(.c) ?*X509_ATTRIBUTE; -pub const sk_X509_ATTRIBUTE_cmp_func = ?*const fn ([*c]?*const X509_ATTRIBUTE, [*c]?*const X509_ATTRIBUTE) callconv(.c) c_int; -pub fn sk_X509_ATTRIBUTE_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_ATTRIBUTE_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_ATTRIBUTE, @ptrCast(ptr))); -} -pub fn sk_X509_ATTRIBUTE_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_ATTRIBUTE_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_ATTRIBUTE, @ptrCast(ptr))))); -} -pub fn sk_X509_ATTRIBUTE_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_ATTRIBUTE = @as(?*const X509_ATTRIBUTE, @ptrCast(a.*)); - var b_ptr: ?*const X509_ATTRIBUTE = @as(?*const X509_ATTRIBUTE, @ptrCast(b.*)); - return @as(sk_X509_ATTRIBUTE_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_ATTRIBUTE_new(arg_comp: sk_X509_ATTRIBUTE_cmp_func) callconv(.c) ?*struct_stack_st_X509_ATTRIBUTE { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_ATTRIBUTE, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_ATTRIBUTE_new_null() callconv(.c) ?*struct_stack_st_X509_ATTRIBUTE { - return @as(?*struct_stack_st_X509_ATTRIBUTE, @ptrCast(sk_new_null())); -} -pub fn sk_X509_ATTRIBUTE_num(arg_sk: ?*const struct_stack_st_X509_ATTRIBUTE) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ATTRIBUTE_zero(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ATTRIBUTE_value(arg_sk: ?*const struct_stack_st_X509_ATTRIBUTE, arg_i: usize) callconv(.c) ?*X509_ATTRIBUTE { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_ATTRIBUTE, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_ATTRIBUTE_set(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE, arg_i: usize, arg_p: ?*X509_ATTRIBUTE) callconv(.c) ?*X509_ATTRIBUTE { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_ATTRIBUTE, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_ATTRIBUTE_free(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ATTRIBUTE_pop_free(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE, arg_free_func: sk_X509_ATTRIBUTE_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_ATTRIBUTE_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_ATTRIBUTE_insert(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE, arg_p: ?*X509_ATTRIBUTE, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_ATTRIBUTE_delete(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE, arg_where: usize) callconv(.c) ?*X509_ATTRIBUTE { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_ATTRIBUTE, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_ATTRIBUTE_delete_ptr(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE, arg_p: ?*const X509_ATTRIBUTE) callconv(.c) ?*X509_ATTRIBUTE { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_ATTRIBUTE, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_ATTRIBUTE_find(arg_sk: ?*const struct_stack_st_X509_ATTRIBUTE, arg_out_index: [*c]usize, arg_p: ?*const X509_ATTRIBUTE) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_ATTRIBUTE_call_cmp_func); -} -pub fn sk_X509_ATTRIBUTE_shift(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE) callconv(.c) ?*X509_ATTRIBUTE { - const sk = arg_sk; - return @as(?*X509_ATTRIBUTE, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_ATTRIBUTE_push(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE, arg_p: ?*X509_ATTRIBUTE) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_ATTRIBUTE_pop(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE) callconv(.c) ?*X509_ATTRIBUTE { - const sk = arg_sk; - return @as(?*X509_ATTRIBUTE, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_ATTRIBUTE_dup(arg_sk: ?*const struct_stack_st_X509_ATTRIBUTE) callconv(.c) ?*struct_stack_st_X509_ATTRIBUTE { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_ATTRIBUTE, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_ATTRIBUTE_sort(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_ATTRIBUTE_call_cmp_func); -} -pub fn sk_X509_ATTRIBUTE_is_sorted(arg_sk: ?*const struct_stack_st_X509_ATTRIBUTE) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_ATTRIBUTE_set_cmp_func(arg_sk: ?*struct_stack_st_X509_ATTRIBUTE, arg_comp: sk_X509_ATTRIBUTE_cmp_func) callconv(.c) sk_X509_ATTRIBUTE_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_ATTRIBUTE_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_ATTRIBUTE_deep_copy(arg_sk: ?*const struct_stack_st_X509_ATTRIBUTE, arg_copy_func: sk_X509_ATTRIBUTE_copy_func, arg_free_func: sk_X509_ATTRIBUTE_free_func) callconv(.c) ?*struct_stack_st_X509_ATTRIBUTE { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_ATTRIBUTE, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_ATTRIBUTE_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_ATTRIBUTE_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const struct_stack_st_DIST_POINT = opaque {}; -pub const struct_stack_st_GENERAL_NAME = opaque {}; -pub const struct_stack_st_X509_TRUST = opaque {}; -pub const sk_X509_TRUST_free_func = ?*const fn ([*c]X509_TRUST) callconv(.c) void; -pub const sk_X509_TRUST_copy_func = ?*const fn ([*c]X509_TRUST) callconv(.c) [*c]X509_TRUST; -pub const sk_X509_TRUST_cmp_func = ?*const fn ([*c][*c]const X509_TRUST, [*c][*c]const X509_TRUST) callconv(.c) c_int; -pub fn sk_X509_TRUST_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_TRUST_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]X509_TRUST, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_X509_TRUST_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_TRUST_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]X509_TRUST, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_X509_TRUST_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const X509_TRUST = @as([*c]const X509_TRUST, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const X509_TRUST = @as([*c]const X509_TRUST, @ptrCast(@alignCast(b.*))); - return @as(sk_X509_TRUST_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_TRUST_new(arg_comp: sk_X509_TRUST_cmp_func) callconv(.c) ?*struct_stack_st_X509_TRUST { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_TRUST, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_TRUST_new_null() callconv(.c) ?*struct_stack_st_X509_TRUST { - return @as(?*struct_stack_st_X509_TRUST, @ptrCast(sk_new_null())); -} -pub fn sk_X509_TRUST_num(arg_sk: ?*const struct_stack_st_X509_TRUST) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_TRUST_zero(arg_sk: ?*struct_stack_st_X509_TRUST) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_TRUST_value(arg_sk: ?*const struct_stack_st_X509_TRUST, arg_i: usize) callconv(.c) [*c]X509_TRUST { - const sk = arg_sk; - const i = arg_i; - return @as([*c]X509_TRUST, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_X509_TRUST_set(arg_sk: ?*struct_stack_st_X509_TRUST, arg_i: usize, arg_p: [*c]X509_TRUST) callconv(.c) [*c]X509_TRUST { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]X509_TRUST, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_X509_TRUST_free(arg_sk: ?*struct_stack_st_X509_TRUST) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_TRUST_pop_free(arg_sk: ?*struct_stack_st_X509_TRUST, arg_free_func: sk_X509_TRUST_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_TRUST_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_TRUST_insert(arg_sk: ?*struct_stack_st_X509_TRUST, arg_p: [*c]X509_TRUST, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_TRUST_delete(arg_sk: ?*struct_stack_st_X509_TRUST, arg_where: usize) callconv(.c) [*c]X509_TRUST { - const sk = arg_sk; - const where = arg_where; - return @as([*c]X509_TRUST, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_X509_TRUST_delete_ptr(arg_sk: ?*struct_stack_st_X509_TRUST, arg_p: [*c]const X509_TRUST) callconv(.c) [*c]X509_TRUST { - const sk = arg_sk; - const p = arg_p; - return @as([*c]X509_TRUST, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_X509_TRUST_find(arg_sk: ?*const struct_stack_st_X509_TRUST, arg_out_index: [*c]usize, arg_p: [*c]const X509_TRUST) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_TRUST_call_cmp_func); -} -pub fn sk_X509_TRUST_shift(arg_sk: ?*struct_stack_st_X509_TRUST) callconv(.c) [*c]X509_TRUST { - const sk = arg_sk; - return @as([*c]X509_TRUST, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_X509_TRUST_push(arg_sk: ?*struct_stack_st_X509_TRUST, arg_p: [*c]X509_TRUST) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_TRUST_pop(arg_sk: ?*struct_stack_st_X509_TRUST) callconv(.c) [*c]X509_TRUST { - const sk = arg_sk; - return @as([*c]X509_TRUST, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_X509_TRUST_dup(arg_sk: ?*const struct_stack_st_X509_TRUST) callconv(.c) ?*struct_stack_st_X509_TRUST { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_TRUST, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_TRUST_sort(arg_sk: ?*struct_stack_st_X509_TRUST) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_TRUST_call_cmp_func); -} -pub fn sk_X509_TRUST_is_sorted(arg_sk: ?*const struct_stack_st_X509_TRUST) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_TRUST_set_cmp_func(arg_sk: ?*struct_stack_st_X509_TRUST, arg_comp: sk_X509_TRUST_cmp_func) callconv(.c) sk_X509_TRUST_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_TRUST_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_TRUST_deep_copy(arg_sk: ?*const struct_stack_st_X509_TRUST, arg_copy_func: sk_X509_TRUST_copy_func, arg_free_func: sk_X509_TRUST_free_func) callconv(.c) ?*struct_stack_st_X509_TRUST { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_TRUST, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_TRUST_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_TRUST_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const sk_X509_REVOKED_free_func = ?*const fn (?*X509_REVOKED) callconv(.c) void; -pub const sk_X509_REVOKED_copy_func = ?*const fn (?*X509_REVOKED) callconv(.c) ?*X509_REVOKED; -pub const sk_X509_REVOKED_cmp_func = ?*const fn ([*c]?*const X509_REVOKED, [*c]?*const X509_REVOKED) callconv(.c) c_int; -pub fn sk_X509_REVOKED_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_REVOKED_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_REVOKED, @ptrCast(ptr))); -} -pub fn sk_X509_REVOKED_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_REVOKED_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_REVOKED, @ptrCast(ptr))))); -} -pub fn sk_X509_REVOKED_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_REVOKED = @as(?*const X509_REVOKED, @ptrCast(a.*)); - var b_ptr: ?*const X509_REVOKED = @as(?*const X509_REVOKED, @ptrCast(b.*)); - return @as(sk_X509_REVOKED_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_REVOKED_new(arg_comp: sk_X509_REVOKED_cmp_func) callconv(.c) ?*struct_stack_st_X509_REVOKED { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_REVOKED, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_REVOKED_new_null() callconv(.c) ?*struct_stack_st_X509_REVOKED { - return @as(?*struct_stack_st_X509_REVOKED, @ptrCast(sk_new_null())); -} -pub fn sk_X509_REVOKED_num(arg_sk: ?*const struct_stack_st_X509_REVOKED) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_REVOKED_zero(arg_sk: ?*struct_stack_st_X509_REVOKED) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_REVOKED_value(arg_sk: ?*const struct_stack_st_X509_REVOKED, arg_i: usize) callconv(.c) ?*X509_REVOKED { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_REVOKED, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_REVOKED_set(arg_sk: ?*struct_stack_st_X509_REVOKED, arg_i: usize, arg_p: ?*X509_REVOKED) callconv(.c) ?*X509_REVOKED { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_REVOKED, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_REVOKED_free(arg_sk: ?*struct_stack_st_X509_REVOKED) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_REVOKED_pop_free(arg_sk: ?*struct_stack_st_X509_REVOKED, arg_free_func: sk_X509_REVOKED_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_REVOKED_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_REVOKED_insert(arg_sk: ?*struct_stack_st_X509_REVOKED, arg_p: ?*X509_REVOKED, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_REVOKED_delete(arg_sk: ?*struct_stack_st_X509_REVOKED, arg_where: usize) callconv(.c) ?*X509_REVOKED { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_REVOKED, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_REVOKED_delete_ptr(arg_sk: ?*struct_stack_st_X509_REVOKED, arg_p: ?*const X509_REVOKED) callconv(.c) ?*X509_REVOKED { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_REVOKED, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_REVOKED_find(arg_sk: ?*const struct_stack_st_X509_REVOKED, arg_out_index: [*c]usize, arg_p: ?*const X509_REVOKED) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_REVOKED_call_cmp_func); -} -pub fn sk_X509_REVOKED_shift(arg_sk: ?*struct_stack_st_X509_REVOKED) callconv(.c) ?*X509_REVOKED { - const sk = arg_sk; - return @as(?*X509_REVOKED, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_REVOKED_push(arg_sk: ?*struct_stack_st_X509_REVOKED, arg_p: ?*X509_REVOKED) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_REVOKED_pop(arg_sk: ?*struct_stack_st_X509_REVOKED) callconv(.c) ?*X509_REVOKED { - const sk = arg_sk; - return @as(?*X509_REVOKED, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_REVOKED_dup(arg_sk: ?*const struct_stack_st_X509_REVOKED) callconv(.c) ?*struct_stack_st_X509_REVOKED { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_REVOKED, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_REVOKED_sort(arg_sk: ?*struct_stack_st_X509_REVOKED) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_REVOKED_call_cmp_func); -} -pub fn sk_X509_REVOKED_is_sorted(arg_sk: ?*const struct_stack_st_X509_REVOKED) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_REVOKED_set_cmp_func(arg_sk: ?*struct_stack_st_X509_REVOKED, arg_comp: sk_X509_REVOKED_cmp_func) callconv(.c) sk_X509_REVOKED_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_REVOKED_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_REVOKED_deep_copy(arg_sk: ?*const struct_stack_st_X509_REVOKED, arg_copy_func: sk_X509_REVOKED_copy_func, arg_free_func: sk_X509_REVOKED_free_func) callconv(.c) ?*struct_stack_st_X509_REVOKED { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_REVOKED, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_REVOKED_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_REVOKED_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const struct_stack_st_X509_INFO = opaque {}; -pub const sk_X509_INFO_free_func = ?*const fn ([*c]X509_INFO) callconv(.c) void; -pub const sk_X509_INFO_copy_func = ?*const fn ([*c]X509_INFO) callconv(.c) [*c]X509_INFO; -pub const sk_X509_INFO_cmp_func = ?*const fn ([*c][*c]const X509_INFO, [*c][*c]const X509_INFO) callconv(.c) c_int; -pub fn sk_X509_INFO_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_INFO_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]X509_INFO, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_X509_INFO_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_INFO_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]X509_INFO, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_X509_INFO_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const X509_INFO = @as([*c]const X509_INFO, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const X509_INFO = @as([*c]const X509_INFO, @ptrCast(@alignCast(b.*))); - return @as(sk_X509_INFO_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_INFO_new(arg_comp: sk_X509_INFO_cmp_func) callconv(.c) ?*struct_stack_st_X509_INFO { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_INFO, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_INFO_new_null() callconv(.c) ?*struct_stack_st_X509_INFO { - return @as(?*struct_stack_st_X509_INFO, @ptrCast(sk_new_null())); -} -pub fn sk_X509_INFO_num(arg_sk: ?*const struct_stack_st_X509_INFO) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_INFO_zero(arg_sk: ?*struct_stack_st_X509_INFO) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_INFO_value(arg_sk: ?*const struct_stack_st_X509_INFO, arg_i: usize) callconv(.c) [*c]X509_INFO { - const sk = arg_sk; - const i = arg_i; - return @as([*c]X509_INFO, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_X509_INFO_set(arg_sk: ?*struct_stack_st_X509_INFO, arg_i: usize, arg_p: [*c]X509_INFO) callconv(.c) [*c]X509_INFO { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]X509_INFO, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_X509_INFO_free(arg_sk: ?*struct_stack_st_X509_INFO) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_INFO_pop_free(arg_sk: ?*struct_stack_st_X509_INFO, arg_free_func: sk_X509_INFO_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_INFO_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_INFO_insert(arg_sk: ?*struct_stack_st_X509_INFO, arg_p: [*c]X509_INFO, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_INFO_delete(arg_sk: ?*struct_stack_st_X509_INFO, arg_where: usize) callconv(.c) [*c]X509_INFO { - const sk = arg_sk; - const where = arg_where; - return @as([*c]X509_INFO, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_X509_INFO_delete_ptr(arg_sk: ?*struct_stack_st_X509_INFO, arg_p: [*c]const X509_INFO) callconv(.c) [*c]X509_INFO { - const sk = arg_sk; - const p = arg_p; - return @as([*c]X509_INFO, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_X509_INFO_find(arg_sk: ?*const struct_stack_st_X509_INFO, arg_out_index: [*c]usize, arg_p: [*c]const X509_INFO) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_INFO_call_cmp_func); -} -pub fn sk_X509_INFO_shift(arg_sk: ?*struct_stack_st_X509_INFO) callconv(.c) [*c]X509_INFO { - const sk = arg_sk; - return @as([*c]X509_INFO, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_X509_INFO_push(arg_sk: ?*struct_stack_st_X509_INFO, arg_p: [*c]X509_INFO) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_INFO_pop(arg_sk: ?*struct_stack_st_X509_INFO) callconv(.c) [*c]X509_INFO { - const sk = arg_sk; - return @as([*c]X509_INFO, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_X509_INFO_dup(arg_sk: ?*const struct_stack_st_X509_INFO) callconv(.c) ?*struct_stack_st_X509_INFO { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_INFO, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_INFO_sort(arg_sk: ?*struct_stack_st_X509_INFO) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_INFO_call_cmp_func); -} -pub fn sk_X509_INFO_is_sorted(arg_sk: ?*const struct_stack_st_X509_INFO) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_INFO_set_cmp_func(arg_sk: ?*struct_stack_st_X509_INFO, arg_comp: sk_X509_INFO_cmp_func) callconv(.c) sk_X509_INFO_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_INFO_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_INFO_deep_copy(arg_sk: ?*const struct_stack_st_X509_INFO, arg_copy_func: sk_X509_INFO_copy_func, arg_free_func: sk_X509_INFO_free_func) callconv(.c) ?*struct_stack_st_X509_INFO { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_INFO, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_INFO_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_INFO_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn X509_get_notBefore(x509: ?*const X509) [*c]ASN1_TIME; -pub extern fn X509_get_notAfter(x509: ?*const X509) [*c]ASN1_TIME; -pub extern fn X509_set_notBefore(x509: ?*X509, tm: [*c]const ASN1_TIME) c_int; -pub extern fn X509_set_notAfter(x509: ?*X509, tm: [*c]const ASN1_TIME) c_int; -pub extern fn X509_get_pathlen(x509: ?*X509) c_long; -pub extern fn X509_SIG_get0(sig: ?*const X509_SIG, out_alg: [*c][*c]const X509_ALGOR, out_digest: [*c][*c]const ASN1_OCTET_STRING) void; -pub extern fn X509_SIG_getm(sig: ?*X509_SIG, out_alg: [*c][*c]X509_ALGOR, out_digest: [*c][*c]ASN1_OCTET_STRING) void; -pub extern fn X509_verify_cert_error_string(err: c_long) [*c]const u8; -pub extern fn X509_verify(x509: ?*X509, pkey: [*c]EVP_PKEY) c_int; -pub extern fn X509_REQ_verify(req: ?*X509_REQ, pkey: [*c]EVP_PKEY) c_int; -pub extern fn X509_CRL_verify(crl: ?*X509_CRL, pkey: [*c]EVP_PKEY) c_int; -pub extern fn NETSCAPE_SPKI_verify(spki: [*c]NETSCAPE_SPKI, pkey: [*c]EVP_PKEY) c_int; -pub extern fn NETSCAPE_SPKI_b64_decode(str: [*c]const u8, len: c_int) [*c]NETSCAPE_SPKI; -pub extern fn NETSCAPE_SPKI_b64_encode(spki: [*c]NETSCAPE_SPKI) [*c]u8; -pub extern fn NETSCAPE_SPKI_get_pubkey(spki: [*c]NETSCAPE_SPKI) [*c]EVP_PKEY; -pub extern fn NETSCAPE_SPKI_set_pubkey(spki: [*c]NETSCAPE_SPKI, pkey: [*c]EVP_PKEY) c_int; -pub extern fn NETSCAPE_SPKI_sign(spki: [*c]NETSCAPE_SPKI, pkey: [*c]EVP_PKEY, md: ?*const EVP_MD) c_int; -pub extern fn X509_ATTRIBUTE_dup(xa: ?*const X509_ATTRIBUTE) ?*X509_ATTRIBUTE; -pub extern fn X509_REVOKED_dup(rev: ?*const X509_REVOKED) ?*X509_REVOKED; -pub extern fn X509_cmp_time(s: [*c]const ASN1_TIME, t: [*c]time_t) c_int; -pub extern fn X509_cmp_current_time(s: [*c]const ASN1_TIME) c_int; -pub extern fn X509_time_adj(s: [*c]ASN1_TIME, offset_sec: c_long, t: [*c]time_t) [*c]ASN1_TIME; -pub extern fn X509_time_adj_ex(s: [*c]ASN1_TIME, offset_day: c_int, offset_sec: c_long, t: [*c]time_t) [*c]ASN1_TIME; -pub extern fn X509_gmtime_adj(s: [*c]ASN1_TIME, offset_sec: c_long) [*c]ASN1_TIME; -pub extern fn X509_get_default_cert_area() [*c]const u8; -pub extern fn X509_get_default_cert_dir() [*c]const u8; -// pub extern fn X509_get_default_cert_file() [*c]const u8; -pub extern fn X509_get_default_cert_dir_env() [*c]const u8; -// pub extern fn X509_get_default_cert_file_env() [*c]const u8; -pub extern fn X509_get_default_private_dir() [*c]const u8; -pub extern fn X509_PUBKEY_new() ?*X509_PUBKEY; -pub extern fn X509_PUBKEY_free(a: ?*X509_PUBKEY) void; -pub extern fn d2i_X509_PUBKEY(a: [*c]?*X509_PUBKEY, in: [*c][*c]const u8, len: c_long) ?*X509_PUBKEY; -pub extern fn i2d_X509_PUBKEY(a: ?*const X509_PUBKEY, out: [*c][*c]u8) c_int; -pub extern const X509_PUBKEY_it: ASN1_ITEM; -pub extern fn X509_PUBKEY_set(x: [*c]?*X509_PUBKEY, pkey: [*c]EVP_PKEY) c_int; -pub extern fn X509_PUBKEY_get(key: ?*X509_PUBKEY) [*c]EVP_PKEY; -pub extern fn X509_SIG_new() ?*X509_SIG; -pub extern fn X509_SIG_free(a: ?*X509_SIG) void; -pub extern fn d2i_X509_SIG(a: [*c]?*X509_SIG, in: [*c][*c]const u8, len: c_long) ?*X509_SIG; -pub extern fn i2d_X509_SIG(a: ?*const X509_SIG, out: [*c][*c]u8) c_int; -pub extern const X509_SIG_it: ASN1_ITEM; -pub extern fn X509_ATTRIBUTE_new() ?*X509_ATTRIBUTE; -pub extern fn X509_ATTRIBUTE_free(a: ?*X509_ATTRIBUTE) void; -pub extern fn d2i_X509_ATTRIBUTE(a: [*c]?*X509_ATTRIBUTE, in: [*c][*c]const u8, len: c_long) ?*X509_ATTRIBUTE; -pub extern fn i2d_X509_ATTRIBUTE(a: ?*const X509_ATTRIBUTE, out: [*c][*c]u8) c_int; -pub extern const X509_ATTRIBUTE_it: ASN1_ITEM; -pub extern fn X509_ATTRIBUTE_create(nid: c_int, attrtype: c_int, value: ?*anyopaque) ?*X509_ATTRIBUTE; -pub extern fn X509_add1_trust_object(x: ?*X509, obj: ?*ASN1_OBJECT) c_int; -pub extern fn X509_add1_reject_object(x: ?*X509, obj: ?*ASN1_OBJECT) c_int; -pub extern fn X509_trust_clear(x: ?*X509) void; -pub extern fn X509_reject_clear(x: ?*X509) void; -pub extern fn X509_TRUST_set(t: [*c]c_int, trust: c_int) c_int; -pub extern fn X509_REVOKED_new() ?*X509_REVOKED; -pub extern fn X509_REVOKED_free(a: ?*X509_REVOKED) void; -pub extern fn d2i_X509_REVOKED(a: [*c]?*X509_REVOKED, in: [*c][*c]const u8, len: c_long) ?*X509_REVOKED; -pub extern fn i2d_X509_REVOKED(a: ?*const X509_REVOKED, out: [*c][*c]u8) c_int; -pub extern const X509_REVOKED_it: ASN1_ITEM; -pub extern fn X509_CRL_add0_revoked(crl: ?*X509_CRL, rev: ?*X509_REVOKED) c_int; -pub extern fn X509_CRL_get0_by_serial(crl: ?*X509_CRL, ret: [*c]?*X509_REVOKED, serial: [*c]ASN1_INTEGER) c_int; -pub extern fn X509_CRL_get0_by_cert(crl: ?*X509_CRL, ret: [*c]?*X509_REVOKED, x: ?*X509) c_int; -pub extern fn X509_PKEY_new() [*c]X509_PKEY; -pub extern fn X509_PKEY_free(a: [*c]X509_PKEY) void; -pub extern fn NETSCAPE_SPKI_new() [*c]NETSCAPE_SPKI; -pub extern fn NETSCAPE_SPKI_free(a: [*c]NETSCAPE_SPKI) void; -pub extern fn d2i_NETSCAPE_SPKI(a: [*c][*c]NETSCAPE_SPKI, in: [*c][*c]const u8, len: c_long) [*c]NETSCAPE_SPKI; -pub extern fn i2d_NETSCAPE_SPKI(a: [*c]const NETSCAPE_SPKI, out: [*c][*c]u8) c_int; -pub extern const NETSCAPE_SPKI_it: ASN1_ITEM; -pub extern fn NETSCAPE_SPKAC_new() [*c]NETSCAPE_SPKAC; -pub extern fn NETSCAPE_SPKAC_free(a: [*c]NETSCAPE_SPKAC) void; -pub extern fn d2i_NETSCAPE_SPKAC(a: [*c][*c]NETSCAPE_SPKAC, in: [*c][*c]const u8, len: c_long) [*c]NETSCAPE_SPKAC; -pub extern fn i2d_NETSCAPE_SPKAC(a: [*c]const NETSCAPE_SPKAC, out: [*c][*c]u8) c_int; -pub extern const NETSCAPE_SPKAC_it: ASN1_ITEM; -pub extern fn X509_INFO_new() [*c]X509_INFO; -pub extern fn X509_INFO_free(a: [*c]X509_INFO) void; -pub extern fn X509_NAME_oneline(a: ?*const X509_NAME, buf: [*c]u8, size: c_int) [*c]u8; -pub extern fn ASN1_digest(i2d: ?*const i2d_of_void, @"type": ?*const EVP_MD, data: [*c]u8, md: [*c]u8, len: [*c]c_uint) c_int; -pub extern fn ASN1_item_digest(it: ?*const ASN1_ITEM, @"type": ?*const EVP_MD, data: ?*anyopaque, md: [*c]u8, len: [*c]c_uint) c_int; -pub extern fn ASN1_item_verify(it: ?*const ASN1_ITEM, algor1: [*c]const X509_ALGOR, signature: [*c]const ASN1_BIT_STRING, data: ?*anyopaque, pkey: [*c]EVP_PKEY) c_int; -pub extern fn ASN1_item_sign(it: ?*const ASN1_ITEM, algor1: [*c]X509_ALGOR, algor2: [*c]X509_ALGOR, signature: [*c]ASN1_BIT_STRING, data: ?*anyopaque, pkey: [*c]EVP_PKEY, @"type": ?*const EVP_MD) c_int; -pub extern fn ASN1_item_sign_ctx(it: ?*const ASN1_ITEM, algor1: [*c]X509_ALGOR, algor2: [*c]X509_ALGOR, signature: [*c]ASN1_BIT_STRING, asn: ?*anyopaque, ctx: [*c]EVP_MD_CTX) c_int; -pub extern fn X509_REQ_extension_nid(nid: c_int) c_int; -pub extern fn X509_REQ_get_extensions(req: ?*X509_REQ) ?*struct_stack_st_X509_EXTENSION; -pub extern fn X509_REQ_add_extensions_nid(req: ?*X509_REQ, exts: ?*const struct_stack_st_X509_EXTENSION, nid: c_int) c_int; -pub extern fn X509_REQ_add_extensions(req: ?*X509_REQ, exts: ?*const struct_stack_st_X509_EXTENSION) c_int; -pub extern fn X509_REQ_get_attr_count(req: ?*const X509_REQ) c_int; -pub extern fn X509_REQ_get_attr_by_NID(req: ?*const X509_REQ, nid: c_int, lastpos: c_int) c_int; -pub extern fn X509_REQ_get_attr_by_OBJ(req: ?*const X509_REQ, obj: ?*const ASN1_OBJECT, lastpos: c_int) c_int; -pub extern fn X509_REQ_get_attr(req: ?*const X509_REQ, loc: c_int) ?*X509_ATTRIBUTE; -pub extern fn X509_REQ_delete_attr(req: ?*X509_REQ, loc: c_int) ?*X509_ATTRIBUTE; -pub extern fn X509_REQ_add1_attr(req: ?*X509_REQ, attr: ?*X509_ATTRIBUTE) c_int; -pub extern fn X509_REQ_add1_attr_by_OBJ(req: ?*X509_REQ, obj: ?*const ASN1_OBJECT, attrtype: c_int, data: [*c]const u8, len: c_int) c_int; -pub extern fn X509_REQ_add1_attr_by_NID(req: ?*X509_REQ, nid: c_int, attrtype: c_int, data: [*c]const u8, len: c_int) c_int; -pub extern fn X509_REQ_add1_attr_by_txt(req: ?*X509_REQ, attrname: [*c]const u8, attrtype: c_int, data: [*c]const u8, len: c_int) c_int; -pub extern fn X509_CRL_sort(crl: ?*X509_CRL) c_int; -pub extern fn X509_REVOKED_get0_serialNumber(revoked: ?*const X509_REVOKED) [*c]const ASN1_INTEGER; -pub extern fn X509_REVOKED_set_serialNumber(revoked: ?*X509_REVOKED, serial: [*c]const ASN1_INTEGER) c_int; -pub extern fn X509_REVOKED_get0_revocationDate(revoked: ?*const X509_REVOKED) [*c]const ASN1_TIME; -pub extern fn X509_REVOKED_set_revocationDate(revoked: ?*X509_REVOKED, tm: [*c]const ASN1_TIME) c_int; -pub extern fn X509_REVOKED_get0_extensions(r: ?*const X509_REVOKED) ?*const struct_stack_st_X509_EXTENSION; -pub extern fn X509_CRL_diff(base: ?*X509_CRL, newer: ?*X509_CRL, skey: [*c]EVP_PKEY, md: ?*const EVP_MD, flags: c_uint) ?*X509_CRL; -pub extern fn X509_REQ_check_private_key(x509: ?*X509_REQ, pkey: [*c]EVP_PKEY) c_int; -pub extern fn X509_check_private_key(x509: ?*X509, pkey: [*c]const EVP_PKEY) c_int; -pub extern fn X509_issuer_name_cmp(a: ?*const X509, b: ?*const X509) c_int; -pub extern fn X509_issuer_name_hash(a: ?*X509) c_ulong; -pub extern fn X509_subject_name_cmp(a: ?*const X509, b: ?*const X509) c_int; -pub extern fn X509_subject_name_hash(x: ?*X509) c_ulong; -pub extern fn X509_issuer_name_hash_old(a: ?*X509) c_ulong; -pub extern fn X509_subject_name_hash_old(x: ?*X509) c_ulong; -pub extern fn X509_cmp(a: ?*const X509, b: ?*const X509) c_int; -pub extern fn X509_NAME_cmp(a: ?*const X509_NAME, b: ?*const X509_NAME) c_int; -pub extern fn X509_NAME_hash(x: ?*X509_NAME) c_ulong; -pub extern fn X509_NAME_hash_old(x: ?*X509_NAME) c_ulong; -pub extern fn X509_CRL_cmp(a: ?*const X509_CRL, b: ?*const X509_CRL) c_int; -pub extern fn X509_CRL_match(a: ?*const X509_CRL, b: ?*const X509_CRL) c_int; -// pub extern fn X509_print_ex_fp(bp: [*c]FILE, x: ?*X509, nmflag: c_ulong, cflag: c_ulong) c_int; -// pub extern fn X509_print_fp(bp: [*c]FILE, x: ?*X509) c_int; -// pub extern fn X509_CRL_print_fp(bp: [*c]FILE, x: ?*X509_CRL) c_int; -// pub extern fn X509_REQ_print_fp(bp: [*c]FILE, req: ?*X509_REQ) c_int; -// pub extern fn X509_NAME_print_ex_fp(fp: [*c]FILE, nm: ?*const X509_NAME, indent: c_int, flags: c_ulong) c_int; -pub extern fn X509_NAME_print(bp: [*c]BIO, name: ?*const X509_NAME, obase: c_int) c_int; -pub extern fn X509_NAME_print_ex(out: [*c]BIO, nm: ?*const X509_NAME, indent: c_int, flags: c_ulong) c_int; -pub extern fn X509_print_ex(bp: [*c]BIO, x: ?*X509, nmflag: c_ulong, cflag: c_ulong) c_int; -pub extern fn X509_print(bp: [*c]BIO, x: ?*X509) c_int; -pub extern fn X509_CRL_print(bp: [*c]BIO, x: ?*X509_CRL) c_int; -pub extern fn X509_REQ_print_ex(bp: [*c]BIO, x: ?*X509_REQ, nmflag: c_ulong, cflag: c_ulong) c_int; -pub extern fn X509_REQ_print(bp: [*c]BIO, req: ?*X509_REQ) c_int; -pub extern fn X509_get_ext_d2i(x509: ?*const X509, nid: c_int, out_critical: [*c]c_int, out_idx: [*c]c_int) ?*anyopaque; -pub extern fn X509_add1_ext_i2d(x: ?*X509, nid: c_int, value: ?*anyopaque, crit: c_int, flags: c_ulong) c_int; -pub extern fn X509_CRL_get_ext_d2i(crl: ?*const X509_CRL, nid: c_int, out_critical: [*c]c_int, out_idx: [*c]c_int) ?*anyopaque; -pub extern fn X509_CRL_add1_ext_i2d(x: ?*X509_CRL, nid: c_int, value: ?*anyopaque, crit: c_int, flags: c_ulong) c_int; -pub extern fn X509_REVOKED_get_ext_count(x: ?*const X509_REVOKED) c_int; -pub extern fn X509_REVOKED_get_ext_by_NID(x: ?*const X509_REVOKED, nid: c_int, lastpos: c_int) c_int; -pub extern fn X509_REVOKED_get_ext_by_OBJ(x: ?*const X509_REVOKED, obj: ?*const ASN1_OBJECT, lastpos: c_int) c_int; -pub extern fn X509_REVOKED_get_ext_by_critical(x: ?*const X509_REVOKED, crit: c_int, lastpos: c_int) c_int; -pub extern fn X509_REVOKED_get_ext(x: ?*const X509_REVOKED, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509_REVOKED_delete_ext(x: ?*X509_REVOKED, loc: c_int) ?*X509_EXTENSION; -pub extern fn X509_REVOKED_add_ext(x: ?*X509_REVOKED, ex: ?*const X509_EXTENSION, loc: c_int) c_int; -pub extern fn X509_REVOKED_get_ext_d2i(revoked: ?*const X509_REVOKED, nid: c_int, out_critical: [*c]c_int, out_idx: [*c]c_int) ?*anyopaque; -pub extern fn X509_REVOKED_add1_ext_i2d(x: ?*X509_REVOKED, nid: c_int, value: ?*anyopaque, crit: c_int, flags: c_ulong) c_int; -pub extern fn X509at_get_attr_count(x: ?*const struct_stack_st_X509_ATTRIBUTE) c_int; -pub extern fn X509at_get_attr_by_NID(x: ?*const struct_stack_st_X509_ATTRIBUTE, nid: c_int, lastpos: c_int) c_int; -pub extern fn X509at_get_attr_by_OBJ(sk: ?*const struct_stack_st_X509_ATTRIBUTE, obj: ?*const ASN1_OBJECT, lastpos: c_int) c_int; -pub extern fn X509at_get_attr(x: ?*const struct_stack_st_X509_ATTRIBUTE, loc: c_int) ?*X509_ATTRIBUTE; -pub extern fn X509at_delete_attr(x: ?*struct_stack_st_X509_ATTRIBUTE, loc: c_int) ?*X509_ATTRIBUTE; -pub extern fn X509at_add1_attr(x: [*c]?*struct_stack_st_X509_ATTRIBUTE, attr: ?*X509_ATTRIBUTE) ?*struct_stack_st_X509_ATTRIBUTE; -pub extern fn X509at_add1_attr_by_OBJ(x: [*c]?*struct_stack_st_X509_ATTRIBUTE, obj: ?*const ASN1_OBJECT, @"type": c_int, bytes: [*c]const u8, len: c_int) ?*struct_stack_st_X509_ATTRIBUTE; -pub extern fn X509at_add1_attr_by_NID(x: [*c]?*struct_stack_st_X509_ATTRIBUTE, nid: c_int, @"type": c_int, bytes: [*c]const u8, len: c_int) ?*struct_stack_st_X509_ATTRIBUTE; -pub extern fn X509at_add1_attr_by_txt(x: [*c]?*struct_stack_st_X509_ATTRIBUTE, attrname: [*c]const u8, @"type": c_int, bytes: [*c]const u8, len: c_int) ?*struct_stack_st_X509_ATTRIBUTE; -pub extern fn X509_ATTRIBUTE_create_by_NID(attr: [*c]?*X509_ATTRIBUTE, nid: c_int, attrtype: c_int, data: ?*const anyopaque, len: c_int) ?*X509_ATTRIBUTE; -pub extern fn X509_ATTRIBUTE_create_by_OBJ(attr: [*c]?*X509_ATTRIBUTE, obj: ?*const ASN1_OBJECT, attrtype: c_int, data: ?*const anyopaque, len: c_int) ?*X509_ATTRIBUTE; -pub extern fn X509_ATTRIBUTE_create_by_txt(attr: [*c]?*X509_ATTRIBUTE, attrname: [*c]const u8, @"type": c_int, bytes: [*c]const u8, len: c_int) ?*X509_ATTRIBUTE; -pub extern fn X509_ATTRIBUTE_set1_object(attr: ?*X509_ATTRIBUTE, obj: ?*const ASN1_OBJECT) c_int; -pub extern fn X509_ATTRIBUTE_set1_data(attr: ?*X509_ATTRIBUTE, attrtype: c_int, data: ?*const anyopaque, len: c_int) c_int; -pub extern fn X509_ATTRIBUTE_get0_data(attr: ?*X509_ATTRIBUTE, idx: c_int, attrtype: c_int, unused: ?*anyopaque) ?*anyopaque; -pub extern fn X509_ATTRIBUTE_count(attr: ?*const X509_ATTRIBUTE) c_int; -pub extern fn X509_ATTRIBUTE_get0_object(attr: ?*X509_ATTRIBUTE) ?*ASN1_OBJECT; -pub extern fn X509_ATTRIBUTE_get0_type(attr: ?*X509_ATTRIBUTE, idx: c_int) [*c]ASN1_TYPE; -pub extern fn X509_verify_cert(ctx: ?*X509_STORE_CTX) c_int; -pub extern fn PKCS8_PRIV_KEY_INFO_new() ?*PKCS8_PRIV_KEY_INFO; -pub extern fn PKCS8_PRIV_KEY_INFO_free(a: ?*PKCS8_PRIV_KEY_INFO) void; -pub extern fn d2i_PKCS8_PRIV_KEY_INFO(a: [*c]?*PKCS8_PRIV_KEY_INFO, in: [*c][*c]const u8, len: c_long) ?*PKCS8_PRIV_KEY_INFO; -pub extern fn i2d_PKCS8_PRIV_KEY_INFO(a: ?*const PKCS8_PRIV_KEY_INFO, out: [*c][*c]u8) c_int; -pub extern const PKCS8_PRIV_KEY_INFO_it: ASN1_ITEM; -pub extern fn EVP_PKCS82PKEY(p8: ?*const PKCS8_PRIV_KEY_INFO) [*c]EVP_PKEY; -pub extern fn EVP_PKEY2PKCS8(pkey: [*c]const EVP_PKEY) ?*PKCS8_PRIV_KEY_INFO; -pub extern fn X509_PUBKEY_set0_param(@"pub": ?*X509_PUBKEY, obj: ?*ASN1_OBJECT, param_type: c_int, param_value: ?*anyopaque, key: [*c]u8, key_len: c_int) c_int; -pub extern fn X509_PUBKEY_get0_param(out_obj: [*c]?*ASN1_OBJECT, out_key: [*c][*c]const u8, out_key_len: [*c]c_int, out_alg: [*c][*c]X509_ALGOR, @"pub": ?*X509_PUBKEY) c_int; -pub extern fn X509_PUBKEY_get0_public_key(@"pub": ?*const X509_PUBKEY) [*c]const ASN1_BIT_STRING; -pub extern fn X509_check_trust(x: ?*X509, id: c_int, flags: c_int) c_int; -pub extern fn X509_TRUST_get_count() c_int; -pub extern fn X509_TRUST_get0(idx: c_int) [*c]X509_TRUST; -pub extern fn X509_TRUST_get_by_id(id: c_int) c_int; -pub extern fn X509_TRUST_add(id: c_int, flags: c_int, ck: ?*const fn ([*c]X509_TRUST, ?*X509, c_int) callconv(.c) c_int, name: [*c]u8, arg1: c_int, arg2: ?*anyopaque) c_int; -pub extern fn X509_TRUST_cleanup() void; -pub extern fn X509_TRUST_get_flags(xp: [*c]const X509_TRUST) c_int; -pub extern fn X509_TRUST_get0_name(xp: [*c]const X509_TRUST) [*c]u8; -pub extern fn X509_TRUST_get_trust(xp: [*c]const X509_TRUST) c_int; -pub extern fn RSA_PSS_PARAMS_new() [*c]RSA_PSS_PARAMS; -pub extern fn RSA_PSS_PARAMS_free(a: [*c]RSA_PSS_PARAMS) void; -pub extern fn d2i_RSA_PSS_PARAMS(a: [*c][*c]RSA_PSS_PARAMS, in: [*c][*c]const u8, len: c_long) [*c]RSA_PSS_PARAMS; -pub extern fn i2d_RSA_PSS_PARAMS(a: [*c]const RSA_PSS_PARAMS, out: [*c][*c]u8) c_int; -pub extern const RSA_PSS_PARAMS_it: ASN1_ITEM; -pub const struct_stack_st_X509_LOOKUP = opaque {}; -pub const sk_X509_LOOKUP_free_func = ?*const fn (?*X509_LOOKUP) callconv(.c) void; -pub const sk_X509_LOOKUP_copy_func = ?*const fn (?*X509_LOOKUP) callconv(.c) ?*X509_LOOKUP; -pub const sk_X509_LOOKUP_cmp_func = ?*const fn ([*c]?*const X509_LOOKUP, [*c]?*const X509_LOOKUP) callconv(.c) c_int; -pub fn sk_X509_LOOKUP_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_LOOKUP_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_LOOKUP, @ptrCast(ptr))); -} -pub fn sk_X509_LOOKUP_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_LOOKUP_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_LOOKUP, @ptrCast(ptr))))); -} -pub fn sk_X509_LOOKUP_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_LOOKUP = @as(?*const X509_LOOKUP, @ptrCast(a.*)); - var b_ptr: ?*const X509_LOOKUP = @as(?*const X509_LOOKUP, @ptrCast(b.*)); - return @as(sk_X509_LOOKUP_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_LOOKUP_new(arg_comp: sk_X509_LOOKUP_cmp_func) callconv(.c) ?*struct_stack_st_X509_LOOKUP { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_LOOKUP, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_LOOKUP_new_null() callconv(.c) ?*struct_stack_st_X509_LOOKUP { - return @as(?*struct_stack_st_X509_LOOKUP, @ptrCast(sk_new_null())); -} -pub fn sk_X509_LOOKUP_num(arg_sk: ?*const struct_stack_st_X509_LOOKUP) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_LOOKUP_zero(arg_sk: ?*struct_stack_st_X509_LOOKUP) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_LOOKUP_value(arg_sk: ?*const struct_stack_st_X509_LOOKUP, arg_i: usize) callconv(.c) ?*X509_LOOKUP { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_LOOKUP, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_LOOKUP_set(arg_sk: ?*struct_stack_st_X509_LOOKUP, arg_i: usize, arg_p: ?*X509_LOOKUP) callconv(.c) ?*X509_LOOKUP { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_LOOKUP, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_LOOKUP_free(arg_sk: ?*struct_stack_st_X509_LOOKUP) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_LOOKUP_pop_free(arg_sk: ?*struct_stack_st_X509_LOOKUP, arg_free_func: sk_X509_LOOKUP_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_LOOKUP_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_LOOKUP_insert(arg_sk: ?*struct_stack_st_X509_LOOKUP, arg_p: ?*X509_LOOKUP, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_LOOKUP_delete(arg_sk: ?*struct_stack_st_X509_LOOKUP, arg_where: usize) callconv(.c) ?*X509_LOOKUP { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_LOOKUP, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_LOOKUP_delete_ptr(arg_sk: ?*struct_stack_st_X509_LOOKUP, arg_p: ?*const X509_LOOKUP) callconv(.c) ?*X509_LOOKUP { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_LOOKUP, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_LOOKUP_find(arg_sk: ?*const struct_stack_st_X509_LOOKUP, arg_out_index: [*c]usize, arg_p: ?*const X509_LOOKUP) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_LOOKUP_call_cmp_func); -} -pub fn sk_X509_LOOKUP_shift(arg_sk: ?*struct_stack_st_X509_LOOKUP) callconv(.c) ?*X509_LOOKUP { - const sk = arg_sk; - return @as(?*X509_LOOKUP, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_LOOKUP_push(arg_sk: ?*struct_stack_st_X509_LOOKUP, arg_p: ?*X509_LOOKUP) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_LOOKUP_pop(arg_sk: ?*struct_stack_st_X509_LOOKUP) callconv(.c) ?*X509_LOOKUP { - const sk = arg_sk; - return @as(?*X509_LOOKUP, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_LOOKUP_dup(arg_sk: ?*const struct_stack_st_X509_LOOKUP) callconv(.c) ?*struct_stack_st_X509_LOOKUP { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_LOOKUP, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_LOOKUP_sort(arg_sk: ?*struct_stack_st_X509_LOOKUP) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_LOOKUP_call_cmp_func); -} -pub fn sk_X509_LOOKUP_is_sorted(arg_sk: ?*const struct_stack_st_X509_LOOKUP) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_LOOKUP_set_cmp_func(arg_sk: ?*struct_stack_st_X509_LOOKUP, arg_comp: sk_X509_LOOKUP_cmp_func) callconv(.c) sk_X509_LOOKUP_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_LOOKUP_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_LOOKUP_deep_copy(arg_sk: ?*const struct_stack_st_X509_LOOKUP, arg_copy_func: sk_X509_LOOKUP_copy_func, arg_free_func: sk_X509_LOOKUP_free_func) callconv(.c) ?*struct_stack_st_X509_LOOKUP { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_LOOKUP, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_LOOKUP_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_LOOKUP_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const struct_stack_st_X509_OBJECT = opaque {}; -pub const sk_X509_OBJECT_free_func = ?*const fn (?*X509_OBJECT) callconv(.c) void; -pub const sk_X509_OBJECT_copy_func = ?*const fn (?*X509_OBJECT) callconv(.c) ?*X509_OBJECT; -pub const sk_X509_OBJECT_cmp_func = ?*const fn ([*c]?*const X509_OBJECT, [*c]?*const X509_OBJECT) callconv(.c) c_int; -pub fn sk_X509_OBJECT_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_OBJECT_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_OBJECT, @ptrCast(ptr))); -} -pub fn sk_X509_OBJECT_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_OBJECT_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_OBJECT, @ptrCast(ptr))))); -} -pub fn sk_X509_OBJECT_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_OBJECT = @as(?*const X509_OBJECT, @ptrCast(a.*)); - var b_ptr: ?*const X509_OBJECT = @as(?*const X509_OBJECT, @ptrCast(b.*)); - return @as(sk_X509_OBJECT_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_OBJECT_new(arg_comp: sk_X509_OBJECT_cmp_func) callconv(.c) ?*struct_stack_st_X509_OBJECT { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_OBJECT, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_OBJECT_new_null() callconv(.c) ?*struct_stack_st_X509_OBJECT { - return @as(?*struct_stack_st_X509_OBJECT, @ptrCast(sk_new_null())); -} -pub fn sk_X509_OBJECT_num(arg_sk: ?*const struct_stack_st_X509_OBJECT) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_OBJECT_zero(arg_sk: ?*struct_stack_st_X509_OBJECT) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_OBJECT_value(arg_sk: ?*const struct_stack_st_X509_OBJECT, arg_i: usize) callconv(.c) ?*X509_OBJECT { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_OBJECT, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_OBJECT_set(arg_sk: ?*struct_stack_st_X509_OBJECT, arg_i: usize, arg_p: ?*X509_OBJECT) callconv(.c) ?*X509_OBJECT { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_OBJECT, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_OBJECT_free(arg_sk: ?*struct_stack_st_X509_OBJECT) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_OBJECT_pop_free(arg_sk: ?*struct_stack_st_X509_OBJECT, arg_free_func: sk_X509_OBJECT_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_OBJECT_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_OBJECT_insert(arg_sk: ?*struct_stack_st_X509_OBJECT, arg_p: ?*X509_OBJECT, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_OBJECT_delete(arg_sk: ?*struct_stack_st_X509_OBJECT, arg_where: usize) callconv(.c) ?*X509_OBJECT { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_OBJECT, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_OBJECT_delete_ptr(arg_sk: ?*struct_stack_st_X509_OBJECT, arg_p: ?*const X509_OBJECT) callconv(.c) ?*X509_OBJECT { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_OBJECT, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_OBJECT_find(arg_sk: ?*const struct_stack_st_X509_OBJECT, arg_out_index: [*c]usize, arg_p: ?*const X509_OBJECT) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_OBJECT_call_cmp_func); -} -pub fn sk_X509_OBJECT_shift(arg_sk: ?*struct_stack_st_X509_OBJECT) callconv(.c) ?*X509_OBJECT { - const sk = arg_sk; - return @as(?*X509_OBJECT, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_OBJECT_push(arg_sk: ?*struct_stack_st_X509_OBJECT, arg_p: ?*X509_OBJECT) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_OBJECT_pop(arg_sk: ?*struct_stack_st_X509_OBJECT) callconv(.c) ?*X509_OBJECT { - const sk = arg_sk; - return @as(?*X509_OBJECT, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_OBJECT_dup(arg_sk: ?*const struct_stack_st_X509_OBJECT) callconv(.c) ?*struct_stack_st_X509_OBJECT { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_OBJECT, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_OBJECT_sort(arg_sk: ?*struct_stack_st_X509_OBJECT) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_OBJECT_call_cmp_func); -} -pub fn sk_X509_OBJECT_is_sorted(arg_sk: ?*const struct_stack_st_X509_OBJECT) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_OBJECT_set_cmp_func(arg_sk: ?*struct_stack_st_X509_OBJECT, arg_comp: sk_X509_OBJECT_cmp_func) callconv(.c) sk_X509_OBJECT_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_OBJECT_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_OBJECT_deep_copy(arg_sk: ?*const struct_stack_st_X509_OBJECT, arg_copy_func: sk_X509_OBJECT_copy_func, arg_free_func: sk_X509_OBJECT_free_func) callconv(.c) ?*struct_stack_st_X509_OBJECT { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_OBJECT, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_OBJECT_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_OBJECT_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub const struct_stack_st_X509_VERIFY_PARAM = opaque {}; -pub const sk_X509_VERIFY_PARAM_free_func = ?*const fn (?*X509_VERIFY_PARAM) callconv(.c) void; -pub const sk_X509_VERIFY_PARAM_copy_func = ?*const fn (?*X509_VERIFY_PARAM) callconv(.c) ?*X509_VERIFY_PARAM; -pub const sk_X509_VERIFY_PARAM_cmp_func = ?*const fn ([*c]?*const X509_VERIFY_PARAM, [*c]?*const X509_VERIFY_PARAM) callconv(.c) c_int; -pub fn sk_X509_VERIFY_PARAM_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_X509_VERIFY_PARAM_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*X509_VERIFY_PARAM, @ptrCast(ptr))); -} -pub fn sk_X509_VERIFY_PARAM_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_X509_VERIFY_PARAM_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*X509_VERIFY_PARAM, @ptrCast(ptr))))); -} -pub fn sk_X509_VERIFY_PARAM_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const X509_VERIFY_PARAM = @as(?*const X509_VERIFY_PARAM, @ptrCast(a.*)); - var b_ptr: ?*const X509_VERIFY_PARAM = @as(?*const X509_VERIFY_PARAM, @ptrCast(b.*)); - return @as(sk_X509_VERIFY_PARAM_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_X509_VERIFY_PARAM_new(arg_comp: sk_X509_VERIFY_PARAM_cmp_func) callconv(.c) ?*struct_stack_st_X509_VERIFY_PARAM { - const comp = arg_comp; - return @as(?*struct_stack_st_X509_VERIFY_PARAM, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_X509_VERIFY_PARAM_new_null() callconv(.c) ?*struct_stack_st_X509_VERIFY_PARAM { - return @as(?*struct_stack_st_X509_VERIFY_PARAM, @ptrCast(sk_new_null())); -} -pub fn sk_X509_VERIFY_PARAM_num(arg_sk: ?*const struct_stack_st_X509_VERIFY_PARAM) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_VERIFY_PARAM_zero(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_VERIFY_PARAM_value(arg_sk: ?*const struct_stack_st_X509_VERIFY_PARAM, arg_i: usize) callconv(.c) ?*X509_VERIFY_PARAM { - const sk = arg_sk; - const i = arg_i; - return @as(?*X509_VERIFY_PARAM, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_X509_VERIFY_PARAM_set(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM, arg_i: usize, arg_p: ?*X509_VERIFY_PARAM) callconv(.c) ?*X509_VERIFY_PARAM { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*X509_VERIFY_PARAM, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_VERIFY_PARAM_free(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_VERIFY_PARAM_pop_free(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM, arg_free_func: sk_X509_VERIFY_PARAM_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_VERIFY_PARAM_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_X509_VERIFY_PARAM_insert(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM, arg_p: ?*X509_VERIFY_PARAM, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_X509_VERIFY_PARAM_delete(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM, arg_where: usize) callconv(.c) ?*X509_VERIFY_PARAM { - const sk = arg_sk; - const where = arg_where; - return @as(?*X509_VERIFY_PARAM, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_X509_VERIFY_PARAM_delete_ptr(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM, arg_p: ?*const X509_VERIFY_PARAM) callconv(.c) ?*X509_VERIFY_PARAM { - const sk = arg_sk; - const p = arg_p; - return @as(?*X509_VERIFY_PARAM, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_X509_VERIFY_PARAM_find(arg_sk: ?*const struct_stack_st_X509_VERIFY_PARAM, arg_out_index: [*c]usize, arg_p: ?*const X509_VERIFY_PARAM) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_X509_VERIFY_PARAM_call_cmp_func); -} -pub fn sk_X509_VERIFY_PARAM_shift(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM) callconv(.c) ?*X509_VERIFY_PARAM { - const sk = arg_sk; - return @as(?*X509_VERIFY_PARAM, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_VERIFY_PARAM_push(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM, arg_p: ?*X509_VERIFY_PARAM) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_X509_VERIFY_PARAM_pop(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM) callconv(.c) ?*X509_VERIFY_PARAM { - const sk = arg_sk; - return @as(?*X509_VERIFY_PARAM, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_VERIFY_PARAM_dup(arg_sk: ?*const struct_stack_st_X509_VERIFY_PARAM) callconv(.c) ?*struct_stack_st_X509_VERIFY_PARAM { - const sk = arg_sk; - return @as(?*struct_stack_st_X509_VERIFY_PARAM, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_X509_VERIFY_PARAM_sort(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_X509_VERIFY_PARAM_call_cmp_func); -} -pub fn sk_X509_VERIFY_PARAM_is_sorted(arg_sk: ?*const struct_stack_st_X509_VERIFY_PARAM) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_X509_VERIFY_PARAM_set_cmp_func(arg_sk: ?*struct_stack_st_X509_VERIFY_PARAM, arg_comp: sk_X509_VERIFY_PARAM_cmp_func) callconv(.c) sk_X509_VERIFY_PARAM_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_X509_VERIFY_PARAM_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_X509_VERIFY_PARAM_deep_copy(arg_sk: ?*const struct_stack_st_X509_VERIFY_PARAM, arg_copy_func: sk_X509_VERIFY_PARAM_copy_func, arg_free_func: sk_X509_VERIFY_PARAM_free_func) callconv(.c) ?*struct_stack_st_X509_VERIFY_PARAM { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_X509_VERIFY_PARAM, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_X509_VERIFY_PARAM_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_X509_VERIFY_PARAM_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn X509_check_ca(x: ?*X509) c_int; -pub const X509_STORE_CTX_verify_cb = ?*const fn (c_int, ?*X509_STORE_CTX) callconv(.c) c_int; -pub const X509_STORE_CTX_verify_fn = ?*const fn (?*X509_STORE_CTX) callconv(.c) c_int; -pub const X509_STORE_CTX_get_issuer_fn = ?*const fn ([*c]?*X509, ?*X509_STORE_CTX, ?*X509) callconv(.c) c_int; -pub const X509_STORE_CTX_check_issued_fn = ?*const fn (?*X509_STORE_CTX, ?*X509, ?*X509) callconv(.c) c_int; -pub const X509_STORE_CTX_check_revocation_fn = ?*const fn (?*X509_STORE_CTX) callconv(.c) c_int; -pub const X509_STORE_CTX_get_crl_fn = ?*const fn (?*X509_STORE_CTX, [*c]?*X509_CRL, ?*X509) callconv(.c) c_int; -pub const X509_STORE_CTX_check_crl_fn = ?*const fn (?*X509_STORE_CTX, ?*X509_CRL) callconv(.c) c_int; -pub const X509_STORE_CTX_cert_crl_fn = ?*const fn (?*X509_STORE_CTX, ?*X509_CRL, ?*X509) callconv(.c) c_int; -pub const X509_STORE_CTX_check_policy_fn = ?*const fn (?*X509_STORE_CTX) callconv(.c) c_int; -pub const X509_STORE_CTX_lookup_certs_fn = ?*const fn (?*X509_STORE_CTX, ?*X509_NAME) callconv(.c) ?*struct_stack_st_X509; -pub const X509_STORE_CTX_lookup_crls_fn = ?*const fn (?*X509_STORE_CTX, ?*X509_NAME) callconv(.c) ?*struct_stack_st_X509_CRL; -pub const X509_STORE_CTX_cleanup_fn = ?*const fn (?*X509_STORE_CTX) callconv(.c) c_int; -pub extern fn X509_STORE_set_depth(store: ?*X509_STORE, depth: c_int) c_int; -pub extern fn X509_STORE_CTX_set_depth(ctx: ?*X509_STORE_CTX, depth: c_int) void; -pub extern fn X509_OBJECT_idx_by_subject(h: ?*struct_stack_st_X509_OBJECT, @"type": c_int, name: ?*X509_NAME) c_int; -pub extern fn X509_OBJECT_retrieve_by_subject(h: ?*struct_stack_st_X509_OBJECT, @"type": c_int, name: ?*X509_NAME) ?*X509_OBJECT; -pub extern fn X509_OBJECT_retrieve_match(h: ?*struct_stack_st_X509_OBJECT, x: ?*X509_OBJECT) ?*X509_OBJECT; -pub extern fn X509_OBJECT_up_ref_count(a: ?*X509_OBJECT) c_int; -pub extern fn X509_OBJECT_free_contents(a: ?*X509_OBJECT) void; -pub extern fn X509_OBJECT_get_type(a: ?*const X509_OBJECT) c_int; -pub extern fn X509_OBJECT_get0_X509(a: ?*const X509_OBJECT) ?*X509; -pub extern fn X509_STORE_new() ?*X509_STORE; -pub extern fn X509_STORE_up_ref(store: ?*X509_STORE) c_int; -pub extern fn X509_STORE_free(v: ?*X509_STORE) void; -pub extern fn X509_STORE_get0_objects(st: ?*X509_STORE) ?*struct_stack_st_X509_OBJECT; -pub extern fn X509_STORE_get1_certs(st: ?*X509_STORE_CTX, nm: ?*X509_NAME) ?*struct_stack_st_X509; -pub extern fn X509_STORE_get1_crls(st: ?*X509_STORE_CTX, nm: ?*X509_NAME) ?*struct_stack_st_X509_CRL; -pub extern fn X509_STORE_set_flags(ctx: ?*X509_STORE, flags: c_ulong) c_int; -pub extern fn X509_STORE_set_purpose(ctx: ?*X509_STORE, purpose: c_int) c_int; -pub extern fn X509_STORE_set_trust(ctx: ?*X509_STORE, trust: c_int) c_int; -pub extern fn X509_STORE_set1_param(ctx: ?*X509_STORE, pm: ?*X509_VERIFY_PARAM) c_int; -pub extern fn X509_STORE_get0_param(ctx: ?*X509_STORE) ?*X509_VERIFY_PARAM; -pub extern fn X509_STORE_set_verify(ctx: ?*X509_STORE, verify: X509_STORE_CTX_verify_fn) void; -pub extern fn X509_STORE_CTX_set_verify(ctx: ?*X509_STORE_CTX, verify: X509_STORE_CTX_verify_fn) void; -pub extern fn X509_STORE_get_verify(ctx: ?*X509_STORE) X509_STORE_CTX_verify_fn; -pub extern fn X509_STORE_set_verify_cb(ctx: ?*X509_STORE, verify_cb: X509_STORE_CTX_verify_cb) void; -pub extern fn X509_STORE_get_verify_cb(ctx: ?*X509_STORE) X509_STORE_CTX_verify_cb; -pub extern fn X509_STORE_set_get_issuer(ctx: ?*X509_STORE, get_issuer: X509_STORE_CTX_get_issuer_fn) void; -pub extern fn X509_STORE_get_get_issuer(ctx: ?*X509_STORE) X509_STORE_CTX_get_issuer_fn; -pub extern fn X509_STORE_set_check_issued(ctx: ?*X509_STORE, check_issued: X509_STORE_CTX_check_issued_fn) void; -pub extern fn X509_STORE_get_check_issued(ctx: ?*X509_STORE) X509_STORE_CTX_check_issued_fn; -pub extern fn X509_STORE_set_check_revocation(ctx: ?*X509_STORE, check_revocation: X509_STORE_CTX_check_revocation_fn) void; -pub extern fn X509_STORE_get_check_revocation(ctx: ?*X509_STORE) X509_STORE_CTX_check_revocation_fn; -pub extern fn X509_STORE_set_get_crl(ctx: ?*X509_STORE, get_crl: X509_STORE_CTX_get_crl_fn) void; -pub extern fn X509_STORE_get_get_crl(ctx: ?*X509_STORE) X509_STORE_CTX_get_crl_fn; -pub extern fn X509_STORE_set_check_crl(ctx: ?*X509_STORE, check_crl: X509_STORE_CTX_check_crl_fn) void; -pub extern fn X509_STORE_get_check_crl(ctx: ?*X509_STORE) X509_STORE_CTX_check_crl_fn; -pub extern fn X509_STORE_set_cert_crl(ctx: ?*X509_STORE, cert_crl: X509_STORE_CTX_cert_crl_fn) void; -pub extern fn X509_STORE_get_cert_crl(ctx: ?*X509_STORE) X509_STORE_CTX_cert_crl_fn; -pub extern fn X509_STORE_set_lookup_certs(ctx: ?*X509_STORE, lookup_certs: X509_STORE_CTX_lookup_certs_fn) void; -pub extern fn X509_STORE_get_lookup_certs(ctx: ?*X509_STORE) X509_STORE_CTX_lookup_certs_fn; -pub extern fn X509_STORE_set_lookup_crls(ctx: ?*X509_STORE, lookup_crls: X509_STORE_CTX_lookup_crls_fn) void; -pub extern fn X509_STORE_get_lookup_crls(ctx: ?*X509_STORE) X509_STORE_CTX_lookup_crls_fn; -pub extern fn X509_STORE_set_cleanup(ctx: ?*X509_STORE, cleanup: X509_STORE_CTX_cleanup_fn) void; -pub extern fn X509_STORE_get_cleanup(ctx: ?*X509_STORE) X509_STORE_CTX_cleanup_fn; -pub extern fn X509_STORE_CTX_new() ?*X509_STORE_CTX; -pub extern fn X509_STORE_CTX_get1_issuer(issuer: [*c]?*X509, ctx: ?*X509_STORE_CTX, x: ?*X509) c_int; -pub extern fn X509_STORE_CTX_zero(ctx: ?*X509_STORE_CTX) void; -pub extern fn X509_STORE_CTX_free(ctx: ?*X509_STORE_CTX) void; -pub extern fn X509_STORE_CTX_init(ctx: ?*X509_STORE_CTX, store: ?*X509_STORE, x509: ?*X509, chain: ?*struct_stack_st_X509) c_int; -pub extern fn X509_STORE_CTX_set0_trusted_stack(ctx: ?*X509_STORE_CTX, sk: ?*struct_stack_st_X509) void; -pub extern fn X509_STORE_CTX_trusted_stack(ctx: ?*X509_STORE_CTX, sk: ?*struct_stack_st_X509) void; -pub extern fn X509_STORE_CTX_cleanup(ctx: ?*X509_STORE_CTX) void; -pub extern fn X509_STORE_CTX_get0_store(ctx: ?*X509_STORE_CTX) ?*X509_STORE; -pub extern fn X509_STORE_CTX_get0_cert(ctx: ?*X509_STORE_CTX) ?*X509; -pub extern fn X509_STORE_add_lookup(v: ?*X509_STORE, m: ?*X509_LOOKUP_METHOD) ?*X509_LOOKUP; -pub extern fn X509_LOOKUP_hash_dir() ?*X509_LOOKUP_METHOD; -// pub extern fn X509_LOOKUP_file() ?*X509_LOOKUP_METHOD; -pub extern fn X509_STORE_add_cert(ctx: ?*X509_STORE, x: ?*X509) c_int; -pub extern fn X509_STORE_add_crl(ctx: ?*X509_STORE, x: ?*X509_CRL) c_int; -pub extern fn X509_STORE_get_by_subject(vs: ?*X509_STORE_CTX, @"type": c_int, name: ?*X509_NAME, ret: ?*X509_OBJECT) c_int; -pub extern fn X509_LOOKUP_ctrl(ctx: ?*X509_LOOKUP, cmd: c_int, argc: [*c]const u8, argl: c_long, ret: [*c][*c]u8) c_int; -// pub extern fn X509_load_cert_file(ctx: ?*X509_LOOKUP, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn X509_load_crl_file(ctx: ?*X509_LOOKUP, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn X509_load_cert_crl_file(ctx: ?*X509_LOOKUP, file: [*c]const u8, @"type": c_int) c_int; -pub extern fn X509_LOOKUP_new(method: ?*X509_LOOKUP_METHOD) ?*X509_LOOKUP; -pub extern fn X509_LOOKUP_free(ctx: ?*X509_LOOKUP) void; -pub extern fn X509_LOOKUP_init(ctx: ?*X509_LOOKUP) c_int; -pub extern fn X509_LOOKUP_by_subject(ctx: ?*X509_LOOKUP, @"type": c_int, name: ?*X509_NAME, ret: ?*X509_OBJECT) c_int; -pub extern fn X509_LOOKUP_shutdown(ctx: ?*X509_LOOKUP) c_int; -// pub extern fn X509_STORE_load_locations(ctx: ?*X509_STORE, file: [*c]const u8, dir: [*c]const u8) c_int; -pub extern fn X509_STORE_set_default_paths(ctx: ?*X509_STORE) c_int; -pub extern fn X509_STORE_CTX_get_error(ctx: ?*X509_STORE_CTX) c_int; -pub extern fn X509_STORE_CTX_set_error(ctx: ?*X509_STORE_CTX, s: c_int) void; -pub extern fn X509_STORE_CTX_get_error_depth(ctx: ?*X509_STORE_CTX) c_int; -pub extern fn X509_STORE_CTX_get_current_cert(ctx: ?*X509_STORE_CTX) ?*X509; -pub extern fn X509_STORE_CTX_get0_current_issuer(ctx: ?*X509_STORE_CTX) ?*X509; -pub extern fn X509_STORE_CTX_get0_current_crl(ctx: ?*X509_STORE_CTX) ?*X509_CRL; -pub extern fn X509_STORE_CTX_get0_parent_ctx(ctx: ?*X509_STORE_CTX) ?*X509_STORE_CTX; -pub extern fn X509_STORE_CTX_get_chain(ctx: ?*X509_STORE_CTX) ?*struct_stack_st_X509; -pub extern fn X509_STORE_CTX_get0_chain(ctx: ?*X509_STORE_CTX) ?*struct_stack_st_X509; -pub extern fn X509_STORE_CTX_get1_chain(ctx: ?*X509_STORE_CTX) ?*struct_stack_st_X509; -pub extern fn X509_STORE_CTX_set_cert(c: ?*X509_STORE_CTX, x: ?*X509) void; -pub extern fn X509_STORE_CTX_set_chain(c: ?*X509_STORE_CTX, sk: ?*struct_stack_st_X509) void; -pub extern fn X509_STORE_CTX_get0_untrusted(ctx: ?*X509_STORE_CTX) ?*struct_stack_st_X509; -pub extern fn X509_STORE_CTX_set0_crls(c: ?*X509_STORE_CTX, sk: ?*struct_stack_st_X509_CRL) void; -pub extern fn X509_STORE_CTX_set_purpose(ctx: ?*X509_STORE_CTX, purpose: c_int) c_int; -pub extern fn X509_STORE_CTX_set_trust(ctx: ?*X509_STORE_CTX, trust: c_int) c_int; -pub extern fn X509_STORE_CTX_purpose_inherit(ctx: ?*X509_STORE_CTX, def_purpose: c_int, purpose: c_int, trust: c_int) c_int; -pub extern fn X509_STORE_CTX_set_flags(ctx: ?*X509_STORE_CTX, flags: c_ulong) void; -pub extern fn X509_STORE_CTX_set_time(ctx: ?*X509_STORE_CTX, flags: c_ulong, t: time_t) void; -pub extern fn X509_STORE_CTX_set_verify_cb(ctx: ?*X509_STORE_CTX, verify_cb: ?*const fn (c_int, ?*X509_STORE_CTX) callconv(.c) c_int) void; -pub extern fn X509_STORE_CTX_get0_param(ctx: ?*X509_STORE_CTX) ?*X509_VERIFY_PARAM; -pub extern fn X509_STORE_CTX_set0_param(ctx: ?*X509_STORE_CTX, param: ?*X509_VERIFY_PARAM) void; -pub extern fn X509_STORE_CTX_set_default(ctx: ?*X509_STORE_CTX, name: [*c]const u8) c_int; -pub extern fn X509_VERIFY_PARAM_new() ?*X509_VERIFY_PARAM; -pub extern fn X509_VERIFY_PARAM_free(param: ?*X509_VERIFY_PARAM) void; -pub extern fn X509_VERIFY_PARAM_inherit(to: ?*X509_VERIFY_PARAM, from: ?*const X509_VERIFY_PARAM) c_int; -pub extern fn X509_VERIFY_PARAM_set1(to: ?*X509_VERIFY_PARAM, from: ?*const X509_VERIFY_PARAM) c_int; -pub extern fn X509_VERIFY_PARAM_set1_name(param: ?*X509_VERIFY_PARAM, name: [*c]const u8) c_int; -pub extern fn X509_VERIFY_PARAM_set_flags(param: ?*X509_VERIFY_PARAM, flags: c_ulong) c_int; -pub extern fn X509_VERIFY_PARAM_clear_flags(param: ?*X509_VERIFY_PARAM, flags: c_ulong) c_int; -pub extern fn X509_VERIFY_PARAM_get_flags(param: ?*X509_VERIFY_PARAM) c_ulong; -pub extern fn X509_VERIFY_PARAM_set_purpose(param: ?*X509_VERIFY_PARAM, purpose: c_int) c_int; -pub extern fn X509_VERIFY_PARAM_set_trust(param: ?*X509_VERIFY_PARAM, trust: c_int) c_int; -pub extern fn X509_VERIFY_PARAM_set_depth(param: ?*X509_VERIFY_PARAM, depth: c_int) void; -pub extern fn X509_VERIFY_PARAM_set_time(param: ?*X509_VERIFY_PARAM, t: time_t) void; -pub extern fn X509_VERIFY_PARAM_add0_policy(param: ?*X509_VERIFY_PARAM, policy: ?*ASN1_OBJECT) c_int; -pub extern fn X509_VERIFY_PARAM_set1_policies(param: ?*X509_VERIFY_PARAM, policies: ?*const struct_stack_st_ASN1_OBJECT) c_int; -pub extern fn X509_VERIFY_PARAM_set1_host(param: ?*X509_VERIFY_PARAM, name: [*c]const u8, namelen: usize) c_int; -pub extern fn X509_VERIFY_PARAM_add1_host(param: ?*X509_VERIFY_PARAM, name: [*c]const u8, namelen: usize) c_int; -pub extern fn X509_VERIFY_PARAM_set_hostflags(param: ?*X509_VERIFY_PARAM, flags: c_uint) void; -pub extern fn X509_VERIFY_PARAM_get0_peername(?*X509_VERIFY_PARAM) [*c]u8; -pub extern fn X509_VERIFY_PARAM_set1_email(param: ?*X509_VERIFY_PARAM, email: [*c]const u8, emaillen: usize) c_int; -pub extern fn X509_VERIFY_PARAM_set1_ip(param: ?*X509_VERIFY_PARAM, ip: [*c]const u8, iplen: usize) c_int; -pub extern fn X509_VERIFY_PARAM_set1_ip_asc(param: ?*X509_VERIFY_PARAM, ipasc: [*c]const u8) c_int; -pub extern fn X509_VERIFY_PARAM_get_depth(param: ?*const X509_VERIFY_PARAM) c_int; -pub extern fn X509_VERIFY_PARAM_get0_name(param: ?*const X509_VERIFY_PARAM) [*c]const u8; -pub extern fn X509_VERIFY_PARAM_add0_table(param: ?*X509_VERIFY_PARAM) c_int; -pub extern fn X509_VERIFY_PARAM_get_count() c_int; -pub extern fn X509_VERIFY_PARAM_get0(id: c_int) ?*const X509_VERIFY_PARAM; -pub extern fn X509_VERIFY_PARAM_lookup(name: [*c]const u8) ?*const X509_VERIFY_PARAM; -pub extern fn X509_VERIFY_PARAM_table_cleanup() void; -pub extern fn OPENSSL_malloc(size: usize) ?*anyopaque; -pub extern fn OPENSSL_free(ptr: ?*anyopaque) void; -pub extern fn OPENSSL_realloc(ptr: ?*anyopaque, new_size: usize) ?*anyopaque; -pub extern fn OPENSSL_cleanse(ptr: ?*anyopaque, len: usize) void; -pub extern fn CRYPTO_memcmp(a: ?*const anyopaque, b: ?*const anyopaque, len: usize) c_int; -pub extern fn OPENSSL_hash32(ptr: ?*const anyopaque, len: usize) u32; -pub extern fn OPENSSL_strhash(s: [*c]const u8) u32; -pub extern fn OPENSSL_strdup(s: [*c]const u8) [*c]u8; -pub extern fn OPENSSL_strnlen(s: [*c]const u8, len: usize) usize; -pub extern fn OPENSSL_tolower(c: c_int) c_int; -pub extern fn OPENSSL_strcasecmp(a: [*c]const u8, b: [*c]const u8) c_int; -pub extern fn OPENSSL_strncasecmp(a: [*c]const u8, b: [*c]const u8, n: usize) c_int; -pub extern fn BIO_snprintf(buf: [*c]u8, n: usize, format: [*c]const u8, ...) c_int; -pub extern fn BIO_vsnprintf(buf: [*c]u8, n: usize, format: [*c]const u8, args: va_list) c_int; -pub extern fn OPENSSL_strndup(str: [*c]const u8, size: usize) [*c]u8; -pub extern fn OPENSSL_memdup(data: ?*const anyopaque, size: usize) ?*anyopaque; -pub extern fn OPENSSL_strlcpy(dst: [*c]u8, src: [*c]const u8, dst_size: usize) usize; -pub extern fn OPENSSL_strlcat(dst: [*c]u8, src: [*c]const u8, dst_size: usize) usize; -// pub extern fn CRYPTO_malloc(size: usize, file: [*c]const u8, line: c_int) ?*anyopaque; -// pub extern fn CRYPTO_realloc(ptr: ?*anyopaque, new_size: usize, file: [*c]const u8, line: c_int) ?*anyopaque; -// pub extern fn CRYPTO_free(ptr: ?*anyopaque, file: [*c]const u8, line: c_int) void; -pub extern fn OPENSSL_clear_free(ptr: ?*anyopaque, len: usize) void; -pub extern fn CRYPTO_secure_malloc_init(size: usize, min_size: usize) c_int; -pub extern fn CRYPTO_secure_malloc_initialized() c_int; -pub extern fn CRYPTO_secure_used() usize; -pub extern fn OPENSSL_secure_malloc(size: usize) ?*anyopaque; -pub extern fn OPENSSL_secure_clear_free(ptr: ?*anyopaque, len: usize) void; -pub extern fn CRYPTO_library_init() void; -pub extern fn CRYPTO_is_confidential_build() c_int; -pub extern fn CRYPTO_has_asm() c_int; -pub extern fn BORINGSSL_self_test() c_int; -pub extern fn BORINGSSL_integrity_test() c_int; -pub extern fn CRYPTO_pre_sandbox_init() void; -pub extern fn FIPS_mode() c_int; -pub const fips_counter_evp_aes_128_gcm: c_int = 0; -pub const fips_counter_evp_aes_256_gcm: c_int = 1; -pub const fips_counter_evp_aes_128_ctr: c_int = 2; -pub const fips_counter_evp_aes_256_ctr: c_int = 3; -pub const fips_counter_max: c_int = 3; -pub const enum_fips_counter_t = c_uint; -pub extern fn FIPS_read_counter(counter: enum_fips_counter_t) usize; -pub extern fn OpenSSL_version(which: c_int) [*c]const u8; -pub extern fn SSLeay_version(which: c_int) [*c]const u8; -pub extern fn SSLeay() c_ulong; -pub extern fn OpenSSL_version_num() c_ulong; -pub extern fn CRYPTO_malloc_init() c_int; -pub extern fn OPENSSL_malloc_init() c_int; -pub extern fn ENGINE_load_builtin_engines() void; -pub extern fn ENGINE_register_all_complete() c_int; -pub extern fn OPENSSL_load_builtin_modules() void; -pub extern fn OPENSSL_init_crypto(opts: u64, settings: ?*const OPENSSL_INIT_SETTINGS) c_int; -pub extern fn OPENSSL_cleanup() void; -pub extern fn FIPS_mode_set(on: c_int) c_int; -pub extern fn FIPS_module_name() [*c]const u8; -pub extern fn FIPS_version() u32; -pub extern fn FIPS_query_algorithm_status(algorithm: [*c]const u8) c_int; -pub const pem_password_cb = fn ([*c]u8, c_int, c_int, ?*anyopaque) callconv(.c) c_int; -pub extern fn PEM_get_EVP_CIPHER_INFO(header: [*c]u8, cipher: [*c]EVP_CIPHER_INFO) c_int; -pub extern fn PEM_do_header(cipher: [*c]EVP_CIPHER_INFO, data: [*c]u8, len: [*c]c_long, callback: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_read_bio(bp: [*c]BIO, name: [*c][*c]u8, header: [*c][*c]u8, data: [*c][*c]u8, len: [*c]c_long) c_int; -pub extern fn PEM_write_bio(bp: [*c]BIO, name: [*c]const u8, hdr: [*c]const u8, data: [*c]const u8, len: c_long) c_int; -pub extern fn PEM_bytes_read_bio(pdata: [*c][*c]u8, plen: [*c]c_long, pnm: [*c][*c]u8, name: [*c]const u8, bp: [*c]BIO, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_ASN1_read_bio(d2i: ?*const d2i_of_void, name: [*c]const u8, bp: [*c]BIO, x: [*c]?*anyopaque, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*anyopaque; -pub extern fn PEM_ASN1_write_bio(i2d: ?*const i2d_of_void, name: [*c]const u8, bp: [*c]BIO, x: ?*anyopaque, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_X509_INFO_read_bio(bp: [*c]BIO, sk: ?*struct_stack_st_X509_INFO, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*struct_stack_st_X509_INFO; -// pub extern fn PEM_read(fp: [*c]FILE, name: [*c][*c]u8, header: [*c][*c]u8, data: [*c][*c]u8, len: [*c]c_long) c_int; -// pub extern fn PEM_write(fp: [*c]FILE, name: [*c]const u8, hdr: [*c]const u8, data: [*c]const u8, len: c_long) c_int; -// pub extern fn PEM_ASN1_read(d2i: ?*const d2i_of_void, name: [*c]const u8, fp: [*c]FILE, x: [*c]?*anyopaque, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*anyopaque; -// pub extern fn PEM_ASN1_write(i2d: ?*const i2d_of_void, name: [*c]const u8, fp: [*c]FILE, x: ?*anyopaque, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, callback: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn PEM_X509_INFO_read(fp: [*c]FILE, sk: ?*struct_stack_st_X509_INFO, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*struct_stack_st_X509_INFO; -pub extern fn PEM_def_callback(buf: [*c]u8, size: c_int, rwflag: c_int, userdata: ?*anyopaque) c_int; -pub extern fn PEM_proc_type(buf: [*c]u8, @"type": c_int) void; -pub extern fn PEM_dek_info(buf: [*c]u8, @"type": [*c]const u8, len: c_int, str: [*c]u8) void; -pub extern fn PEM_read_bio_X509(bp: [*c]BIO, x: [*c]?*X509, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509; -// pub extern fn PEM_read_X509(fp: [*c]FILE, x: [*c]?*X509, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509; -pub extern fn PEM_write_bio_X509(bp: [*c]BIO, x: ?*X509) c_int; -// pub extern fn PEM_write_X509(fp: [*c]FILE, x: ?*X509) c_int; -pub extern fn PEM_read_bio_X509_AUX(bp: [*c]BIO, x: [*c]?*X509, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509; -// pub extern fn PEM_read_X509_AUX(fp: [*c]FILE, x: [*c]?*X509, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509; -pub extern fn PEM_write_bio_X509_AUX(bp: [*c]BIO, x: ?*X509) c_int; -// pub extern fn PEM_write_X509_AUX(fp: [*c]FILE, x: ?*X509) c_int; -pub extern fn PEM_read_bio_X509_REQ(bp: [*c]BIO, x: [*c]?*X509_REQ, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509_REQ; -// pub extern fn PEM_read_X509_REQ(fp: [*c]FILE, x: [*c]?*X509_REQ, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509_REQ; -pub extern fn PEM_write_bio_X509_REQ(bp: [*c]BIO, x: ?*X509_REQ) c_int; -// pub extern fn PEM_write_X509_REQ(fp: [*c]FILE, x: ?*X509_REQ) c_int; -pub extern fn PEM_write_bio_X509_REQ_NEW(bp: [*c]BIO, x: ?*X509_REQ) c_int; -// pub extern fn PEM_write_X509_REQ_NEW(fp: [*c]FILE, x: ?*X509_REQ) c_int; -pub extern fn PEM_read_bio_X509_CRL(bp: [*c]BIO, x: [*c]?*X509_CRL, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509_CRL; -// pub extern fn PEM_read_X509_CRL(fp: [*c]FILE, x: [*c]?*X509_CRL, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509_CRL; -pub extern fn PEM_write_bio_X509_CRL(bp: [*c]BIO, x: ?*X509_CRL) c_int; -// pub extern fn PEM_write_X509_CRL(fp: [*c]FILE, x: ?*X509_CRL) c_int; -pub extern fn PEM_read_bio_PKCS7(bp: [*c]BIO, x: [*c][*c]PKCS7, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]PKCS7; -// pub extern fn PEM_read_PKCS7(fp: [*c]FILE, x: [*c][*c]PKCS7, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]PKCS7; -pub extern fn PEM_write_bio_PKCS7(bp: [*c]BIO, x: [*c]PKCS7) c_int; -// pub extern fn PEM_write_PKCS7(fp: [*c]FILE, x: [*c]PKCS7) c_int; -pub extern fn PEM_read_bio_PKCS8(bp: [*c]BIO, x: [*c]?*X509_SIG, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509_SIG; -// pub extern fn PEM_read_PKCS8(fp: [*c]FILE, x: [*c]?*X509_SIG, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*X509_SIG; -pub extern fn PEM_write_bio_PKCS8(bp: [*c]BIO, x: ?*X509_SIG) c_int; -// pub extern fn PEM_write_PKCS8(fp: [*c]FILE, x: ?*X509_SIG) c_int; -pub extern fn PEM_read_bio_PKCS8_PRIV_KEY_INFO(bp: [*c]BIO, x: [*c]?*PKCS8_PRIV_KEY_INFO, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*PKCS8_PRIV_KEY_INFO; -// pub extern fn PEM_read_PKCS8_PRIV_KEY_INFO(fp: [*c]FILE, x: [*c]?*PKCS8_PRIV_KEY_INFO, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*PKCS8_PRIV_KEY_INFO; -pub extern fn PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp: [*c]BIO, x: ?*PKCS8_PRIV_KEY_INFO) c_int; -// pub extern fn PEM_write_PKCS8_PRIV_KEY_INFO(fp: [*c]FILE, x: ?*PKCS8_PRIV_KEY_INFO) c_int; -pub extern fn PEM_read_bio_RSAPrivateKey(bp: [*c]BIO, x: [*c]?*RSA, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*RSA; -// pub extern fn PEM_read_RSAPrivateKey(fp: [*c]FILE, x: [*c]?*RSA, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*RSA; -pub extern fn PEM_write_bio_RSAPrivateKey(bp: [*c]BIO, x: ?*RSA, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn PEM_write_RSAPrivateKey(fp: [*c]FILE, x: ?*RSA, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_read_bio_RSAPublicKey(bp: [*c]BIO, x: [*c]?*RSA, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*RSA; -// pub extern fn PEM_read_RSAPublicKey(fp: [*c]FILE, x: [*c]?*RSA, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*RSA; -pub extern fn PEM_write_bio_RSAPublicKey(bp: [*c]BIO, x: ?*const RSA) c_int; -// pub extern fn PEM_write_RSAPublicKey(fp: [*c]FILE, x: ?*const RSA) c_int; -pub extern fn PEM_read_bio_RSA_PUBKEY(bp: [*c]BIO, x: [*c]?*RSA, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*RSA; -// pub extern fn PEM_read_RSA_PUBKEY(fp: [*c]FILE, x: [*c]?*RSA, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*RSA; -pub extern fn PEM_write_bio_RSA_PUBKEY(bp: [*c]BIO, x: ?*RSA) c_int; -// pub extern fn PEM_write_RSA_PUBKEY(fp: [*c]FILE, x: ?*RSA) c_int; -pub extern fn PEM_read_bio_DSAPrivateKey(bp: [*c]BIO, x: [*c][*c]DSA, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]DSA; -// pub extern fn PEM_read_DSAPrivateKey(fp: [*c]FILE, x: [*c][*c]DSA, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]DSA; -pub extern fn PEM_write_bio_DSAPrivateKey(bp: [*c]BIO, x: [*c]DSA, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn PEM_write_DSAPrivateKey(fp: [*c]FILE, x: [*c]DSA, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_read_bio_DSA_PUBKEY(bp: [*c]BIO, x: [*c][*c]DSA, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]DSA; -// pub extern fn PEM_read_DSA_PUBKEY(fp: [*c]FILE, x: [*c][*c]DSA, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]DSA; -pub extern fn PEM_write_bio_DSA_PUBKEY(bp: [*c]BIO, x: [*c]DSA) c_int; -// pub extern fn PEM_write_DSA_PUBKEY(fp: [*c]FILE, x: [*c]DSA) c_int; -pub extern fn PEM_read_bio_DSAparams(bp: [*c]BIO, x: [*c][*c]DSA, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]DSA; -// pub extern fn PEM_read_DSAparams(fp: [*c]FILE, x: [*c][*c]DSA, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]DSA; -pub extern fn PEM_write_bio_DSAparams(bp: [*c]BIO, x: [*c]const DSA) c_int; -// pub extern fn PEM_write_DSAparams(fp: [*c]FILE, x: [*c]const DSA) c_int; -pub extern fn PEM_read_bio_ECPrivateKey(bp: [*c]BIO, x: [*c]?*EC_KEY, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*EC_KEY; -// pub extern fn PEM_read_ECPrivateKey(fp: [*c]FILE, x: [*c]?*EC_KEY, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*EC_KEY; -pub extern fn PEM_write_bio_ECPrivateKey(bp: [*c]BIO, x: ?*EC_KEY, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn PEM_write_ECPrivateKey(fp: [*c]FILE, x: ?*EC_KEY, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_read_bio_EC_PUBKEY(bp: [*c]BIO, x: [*c]?*EC_KEY, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*EC_KEY; -// pub extern fn PEM_read_EC_PUBKEY(fp: [*c]FILE, x: [*c]?*EC_KEY, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*EC_KEY; -pub extern fn PEM_write_bio_EC_PUBKEY(bp: [*c]BIO, x: ?*EC_KEY) c_int; -// pub extern fn PEM_write_EC_PUBKEY(fp: [*c]FILE, x: ?*EC_KEY) c_int; -pub extern fn PEM_read_bio_DHparams(bp: [*c]BIO, x: [*c]?*DH, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*DH; -// pub extern fn PEM_read_DHparams(fp: [*c]FILE, x: [*c]?*DH, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*DH; -pub extern fn PEM_write_bio_DHparams(bp: [*c]BIO, x: ?*const DH) c_int; -// pub extern fn PEM_write_DHparams(fp: [*c]FILE, x: ?*const DH) c_int; -pub extern fn PEM_read_bio_PrivateKey(bp: [*c]BIO, x: [*c][*c]EVP_PKEY, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]EVP_PKEY; -// pub extern fn PEM_read_PrivateKey(fp: [*c]FILE, x: [*c][*c]EVP_PKEY, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]EVP_PKEY; -pub extern fn PEM_write_bio_PrivateKey(bp: [*c]BIO, x: [*c]EVP_PKEY, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn PEM_write_PrivateKey(fp: [*c]FILE, x: [*c]EVP_PKEY, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_read_bio_PUBKEY(bp: [*c]BIO, x: [*c][*c]EVP_PKEY, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]EVP_PKEY; -// pub extern fn PEM_read_PUBKEY(fp: [*c]FILE, x: [*c][*c]EVP_PKEY, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]EVP_PKEY; -pub extern fn PEM_write_bio_PUBKEY(bp: [*c]BIO, x: [*c]EVP_PKEY) c_int; -// pub extern fn PEM_write_PUBKEY(fp: [*c]FILE, x: [*c]EVP_PKEY) c_int; -pub extern fn PEM_write_bio_PKCS8PrivateKey_nid(bp: [*c]BIO, x: [*c]EVP_PKEY, nid: c_int, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn PEM_write_bio_PKCS8PrivateKey([*c]BIO, [*c]EVP_PKEY, ?*const EVP_CIPHER, [*c]u8, c_int, ?*const pem_password_cb, ?*anyopaque) c_int; -pub extern fn i2d_PKCS8PrivateKey_bio(bp: [*c]BIO, x: [*c]EVP_PKEY, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn i2d_PKCS8PrivateKey_nid_bio(bp: [*c]BIO, x: [*c]EVP_PKEY, nid: c_int, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -pub extern fn d2i_PKCS8PrivateKey_bio(bp: [*c]BIO, x: [*c][*c]EVP_PKEY, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]EVP_PKEY; -// pub extern fn i2d_PKCS8PrivateKey_fp(fp: [*c]FILE, x: [*c]EVP_PKEY, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn i2d_PKCS8PrivateKey_nid_fp(fp: [*c]FILE, x: [*c]EVP_PKEY, nid: c_int, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn PEM_write_PKCS8PrivateKey_nid(fp: [*c]FILE, x: [*c]EVP_PKEY, nid: c_int, kstr: [*c]u8, klen: c_int, cb: ?*const pem_password_cb, u: ?*anyopaque) c_int; -// pub extern fn d2i_PKCS8PrivateKey_fp(fp: [*c]FILE, x: [*c][*c]EVP_PKEY, cb: ?*const pem_password_cb, u: ?*anyopaque) [*c]EVP_PKEY; -// pub extern fn PEM_write_PKCS8PrivateKey(fp: [*c]FILE, x: [*c]EVP_PKEY, enc: ?*const EVP_CIPHER, kstr: [*c]u8, klen: c_int, cd: ?*const pem_password_cb, u: ?*anyopaque) c_int; - -pub extern fn HMAC(evp_md: *const EVP_MD, key: *const anyopaque, key_len: usize, data: [*]const u8, data_len: usize, out: [*]u8, out_len: *c_uint) ?[*]u8; -pub extern fn HMAC_CTX_init(ctx: [*c]HMAC_CTX) void; -pub extern fn HMAC_CTX_new() [*c]HMAC_CTX; -pub extern fn HMAC_CTX_cleanup(ctx: [*c]HMAC_CTX) void; -pub extern fn HMAC_CTX_cleanse(ctx: [*c]HMAC_CTX) void; -pub extern fn HMAC_CTX_free(ctx: [*c]HMAC_CTX) void; -pub extern fn HMAC_Init_ex(ctx: [*c]HMAC_CTX, key: ?*const anyopaque, key_len: usize, md: ?*const EVP_MD, impl: ?*ENGINE) c_int; -pub extern fn HMAC_Update(ctx: [*c]HMAC_CTX, data: [*c]const u8, data_len: usize) c_int; -pub extern fn HMAC_Final(ctx: [*c]HMAC_CTX, out: [*c]u8, out_len: [*c]c_uint) c_int; -pub extern fn HMAC_size(ctx: [*c]const HMAC_CTX) usize; -pub extern fn HMAC_CTX_get_md(ctx: [*c]const HMAC_CTX) ?*const EVP_MD; -pub extern fn HMAC_CTX_copy_ex(dest: [*c]HMAC_CTX, src: [*c]const HMAC_CTX) c_int; -pub extern fn HMAC_CTX_reset(ctx: [*c]HMAC_CTX) void; -pub extern fn HMAC_Init(ctx: [*c]HMAC_CTX, key: ?*const anyopaque, key_len: c_int, md: ?*const EVP_MD) c_int; -pub extern fn HMAC_CTX_copy(dest: [*c]HMAC_CTX, src: [*c]const HMAC_CTX) c_int; -pub extern fn TLS_method() ?*const SSL_METHOD; -pub extern fn DTLS_method() ?*const SSL_METHOD; -pub extern fn TLS_with_buffers_method() ?*const SSL_METHOD; -pub extern fn DTLS_with_buffers_method() ?*const SSL_METHOD; -pub extern fn SSL_CTX_new(method: ?*const SSL_METHOD) ?*SSL_CTX; -pub extern fn SSL_CTX_up_ref(ctx: ?*SSL_CTX) c_int; -pub extern fn SSL_CTX_free(ctx: ?*SSL_CTX) void; -pub extern fn SSL_free(ssl: ?*SSL) void; -pub extern fn SSL_get_SSL_CTX(ssl: ?*const SSL) ?*SSL_CTX; -pub extern fn SSL_set_connect_state(ssl: ?*SSL) void; -pub extern fn SSL_set_accept_state(ssl: ?*SSL) void; -pub extern fn SSL_is_server(ssl: ?*const SSL) c_int; -pub extern fn SSL_is_dtls(ssl: ?*const SSL) c_int; -pub extern fn SSL_set_bio(ssl: ?*SSL, rbio: [*c]BIO, wbio: [*c]BIO) void; -pub extern fn SSL_set0_rbio(ssl: ?*SSL, rbio: [*c]BIO) void; -pub extern fn SSL_set0_wbio(ssl: ?*SSL, wbio: [*c]BIO) void; -pub extern fn SSL_get_rbio(ssl: ?*const SSL) [*c]BIO; -pub extern fn SSL_get_wbio(ssl: ?*const SSL) [*c]BIO; -pub extern fn SSL_get_fd(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_rfd(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_wfd(ssl: ?*const SSL) c_int; -pub extern fn SSL_set_fd(ssl: ?*SSL, fd: c_int) c_int; -pub extern fn SSL_set_rfd(ssl: ?*SSL, fd: c_int) c_int; -pub extern fn SSL_set_wfd(ssl: ?*SSL, fd: c_int) c_int; -pub extern fn SSL_do_handshake(ssl: ?*SSL) c_int; -pub extern fn SSL_connect(ssl: ?*SSL) c_int; -pub extern fn SSL_accept(ssl: ?*SSL) c_int; -pub extern fn SSL_read(ssl: ?*SSL, buf: ?*anyopaque, num: c_int) c_int; -pub extern fn SSL_peek(ssl: ?*SSL, buf: ?*anyopaque, num: c_int) c_int; -pub extern fn SSL_pending(ssl: ?*const SSL) c_int; -pub extern fn SSL_has_pending(ssl: ?*const SSL) c_int; -pub extern fn SSL_write(ssl: ?*SSL, buf: ?*const anyopaque, num: c_int) c_int; -pub extern fn SSL_key_update(ssl: ?*SSL, request_type: c_int) c_int; -pub extern fn SSL_shutdown(ssl: ?*SSL) c_int; -pub extern fn SSL_CTX_set_quiet_shutdown(ctx: ?*SSL_CTX, mode: c_int) void; -pub extern fn SSL_CTX_get_quiet_shutdown(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_set_quiet_shutdown(ssl: ?*SSL, mode: c_int) void; -pub extern fn SSL_get_quiet_shutdown(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_error(ssl: ?*const SSL, ret_code: c_int) c_int; -pub extern fn SSL_error_description(err: c_int) [*c]const u8; -pub extern fn SSL_set_mtu(ssl: ?*SSL, mtu: c_uint) c_int; -pub extern fn DTLSv1_set_initial_timeout_duration(ssl: ?*SSL, duration_ms: c_uint) void; -pub extern fn DTLSv1_get_timeout(ssl: ?*const SSL, out: [*c]struct_timeval) c_int; -pub extern fn DTLSv1_handle_timeout(ssl: ?*SSL) c_int; -pub extern fn SSL_CTX_set_min_proto_version(ctx: ?*SSL_CTX, version: u16) c_int; -pub extern fn SSL_CTX_set_max_proto_version(ctx: ?*SSL_CTX, version: u16) c_int; -pub extern fn SSL_CTX_get_min_proto_version(ctx: ?*const SSL_CTX) u16; -pub extern fn SSL_CTX_get_max_proto_version(ctx: ?*const SSL_CTX) u16; -pub extern fn SSL_set_min_proto_version(ssl: ?*SSL, version: u16) c_int; -pub extern fn SSL_set_max_proto_version(ssl: ?*SSL, version: u16) c_int; -pub extern fn SSL_get_min_proto_version(ssl: ?*const SSL) u16; -pub extern fn SSL_get_max_proto_version(ssl: ?*const SSL) u16; -pub extern fn SSL_version(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_set_options(ctx: ?*SSL_CTX, options: u32) u32; -pub extern fn SSL_CTX_clear_options(ctx: ?*SSL_CTX, options: u32) u32; -pub extern fn SSL_CTX_get_options(ctx: ?*const SSL_CTX) u32; -pub extern fn SSL_set_options(ssl: ?*SSL, options: u32) u32; -pub extern fn SSL_clear_options(ssl: ?*SSL, options: u32) u32; -pub extern fn SSL_get_options(ssl: ?*const SSL) u32; -pub extern fn SSL_CTX_set_mode(ctx: ?*SSL_CTX, mode: u32) u32; -pub extern fn SSL_CTX_clear_mode(ctx: ?*SSL_CTX, mode: u32) u32; -pub extern fn SSL_CTX_get_mode(ctx: ?*const SSL_CTX) u32; -pub extern fn SSL_set_mode(ssl: ?*SSL, mode: u32) u32; -pub extern fn SSL_clear_mode(ssl: ?*SSL, mode: u32) u32; -pub extern fn SSL_get_mode(ssl: ?*const SSL) u32; -pub extern fn SSL_CTX_set0_buffer_pool(ctx: ?*SSL_CTX, pool: ?*CRYPTO_BUFFER_POOL) void; -pub extern fn SSL_CTX_use_certificate(ctx: ?*SSL_CTX, x509: ?*X509) c_int; -pub extern fn SSL_use_certificate(ssl: ?*SSL, x509: ?*X509) c_int; -pub extern fn SSL_CTX_use_PrivateKey(ctx: ?*SSL_CTX, pkey: [*c]EVP_PKEY) c_int; -pub extern fn SSL_use_PrivateKey(ssl: ?*SSL, pkey: [*c]EVP_PKEY) c_int; -pub extern fn SSL_CTX_set0_chain(ctx: ?*SSL_CTX, chain: ?*struct_stack_st_X509) c_int; -pub extern fn SSL_CTX_set1_chain(ctx: ?*SSL_CTX, chain: ?*struct_stack_st_X509) c_int; -pub extern fn SSL_set0_chain(ssl: ?*SSL, chain: ?*struct_stack_st_X509) c_int; -pub extern fn SSL_set1_chain(ssl: ?*SSL, chain: ?*struct_stack_st_X509) c_int; -pub extern fn SSL_CTX_add0_chain_cert(ctx: ?*SSL_CTX, x509: ?*X509) c_int; -pub extern fn SSL_CTX_add1_chain_cert(ctx: ?*SSL_CTX, x509: ?*X509) c_int; -pub extern fn SSL_add0_chain_cert(ssl: ?*SSL, x509: ?*X509) c_int; -pub extern fn SSL_CTX_add_extra_chain_cert(ctx: ?*SSL_CTX, x509: ?*X509) c_int; -pub extern fn SSL_add1_chain_cert(ssl: ?*SSL, x509: ?*X509) c_int; -pub extern fn SSL_CTX_clear_chain_certs(ctx: ?*SSL_CTX) c_int; -pub extern fn SSL_CTX_clear_extra_chain_certs(ctx: ?*SSL_CTX) c_int; -pub extern fn SSL_clear_chain_certs(ssl: ?*SSL) c_int; -pub extern fn SSL_CTX_set_cert_cb(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, ?*anyopaque) callconv(.c) c_int, arg: ?*anyopaque) void; -pub extern fn SSL_set_cert_cb(ssl: ?*SSL, cb: ?*const fn (?*SSL, ?*anyopaque) callconv(.c) c_int, arg: ?*anyopaque) void; -pub extern fn SSL_get0_certificate_types(ssl: ?*const SSL, out_types: [*c][*c]const u8) usize; -pub extern fn SSL_get0_peer_verify_algorithms(ssl: ?*const SSL, out_sigalgs: [*c][*c]const u16) usize; -pub extern fn SSL_get0_peer_delegation_algorithms(ssl: ?*const SSL, out_sigalgs: [*c][*c]const u16) usize; -pub extern fn SSL_certs_clear(ssl: ?*SSL) void; -pub extern fn SSL_CTX_check_private_key(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_check_private_key(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_get0_certificate(ctx: ?*const SSL_CTX) ?*X509; -pub extern fn SSL_get_certificate(ssl: ?*const SSL) ?*X509; -pub extern fn SSL_CTX_get0_privatekey(ctx: ?*const SSL_CTX) [*c]EVP_PKEY; -pub extern fn SSL_get_privatekey(ssl: ?*const SSL) [*c]EVP_PKEY; -pub extern fn SSL_CTX_get0_chain_certs(ctx: ?*const SSL_CTX, out_chain: [*c]?*struct_stack_st_X509) c_int; -pub extern fn SSL_CTX_get_extra_chain_certs(ctx: ?*const SSL_CTX, out_chain: [*c]?*struct_stack_st_X509) c_int; -pub extern fn SSL_get0_chain_certs(ssl: ?*const SSL, out_chain: [*c]?*struct_stack_st_X509) c_int; -pub extern fn SSL_CTX_set_signed_cert_timestamp_list(ctx: ?*SSL_CTX, list: [*c]const u8, list_len: usize) c_int; -pub extern fn SSL_set_signed_cert_timestamp_list(ctx: ?*SSL, list: [*c]const u8, list_len: usize) c_int; -pub extern fn SSL_CTX_set_ocsp_response(ctx: ?*SSL_CTX, response: [*c]const u8, response_len: usize) c_int; -pub extern fn SSL_set_ocsp_response(ssl: ?*SSL, response: [*c]const u8, response_len: usize) c_int; -pub extern fn SSL_get_signature_algorithm_name(sigalg: u16, include_curve: c_int) [*c]const u8; -pub extern fn SSL_get_signature_algorithm_key_type(sigalg: u16) c_int; -pub extern fn SSL_get_signature_algorithm_digest(sigalg: u16) ?*const EVP_MD; -pub extern fn SSL_is_signature_algorithm_rsa_pss(sigalg: u16) c_int; -pub extern fn SSL_CTX_set_signing_algorithm_prefs(ctx: ?*SSL_CTX, prefs: [*c]const u16, num_prefs: usize) c_int; -pub extern fn SSL_set_signing_algorithm_prefs(ssl: ?*SSL, prefs: [*c]const u16, num_prefs: usize) c_int; -pub extern fn SSL_CTX_set_chain_and_key(ctx: ?*SSL_CTX, certs: [*c]const ?*CRYPTO_BUFFER, num_certs: usize, privkey: [*c]EVP_PKEY, privkey_method: [*c]const SSL_PRIVATE_KEY_METHOD) c_int; -pub extern fn SSL_set_chain_and_key(ssl: ?*SSL, certs: [*c]const ?*CRYPTO_BUFFER, num_certs: usize, privkey: [*c]EVP_PKEY, privkey_method: [*c]const SSL_PRIVATE_KEY_METHOD) c_int; -pub extern fn SSL_CTX_get0_chain(ctx: ?*const SSL_CTX) ?*const struct_stack_st_CRYPTO_BUFFER; -pub extern fn SSL_CTX_use_RSAPrivateKey(ctx: ?*SSL_CTX, rsa: ?*RSA) c_int; -pub extern fn SSL_use_RSAPrivateKey(ssl: ?*SSL, rsa: ?*RSA) c_int; -pub extern fn SSL_CTX_use_certificate_ASN1(ctx: ?*SSL_CTX, der_len: usize, der: [*c]const u8) c_int; -pub extern fn SSL_use_certificate_ASN1(ssl: ?*SSL, der: [*c]const u8, der_len: usize) c_int; -pub extern fn SSL_CTX_use_PrivateKey_ASN1(pk: c_int, ctx: ?*SSL_CTX, der: [*c]const u8, der_len: usize) c_int; -pub extern fn SSL_use_PrivateKey_ASN1(@"type": c_int, ssl: ?*SSL, der: [*c]const u8, der_len: usize) c_int; -pub extern fn SSL_CTX_use_RSAPrivateKey_ASN1(ctx: ?*SSL_CTX, der: [*c]const u8, der_len: usize) c_int; -pub extern fn SSL_use_RSAPrivateKey_ASN1(ssl: ?*SSL, der: [*c]const u8, der_len: usize) c_int; -// pub extern fn SSL_CTX_use_RSAPrivateKey_file(ctx: ?*SSL_CTX, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn SSL_use_RSAPrivateKey_file(ssl: ?*SSL, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn SSL_CTX_use_certificate_file(ctx: ?*SSL_CTX, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn SSL_use_certificate_file(ssl: ?*SSL, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn SSL_CTX_use_PrivateKey_file(ctx: ?*SSL_CTX, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn SSL_use_PrivateKey_file(ssl: ?*SSL, file: [*c]const u8, @"type": c_int) c_int; -// pub extern fn SSL_CTX_use_certificate_chain_file(ctx: ?*SSL_CTX, file: [*c]const u8) c_int; -pub extern fn SSL_CTX_set_default_passwd_cb(ctx: ?*SSL_CTX, cb: ?*const pem_password_cb) void; -pub extern fn SSL_CTX_get_default_passwd_cb(ctx: ?*const SSL_CTX) ?*const pem_password_cb; -pub extern fn SSL_CTX_set_default_passwd_cb_userdata(ctx: ?*SSL_CTX, data: ?*anyopaque) void; -pub extern fn SSL_CTX_get_default_passwd_cb_userdata(ctx: ?*const SSL_CTX) ?*anyopaque; -pub extern fn SSL_set_private_key_method(ssl: ?*SSL, key_method: [*c]const SSL_PRIVATE_KEY_METHOD) void; -pub extern fn SSL_CTX_set_private_key_method(ctx: ?*SSL_CTX, key_method: [*c]const SSL_PRIVATE_KEY_METHOD) void; -pub extern fn SSL_can_release_private_key(ssl: ?*const SSL) c_int; -pub const struct_stack_st_SSL_CIPHER = opaque {}; -pub const sk_SSL_CIPHER_free_func = ?*const fn (?*const SSL_CIPHER) callconv(.c) void; -pub const sk_SSL_CIPHER_copy_func = ?*const fn (?*const SSL_CIPHER) callconv(.c) ?*const SSL_CIPHER; -pub const sk_SSL_CIPHER_cmp_func = ?*const fn ([*c]?*const SSL_CIPHER, [*c]?*const SSL_CIPHER) callconv(.c) c_int; -pub fn sk_SSL_CIPHER_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_SSL_CIPHER_free_func, @ptrCast(@alignCast(free_func))).?(@as(?*const SSL_CIPHER, @ptrCast(ptr))); -} -pub fn sk_SSL_CIPHER_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(@as(sk_SSL_CIPHER_copy_func, @ptrCast(@alignCast(copy_func))).?(@as(?*const SSL_CIPHER, @ptrCast(ptr))))))); -} -pub fn sk_SSL_CIPHER_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: ?*const SSL_CIPHER = @as(?*const SSL_CIPHER, @ptrCast(a.*)); - var b_ptr: ?*const SSL_CIPHER = @as(?*const SSL_CIPHER, @ptrCast(b.*)); - return @as(sk_SSL_CIPHER_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_SSL_CIPHER_new(arg_comp: sk_SSL_CIPHER_cmp_func) callconv(.c) ?*struct_stack_st_SSL_CIPHER { - const comp = arg_comp; - return @as(?*struct_stack_st_SSL_CIPHER, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_SSL_CIPHER_new_null() callconv(.c) ?*struct_stack_st_SSL_CIPHER { - return @as(?*struct_stack_st_SSL_CIPHER, @ptrCast(sk_new_null())); -} -pub fn sk_SSL_CIPHER_num(arg_sk: ?*const struct_stack_st_SSL_CIPHER) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_CIPHER_zero(arg_sk: ?*struct_stack_st_SSL_CIPHER) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_CIPHER_value(arg_sk: ?*const struct_stack_st_SSL_CIPHER, arg_i: usize) callconv(.c) ?*const SSL_CIPHER { - const sk = arg_sk; - const i = arg_i; - return @as(?*const SSL_CIPHER, @ptrCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i))); -} -pub fn sk_SSL_CIPHER_set(arg_sk: ?*struct_stack_st_SSL_CIPHER, arg_i: usize, arg_p: ?*const SSL_CIPHER) callconv(.c) ?*const SSL_CIPHER { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as(?*const SSL_CIPHER, @ptrCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(p))))))); -} -pub fn sk_SSL_CIPHER_free(arg_sk: ?*struct_stack_st_SSL_CIPHER) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_CIPHER_pop_free(arg_sk: ?*struct_stack_st_SSL_CIPHER, arg_free_func: sk_SSL_CIPHER_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_SSL_CIPHER_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_SSL_CIPHER_insert(arg_sk: ?*struct_stack_st_SSL_CIPHER, arg_p: ?*const SSL_CIPHER, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(p)))), where); -} -pub fn sk_SSL_CIPHER_delete(arg_sk: ?*struct_stack_st_SSL_CIPHER, arg_where: usize) callconv(.c) ?*const SSL_CIPHER { - const sk = arg_sk; - const where = arg_where; - return @as(?*const SSL_CIPHER, @ptrCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where))); -} -pub fn sk_SSL_CIPHER_delete_ptr(arg_sk: ?*struct_stack_st_SSL_CIPHER, arg_p: ?*const SSL_CIPHER) callconv(.c) ?*const SSL_CIPHER { - const sk = arg_sk; - const p = arg_p; - return @as(?*const SSL_CIPHER, @ptrCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p))))); -} -pub fn sk_SSL_CIPHER_find(arg_sk: ?*const struct_stack_st_SSL_CIPHER, arg_out_index: [*c]usize, arg_p: ?*const SSL_CIPHER) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_SSL_CIPHER_call_cmp_func); -} -pub fn sk_SSL_CIPHER_shift(arg_sk: ?*struct_stack_st_SSL_CIPHER) callconv(.c) ?*const SSL_CIPHER { - const sk = arg_sk; - return @as(?*const SSL_CIPHER, @ptrCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_SSL_CIPHER_push(arg_sk: ?*struct_stack_st_SSL_CIPHER, arg_p: ?*const SSL_CIPHER) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(p))))); -} -pub fn sk_SSL_CIPHER_pop(arg_sk: ?*struct_stack_st_SSL_CIPHER) callconv(.c) ?*const SSL_CIPHER { - const sk = arg_sk; - return @as(?*const SSL_CIPHER, @ptrCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_SSL_CIPHER_dup(arg_sk: ?*const struct_stack_st_SSL_CIPHER) callconv(.c) ?*struct_stack_st_SSL_CIPHER { - const sk = arg_sk; - return @as(?*struct_stack_st_SSL_CIPHER, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_SSL_CIPHER_sort(arg_sk: ?*struct_stack_st_SSL_CIPHER) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_SSL_CIPHER_call_cmp_func); -} -pub fn sk_SSL_CIPHER_is_sorted(arg_sk: ?*const struct_stack_st_SSL_CIPHER) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_CIPHER_set_cmp_func(arg_sk: ?*struct_stack_st_SSL_CIPHER, arg_comp: sk_SSL_CIPHER_cmp_func) callconv(.c) sk_SSL_CIPHER_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_SSL_CIPHER_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_SSL_CIPHER_deep_copy(arg_sk: ?*const struct_stack_st_SSL_CIPHER, arg_copy_func: sk_SSL_CIPHER_copy_func, arg_free_func: sk_SSL_CIPHER_free_func) callconv(.c) ?*struct_stack_st_SSL_CIPHER { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_SSL_CIPHER, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_SSL_CIPHER_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_SSL_CIPHER_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn SSL_get_cipher_by_value(value: u16) ?*const SSL_CIPHER; -pub extern fn SSL_CIPHER_get_id(cipher: ?*const SSL_CIPHER) u32; -pub extern fn SSL_CIPHER_get_protocol_id(cipher: ?*const SSL_CIPHER) u16; -pub extern fn SSL_CIPHER_is_aead(cipher: ?*const SSL_CIPHER) c_int; -pub extern fn SSL_CIPHER_is_block_cipher(cipher: ?*const SSL_CIPHER) c_int; -pub extern fn SSL_CIPHER_get_cipher_nid(cipher: ?*const SSL_CIPHER) c_int; -pub extern fn SSL_CIPHER_get_digest_nid(cipher: ?*const SSL_CIPHER) c_int; -pub extern fn SSL_CIPHER_get_kx_nid(cipher: ?*const SSL_CIPHER) c_int; -pub extern fn SSL_CIPHER_get_auth_nid(cipher: ?*const SSL_CIPHER) c_int; -pub extern fn SSL_CIPHER_get_prf_nid(cipher: ?*const SSL_CIPHER) c_int; -pub extern fn SSL_CIPHER_get_min_version(cipher: ?*const SSL_CIPHER) u16; -pub extern fn SSL_CIPHER_get_max_version(cipher: ?*const SSL_CIPHER) u16; -pub extern fn SSL_CIPHER_standard_name(cipher: ?*const SSL_CIPHER) [*c]const u8; -pub extern fn SSL_CIPHER_get_name(cipher: ?*const SSL_CIPHER) [*c]const u8; -pub extern fn SSL_CIPHER_get_kx_name(cipher: ?*const SSL_CIPHER) [*c]const u8; -pub extern fn SSL_CIPHER_get_bits(cipher: ?*const SSL_CIPHER, out_alg_bits: [*c]c_int) c_int; -pub extern fn SSL_CTX_set_strict_cipher_list(ctx: ?*SSL_CTX, str: [*c]const u8) c_int; -pub extern fn SSL_CTX_set_cipher_list(ctx: ?*SSL_CTX, str: [*c]const u8) c_int; -pub extern fn SSL_set_strict_cipher_list(ssl: ?*SSL, str: [*c]const u8) c_int; -pub extern fn SSL_set_cipher_list(ssl: ?*SSL, str: [*c]const u8) c_int; -pub extern fn SSL_CTX_get_ciphers(ctx: ?*const SSL_CTX) ?*struct_stack_st_SSL_CIPHER; -pub extern fn SSL_CTX_cipher_in_group(ctx: ?*const SSL_CTX, i: usize) c_int; -pub extern fn SSL_get_ciphers(ssl: ?*const SSL) ?*struct_stack_st_SSL_CIPHER; -pub extern fn SSL_is_init_finished(ssl: ?*const SSL) c_int; -pub extern fn SSL_in_init(ssl: ?*const SSL) c_int; -pub extern fn SSL_in_false_start(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_peer_certificate(ssl: ?*const SSL) ?*X509; -pub extern fn SSL_get_peer_cert_chain(ssl: ?*const SSL) ?*struct_stack_st_X509; -pub extern fn SSL_get_peer_full_cert_chain(ssl: ?*const SSL) ?*struct_stack_st_X509; -pub extern fn SSL_get0_peer_certificates(ssl: ?*const SSL) ?*const struct_stack_st_CRYPTO_BUFFER; -pub extern fn SSL_get0_signed_cert_timestamp_list(ssl: ?*const SSL, out: [*c][*c]const u8, out_len: [*c]usize) void; -pub extern fn SSL_get0_ocsp_response(ssl: ?*const SSL, out: [*c][*c]const u8, out_len: [*c]usize) void; -pub extern fn SSL_get_tls_unique(ssl: ?*const SSL, out: [*c]u8, out_len: [*c]usize, max_out: usize) c_int; -pub extern fn SSL_get_extms_support(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_current_cipher(ssl: ?*const SSL) ?*const SSL_CIPHER; -pub extern fn SSL_session_reused(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_secure_renegotiation_support(ssl: ?*const SSL) c_int; -pub extern fn SSL_export_keying_material(ssl: ?*SSL, out: [*c]u8, out_len: usize, label: [*c]const u8, label_len: usize, context: [*c]const u8, context_len: usize, use_context: c_int) c_int; -pub extern fn PEM_read_bio_SSL_SESSION(bp: [*c]BIO, x: [*c]?*SSL_SESSION, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*SSL_SESSION; -// pub extern fn PEM_read_SSL_SESSION(fp: [*c]FILE, x: [*c]?*SSL_SESSION, cb: ?*const pem_password_cb, u: ?*anyopaque) ?*SSL_SESSION; -pub extern fn PEM_write_bio_SSL_SESSION(bp: [*c]BIO, x: ?*SSL_SESSION) c_int; -// pub extern fn PEM_write_SSL_SESSION(fp: [*c]FILE, x: ?*SSL_SESSION) c_int; -pub extern fn SSL_SESSION_new(ctx: ?*const SSL_CTX) ?*SSL_SESSION; -pub extern fn SSL_SESSION_up_ref(session: ?*SSL_SESSION) c_int; -pub extern fn SSL_SESSION_free(session: ?*SSL_SESSION) void; -pub extern fn SSL_SESSION_to_bytes(in: ?*const SSL_SESSION, out_data: [*c][*c]u8, out_len: [*c]usize) c_int; -pub extern fn SSL_SESSION_to_bytes_for_ticket(in: ?*const SSL_SESSION, out_data: [*c][*c]u8, out_len: [*c]usize) c_int; -pub extern fn SSL_SESSION_from_bytes(in: [*c]const u8, in_len: usize, ctx: ?*const SSL_CTX) ?*SSL_SESSION; -pub extern fn SSL_SESSION_get_version(session: ?*const SSL_SESSION) [*c]const u8; -pub extern fn SSL_SESSION_get_protocol_version(session: ?*const SSL_SESSION) u16; -pub extern fn SSL_SESSION_set_protocol_version(session: ?*SSL_SESSION, version: u16) c_int; -pub extern fn SSL_SESSION_get_id(session: ?*const SSL_SESSION, out_len: [*c]c_uint) [*c]const u8; -pub extern fn SSL_SESSION_set1_id(session: ?*SSL_SESSION, sid: [*c]const u8, sid_len: usize) c_int; -pub extern fn SSL_SESSION_get_time(session: ?*const SSL_SESSION) u64; -pub extern fn SSL_SESSION_get_timeout(session: ?*const SSL_SESSION) u32; -pub extern fn SSL_SESSION_get0_peer(session: ?*const SSL_SESSION) ?*X509; -pub extern fn SSL_SESSION_get0_peer_certificates(session: ?*const SSL_SESSION) ?*const struct_stack_st_CRYPTO_BUFFER; -pub extern fn SSL_SESSION_get0_signed_cert_timestamp_list(session: ?*const SSL_SESSION, out: [*c][*c]const u8, out_len: [*c]usize) void; -pub extern fn SSL_SESSION_get0_ocsp_response(session: ?*const SSL_SESSION, out: [*c][*c]const u8, out_len: [*c]usize) void; -pub extern fn SSL_SESSION_get_master_key(session: ?*const SSL_SESSION, out: [*c]u8, max_out: usize) usize; -pub extern fn SSL_SESSION_set_time(session: ?*SSL_SESSION, time: u64) u64; -pub extern fn SSL_SESSION_set_timeout(session: ?*SSL_SESSION, timeout: u32) u32; -pub extern fn SSL_SESSION_get0_id_context(session: ?*const SSL_SESSION, out_len: [*c]c_uint) [*c]const u8; -pub extern fn SSL_SESSION_set1_id_context(session: ?*SSL_SESSION, sid_ctx: [*c]const u8, sid_ctx_len: usize) c_int; -pub extern fn SSL_SESSION_should_be_single_use(session: ?*const SSL_SESSION) c_int; -pub extern fn SSL_SESSION_is_resumable(session: ?*const SSL_SESSION) c_int; -pub extern fn SSL_SESSION_has_ticket(session: ?*const SSL_SESSION) c_int; -pub extern fn SSL_SESSION_get0_ticket(session: ?*const SSL_SESSION, out_ticket: [*c][*c]const u8, out_len: [*c]usize) void; -pub extern fn SSL_SESSION_set_ticket(session: ?*SSL_SESSION, ticket: [*c]const u8, ticket_len: usize) c_int; -pub extern fn SSL_SESSION_get_ticket_lifetime_hint(session: ?*const SSL_SESSION) u32; -pub extern fn SSL_SESSION_get0_cipher(session: ?*const SSL_SESSION) ?*const SSL_CIPHER; -pub extern fn SSL_SESSION_has_peer_sha256(session: ?*const SSL_SESSION) c_int; -pub extern fn SSL_SESSION_get0_peer_sha256(session: ?*const SSL_SESSION, out_ptr: [*c][*c]const u8, out_len: [*c]usize) void; -pub extern fn SSL_CTX_set_session_cache_mode(ctx: ?*SSL_CTX, mode: c_int) c_int; -pub extern fn SSL_CTX_get_session_cache_mode(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_set_session(ssl: ?*SSL, session: ?*SSL_SESSION) c_int; -pub extern fn SSL_CTX_set_timeout(ctx: ?*SSL_CTX, timeout: u32) u32; -pub extern fn SSL_CTX_set_session_psk_dhe_timeout(ctx: ?*SSL_CTX, timeout: u32) void; -pub extern fn SSL_CTX_get_timeout(ctx: ?*const SSL_CTX) u32; -pub extern fn SSL_CTX_set_session_id_context(ctx: ?*SSL_CTX, sid_ctx: [*c]const u8, sid_ctx_len: usize) c_int; -pub extern fn SSL_set_session_id_context(ssl: ?*SSL, sid_ctx: [*c]const u8, sid_ctx_len: usize) c_int; -pub extern fn SSL_get0_session_id_context(ssl: ?*const SSL, out_len: [*c]usize) [*c]const u8; -pub extern fn SSL_CTX_sess_set_cache_size(ctx: ?*SSL_CTX, size: c_ulong) c_ulong; -pub extern fn SSL_CTX_sess_get_cache_size(ctx: ?*const SSL_CTX) c_ulong; -pub extern fn SSL_CTX_sess_number(ctx: ?*const SSL_CTX) usize; -pub extern fn SSL_CTX_add_session(ctx: ?*SSL_CTX, session: ?*SSL_SESSION) c_int; -pub extern fn SSL_CTX_remove_session(ctx: ?*SSL_CTX, session: ?*SSL_SESSION) c_int; -pub extern fn SSL_CTX_flush_sessions(ctx: ?*SSL_CTX, time: u64) void; -pub extern fn SSL_CTX_sess_set_new_cb(ctx: ?*SSL_CTX, new_session_cb: ?*const fn (?*SSL, ?*SSL_SESSION) callconv(.c) c_int) void; -pub extern fn SSL_CTX_sess_get_new_cb(ctx: ?*SSL_CTX) ?*const fn (?*SSL, ?*SSL_SESSION) callconv(.c) c_int; -pub extern fn SSL_CTX_sess_set_remove_cb(ctx: ?*SSL_CTX, remove_session_cb: ?*const fn (?*SSL_CTX, ?*SSL_SESSION) callconv(.c) void) void; -pub extern fn SSL_CTX_sess_get_remove_cb(ctx: ?*SSL_CTX) ?*const fn (?*SSL_CTX, ?*SSL_SESSION) callconv(.c) void; -pub extern fn SSL_CTX_sess_set_get_cb(ctx: ?*SSL_CTX, get_session_cb: ?*const fn (?*SSL, [*c]const u8, c_int, [*c]c_int) callconv(.c) ?*SSL_SESSION) void; -pub extern fn SSL_CTX_sess_get_get_cb(ctx: ?*SSL_CTX) ?*const fn (?*SSL, [*c]const u8, c_int, [*c]c_int) callconv(.c) ?*SSL_SESSION; -pub extern fn SSL_magic_pending_session_ptr() ?*SSL_SESSION; -pub extern fn SSL_CTX_get_tlsext_ticket_keys(ctx: ?*SSL_CTX, out: ?*anyopaque, len: usize) c_int; -pub extern fn SSL_CTX_set_tlsext_ticket_keys(ctx: ?*SSL_CTX, in: ?*const anyopaque, len: usize) c_int; -pub extern fn SSL_CTX_set_tlsext_ticket_key_cb(ctx: ?*SSL_CTX, callback: ?*const fn (?*SSL, [*c]u8, [*c]u8, [*c]EVP_CIPHER_CTX, [*c]HMAC_CTX, c_int) callconv(.c) c_int) c_int; -pub extern fn SSL_CTX_set_ticket_aead_method(ctx: ?*SSL_CTX, aead_method: [*c]const SSL_TICKET_AEAD_METHOD) void; -pub extern fn SSL_process_tls13_new_session_ticket(ssl: ?*SSL, buf: [*c]const u8, buf_len: usize) ?*SSL_SESSION; -pub extern fn SSL_CTX_set_num_tickets(ctx: ?*SSL_CTX, num_tickets: usize) c_int; -pub extern fn SSL_CTX_get_num_tickets(ctx: ?*const SSL_CTX) usize; -pub extern fn SSL_CTX_set1_curves(ctx: ?*SSL_CTX, curves: [*c]const c_int, curves_len: usize) c_int; -pub extern fn SSL_set1_curves(ssl: ?*SSL, curves: [*c]const c_int, curves_len: usize) c_int; -pub extern fn SSL_CTX_set1_curves_list(ctx: ?*SSL_CTX, curves: [*c]const u8) c_int; -pub extern fn SSL_set1_curves_list(ssl: ?*SSL, curves: [*c]const u8) c_int; -pub extern fn SSL_get_curve_id(ssl: ?*const SSL) u16; -pub extern fn SSL_get_curve_name(curve_id: u16) [*c]const u8; -pub extern fn SSL_CTX_set1_groups(ctx: ?*SSL_CTX, groups: [*c]const c_int, groups_len: usize) c_int; -pub extern fn SSL_set1_groups(ssl: ?*SSL, groups: [*c]const c_int, groups_len: usize) c_int; -pub extern fn SSL_CTX_set1_groups_list(ctx: ?*SSL_CTX, groups: [*c]const u8) c_int; -pub extern fn SSL_set1_groups_list(ssl: ?*SSL, groups: [*c]const u8) c_int; -pub extern fn SSL_CTX_set_verify(ctx: ?*SSL_CTX, mode: c_int, callback: ?*const fn (c_int, ?*X509_STORE_CTX) callconv(.c) c_int) void; -pub extern fn SSL_set_verify(ssl: ?*SSL, mode: c_int, callback: ?*const fn (c_int, ?*X509_STORE_CTX) callconv(.c) c_int) void; -pub const ssl_verify_ok: c_int = 0; -pub const ssl_verify_invalid: c_int = 1; -pub const ssl_verify_retry: c_int = 2; -pub extern fn SSL_set_custom_verify(ssl: ?*SSL, mode: c_int, callback: ?*const fn (?*SSL, [*c]u8) callconv(.c) enum_ssl_verify_result_t) void; -pub extern fn SSL_CTX_get_verify_mode(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_get_verify_mode(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_get_verify_callback(ctx: ?*const SSL_CTX) ?*const fn (c_int, ?*X509_STORE_CTX) callconv(.c) c_int; -pub extern fn SSL_get_verify_callback(ssl: ?*const SSL) ?*const fn (c_int, ?*X509_STORE_CTX) callconv(.c) c_int; -pub extern fn SSL_set1_host(ssl: ?*SSL, hostname: [*c]const u8) c_int; -pub extern fn SSL_CTX_set_verify_depth(ctx: ?*SSL_CTX, depth: c_int) void; -pub extern fn SSL_set_verify_depth(ssl: ?*SSL, depth: c_int) void; -pub extern fn SSL_CTX_get_verify_depth(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_get_verify_depth(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_set1_param(ctx: ?*SSL_CTX, param: ?*const X509_VERIFY_PARAM) c_int; -pub extern fn SSL_set1_param(ssl: ?*SSL, param: ?*const X509_VERIFY_PARAM) c_int; -pub extern fn SSL_CTX_get0_param(ctx: ?*SSL_CTX) ?*X509_VERIFY_PARAM; -pub extern fn SSL_get0_param(ssl: ?*SSL) ?*X509_VERIFY_PARAM; -pub extern fn SSL_CTX_set_purpose(ctx: ?*SSL_CTX, purpose: c_int) c_int; -pub extern fn SSL_set_purpose(ssl: ?*SSL, purpose: c_int) c_int; -pub extern fn SSL_CTX_set_trust(ctx: ?*SSL_CTX, trust: c_int) c_int; -pub extern fn SSL_set_trust(ssl: ?*SSL, trust: c_int) c_int; -pub extern fn SSL_CTX_set_cert_store(ctx: ?*SSL_CTX, store: ?*X509_STORE) void; -pub extern fn SSL_CTX_get_cert_store(ctx: ?*const SSL_CTX) ?*X509_STORE; -pub extern fn SSL_CTX_set_default_verify_paths(ctx: ?*SSL_CTX) c_int; -// pub extern fn SSL_CTX_load_verify_locations(ctx: ?*SSL_CTX, ca_file: [*c]const u8, ca_dir: [*c]const u8) c_int; -pub extern fn SSL_get_verify_result(ssl: ?*const SSL) c_long; -pub extern fn SSL_alert_from_verify_result(result: c_long) c_int; -pub extern fn SSL_get_ex_data_X509_STORE_CTX_idx() c_int; -pub extern fn SSL_CTX_set_cert_verify_callback(ctx: ?*SSL_CTX, callback: ?*const fn (?*X509_STORE_CTX, ?*anyopaque) callconv(.c) c_int, arg: ?*anyopaque) void; -pub extern fn SSL_enable_signed_cert_timestamps(ssl: ?*SSL) void; -pub extern fn SSL_CTX_enable_signed_cert_timestamps(ctx: ?*SSL_CTX) void; -pub extern fn SSL_enable_ocsp_stapling(ssl: ?*SSL) void; -pub extern fn SSL_CTX_enable_ocsp_stapling(ctx: ?*SSL_CTX) void; -pub extern fn SSL_CTX_set0_verify_cert_store(ctx: ?*SSL_CTX, store: ?*X509_STORE) c_int; -pub extern fn SSL_CTX_set1_verify_cert_store(ctx: ?*SSL_CTX, store: ?*X509_STORE) c_int; -pub extern fn SSL_set0_verify_cert_store(ssl: ?*SSL, store: ?*X509_STORE) c_int; -pub extern fn SSL_set1_verify_cert_store(ssl: ?*SSL, store: ?*X509_STORE) c_int; -pub extern fn SSL_CTX_set_verify_algorithm_prefs(ctx: ?*SSL_CTX, prefs: [*c]const u16, num_prefs: usize) c_int; -pub extern fn SSL_set_verify_algorithm_prefs(ssl: ?*SSL, prefs: [*c]const u16, num_prefs: usize) c_int; -pub extern fn SSL_set_hostflags(ssl: ?*SSL, flags: c_uint) void; -pub extern fn SSL_set_client_CA_list(ssl: ?*SSL, name_list: ?*struct_stack_st_X509_NAME) void; -pub extern fn SSL_CTX_set_client_CA_list(ctx: ?*SSL_CTX, name_list: ?*struct_stack_st_X509_NAME) void; -pub extern fn SSL_set0_client_CAs(ssl: ?*SSL, name_list: ?*struct_stack_st_CRYPTO_BUFFER) void; -pub extern fn SSL_CTX_set0_client_CAs(ctx: ?*SSL_CTX, name_list: ?*struct_stack_st_CRYPTO_BUFFER) void; -pub extern fn SSL_get_client_CA_list(ssl: ?*const SSL) ?*struct_stack_st_X509_NAME; -pub extern fn SSL_get0_server_requested_CAs(ssl: ?*const SSL) ?*const struct_stack_st_CRYPTO_BUFFER; -pub extern fn SSL_CTX_get_client_CA_list(ctx: ?*const SSL_CTX) ?*struct_stack_st_X509_NAME; -pub extern fn SSL_add_client_CA(ssl: ?*SSL, x509: ?*X509) c_int; -pub extern fn SSL_CTX_add_client_CA(ctx: ?*SSL_CTX, x509: ?*X509) c_int; -// pub extern fn SSL_load_client_CA_file(file: [*c]const u8) ?*struct_stack_st_X509_NAME; -pub extern fn SSL_dup_CA_list(list: ?*struct_stack_st_X509_NAME) ?*struct_stack_st_X509_NAME; -// pub extern fn SSL_add_file_cert_subjects_to_stack(out: ?*struct_stack_st_X509_NAME, file: [*c]const u8) c_int; -pub extern fn SSL_add_bio_cert_subjects_to_stack(out: ?*struct_stack_st_X509_NAME, bio: [*c]BIO) c_int; -pub extern fn SSL_set_tlsext_host_name(ssl: ?*SSL, name: [*c]const u8) c_int; -pub extern fn SSL_get_servername(ssl: ?*const SSL, @"type": c_int) [*c]const u8; -pub extern fn SSL_get_servername_type(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_set_tlsext_servername_callback(ctx: ?*SSL_CTX, callback: ?*const fn (?*SSL, [*c]c_int, ?*anyopaque) callconv(.c) c_int) c_int; -pub extern fn SSL_CTX_set_tlsext_servername_arg(ctx: ?*SSL_CTX, arg: ?*anyopaque) c_int; -pub extern fn SSL_set_SSL_CTX(ssl: ?*SSL, ctx: ?*SSL_CTX) ?*SSL_CTX; -pub extern fn SSL_CTX_set_alpn_protos(ctx: ?*SSL_CTX, protos: [*c]const u8, protos_len: usize) c_int; -pub extern fn SSL_set_alpn_protos(ssl: ?*SSL, protos: [*c]const u8, protos_len: usize) c_int; -pub extern fn SSL_CTX_set_alpn_select_cb(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, [*c][*c]const u8, [*c]u8, [*c]const u8, c_uint, ?*anyopaque) callconv(.c) c_int, arg: ?*anyopaque) void; -pub extern fn SSL_get0_alpn_selected(ssl: ?*const SSL, out_data: [*c][*c]const u8, out_len: [*c]c_uint) void; -pub extern fn SSL_CTX_set_allow_unknown_alpn_protos(ctx: ?*SSL_CTX, enabled: c_int) void; -pub extern fn SSL_add_application_settings(ssl: ?*SSL, proto: [*c]const u8, proto_len: usize, settings: [*c]const u8, settings_len: usize) c_int; -pub extern fn SSL_get0_peer_application_settings(ssl: ?*const SSL, out_data: [*c][*c]const u8, out_len: [*c]usize) void; -pub extern fn SSL_has_application_settings(ssl: ?*const SSL) c_int; -pub const ssl_cert_compression_func_t = ?*const fn (?*SSL, ?*CBB, [*c]const u8, usize) callconv(.c) c_int; -pub const ssl_cert_decompression_func_t = ?*const fn (?*SSL, [*c]?*CRYPTO_BUFFER, usize, [*c]const u8, usize) callconv(.c) c_int; -pub extern fn SSL_CTX_add_cert_compression_alg(ctx: ?*SSL_CTX, alg_id: u16, compress: ssl_cert_compression_func_t, decompress: ssl_cert_decompression_func_t) c_int; -pub extern fn SSL_CTX_set_next_protos_advertised_cb(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, [*c][*c]const u8, [*c]c_uint, ?*anyopaque) callconv(.c) c_int, arg: ?*anyopaque) void; -pub extern fn SSL_CTX_set_next_proto_select_cb(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, [*c][*c]u8, [*c]u8, [*c]const u8, c_uint, ?*anyopaque) callconv(.c) c_int, arg: ?*anyopaque) void; -pub extern fn SSL_get0_next_proto_negotiated(ssl: ?*const SSL, out_data: [*c][*c]const u8, out_len: [*c]c_uint) void; -pub extern fn SSL_select_next_proto(out: [*c][*c]u8, out_len: [*c]u8, peer: [*c]const u8, peer_len: c_uint, supported: [*c]const u8, supported_len: c_uint) c_int; -pub extern fn SSL_CTX_set_tls_channel_id_enabled(ctx: ?*SSL_CTX, enabled: c_int) void; -pub extern fn SSL_set_tls_channel_id_enabled(ssl: ?*SSL, enabled: c_int) void; -pub extern fn SSL_CTX_set1_tls_channel_id(ctx: ?*SSL_CTX, private_key: [*c]EVP_PKEY) c_int; -pub extern fn SSL_set1_tls_channel_id(ssl: ?*SSL, private_key: [*c]EVP_PKEY) c_int; -pub extern fn SSL_get_tls_channel_id(ssl: ?*SSL, out: [*c]u8, max_out: usize) usize; -pub const struct_stack_st_SRTP_PROTECTION_PROFILE = opaque {}; -pub const sk_SRTP_PROTECTION_PROFILE_free_func = ?*const fn ([*c]const SRTP_PROTECTION_PROFILE) callconv(.c) void; -pub const sk_SRTP_PROTECTION_PROFILE_copy_func = ?*const fn ([*c]const SRTP_PROTECTION_PROFILE) callconv(.c) [*c]const SRTP_PROTECTION_PROFILE; -pub const sk_SRTP_PROTECTION_PROFILE_cmp_func = ?*const fn ([*c][*c]const SRTP_PROTECTION_PROFILE, [*c][*c]const SRTP_PROTECTION_PROFILE) callconv(.c) c_int; -pub fn sk_SRTP_PROTECTION_PROFILE_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_SRTP_PROTECTION_PROFILE_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(@as(sk_SRTP_PROTECTION_PROFILE_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(ptr)))))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const SRTP_PROTECTION_PROFILE = @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const SRTP_PROTECTION_PROFILE = @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(b.*))); - return @as(sk_SRTP_PROTECTION_PROFILE_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_SRTP_PROTECTION_PROFILE_new(arg_comp: sk_SRTP_PROTECTION_PROFILE_cmp_func) callconv(.c) ?*struct_stack_st_SRTP_PROTECTION_PROFILE { - const comp = arg_comp; - return @as(?*struct_stack_st_SRTP_PROTECTION_PROFILE, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_new_null() callconv(.c) ?*struct_stack_st_SRTP_PROTECTION_PROFILE { - return @as(?*struct_stack_st_SRTP_PROTECTION_PROFILE, @ptrCast(sk_new_null())); -} -pub fn sk_SRTP_PROTECTION_PROFILE_num(arg_sk: ?*const struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_zero(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_value(arg_sk: ?*const struct_stack_st_SRTP_PROTECTION_PROFILE, arg_i: usize) callconv(.c) [*c]const SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - const i = arg_i; - return @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_set(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE, arg_i: usize, arg_p: [*c]const SRTP_PROTECTION_PROFILE) callconv(.c) [*c]const SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(p)))))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_free(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_pop_free(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE, arg_free_func: sk_SRTP_PROTECTION_PROFILE_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_SRTP_PROTECTION_PROFILE_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_insert(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE, arg_p: [*c]const SRTP_PROTECTION_PROFILE, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(p)))), where); -} -pub fn sk_SRTP_PROTECTION_PROFILE_delete(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE, arg_where: usize) callconv(.c) [*c]const SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - const where = arg_where; - return @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_delete_ptr(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE, arg_p: [*c]const SRTP_PROTECTION_PROFILE) callconv(.c) [*c]const SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - const p = arg_p; - return @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_find(arg_sk: ?*const struct_stack_st_SRTP_PROTECTION_PROFILE, arg_out_index: [*c]usize, arg_p: [*c]const SRTP_PROTECTION_PROFILE) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_SRTP_PROTECTION_PROFILE_call_cmp_func); -} -pub fn sk_SRTP_PROTECTION_PROFILE_shift(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) [*c]const SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - return @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_push(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE, arg_p: [*c]const SRTP_PROTECTION_PROFILE) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(@constCast(@volatileCast(p))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_pop(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) [*c]const SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - return @as([*c]const SRTP_PROTECTION_PROFILE, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_dup(arg_sk: ?*const struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) ?*struct_stack_st_SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - return @as(?*struct_stack_st_SRTP_PROTECTION_PROFILE, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_sort(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_SRTP_PROTECTION_PROFILE_call_cmp_func); -} -pub fn sk_SRTP_PROTECTION_PROFILE_is_sorted(arg_sk: ?*const struct_stack_st_SRTP_PROTECTION_PROFILE) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_set_cmp_func(arg_sk: ?*struct_stack_st_SRTP_PROTECTION_PROFILE, arg_comp: sk_SRTP_PROTECTION_PROFILE_cmp_func) callconv(.c) sk_SRTP_PROTECTION_PROFILE_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_SRTP_PROTECTION_PROFILE_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_SRTP_PROTECTION_PROFILE_deep_copy(arg_sk: ?*const struct_stack_st_SRTP_PROTECTION_PROFILE, arg_copy_func: sk_SRTP_PROTECTION_PROFILE_copy_func, arg_free_func: sk_SRTP_PROTECTION_PROFILE_free_func) callconv(.c) ?*struct_stack_st_SRTP_PROTECTION_PROFILE { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_SRTP_PROTECTION_PROFILE, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_SRTP_PROTECTION_PROFILE_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_SRTP_PROTECTION_PROFILE_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -// pub extern fn SSL_CTX_set_srtp_profiles(ctx: ?*SSL_CTX, profiles: [*c]const u8) c_int; -// pub extern fn SSL_set_srtp_profiles(ssl: ?*SSL, profiles: [*c]const u8) c_int; -// pub extern fn SSL_get_srtp_profiles(ssl: ?*const SSL) ?*const struct_stack_st_SRTP_PROTECTION_PROFILE; -// pub extern fn SSL_get_selected_srtp_profile(ssl: ?*SSL) [*c]const SRTP_PROTECTION_PROFILE; -pub extern fn SSL_CTX_set_psk_client_callback(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, [*c]const u8, [*c]u8, c_uint, [*c]u8, c_uint) callconv(.c) c_uint) void; -pub extern fn SSL_set_psk_client_callback(ssl: ?*SSL, cb: ?*const fn (?*SSL, [*c]const u8, [*c]u8, c_uint, [*c]u8, c_uint) callconv(.c) c_uint) void; -pub extern fn SSL_CTX_set_psk_server_callback(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, [*c]const u8, [*c]u8, c_uint) callconv(.c) c_uint) void; -pub extern fn SSL_set_psk_server_callback(ssl: ?*SSL, cb: ?*const fn (?*SSL, [*c]const u8, [*c]u8, c_uint) callconv(.c) c_uint) void; -pub extern fn SSL_CTX_use_psk_identity_hint(ctx: ?*SSL_CTX, identity_hint: [*c]const u8) c_int; -pub extern fn SSL_use_psk_identity_hint(ssl: ?*SSL, identity_hint: [*c]const u8) c_int; -pub extern fn SSL_get_psk_identity_hint(ssl: ?*const SSL) [*c]const u8; -pub extern fn SSL_get_psk_identity(ssl: ?*const SSL) [*c]const u8; -pub extern fn SSL_set1_delegated_credential(ssl: ?*SSL, dc: ?*CRYPTO_BUFFER, pkey: [*c]EVP_PKEY, key_method: [*c]const SSL_PRIVATE_KEY_METHOD) c_int; -pub extern fn SSL_delegated_credential_used(ssl: ?*const SSL) c_int; -pub extern fn SSL_quic_max_handshake_flight_len(ssl: ?*const SSL, level: enum_ssl_encryption_level_t) usize; -pub extern fn SSL_quic_read_level(ssl: ?*const SSL) enum_ssl_encryption_level_t; -pub extern fn SSL_quic_write_level(ssl: ?*const SSL) enum_ssl_encryption_level_t; -pub extern fn SSL_provide_quic_data(ssl: ?*SSL, level: enum_ssl_encryption_level_t, data: [*c]const u8, len: usize) c_int; -pub extern fn SSL_process_quic_post_handshake(ssl: ?*SSL) c_int; -pub extern fn SSL_CTX_set_quic_method(ctx: ?*SSL_CTX, quic_method: [*c]const SSL_QUIC_METHOD) c_int; -pub extern fn SSL_set_quic_method(ssl: ?*SSL, quic_method: [*c]const SSL_QUIC_METHOD) c_int; -pub extern fn SSL_set_quic_transport_params(ssl: ?*SSL, params: [*c]const u8, params_len: usize) c_int; -pub extern fn SSL_get_peer_quic_transport_params(ssl: ?*const SSL, out_params: [*c][*c]const u8, out_params_len: [*c]usize) void; -pub extern fn SSL_set_quic_use_legacy_codepoint(ssl: ?*SSL, use_legacy: c_int) void; -pub extern fn SSL_set_quic_early_data_context(ssl: ?*SSL, context: [*c]const u8, context_len: usize) c_int; -pub extern fn SSL_CTX_set_early_data_enabled(ctx: ?*SSL_CTX, enabled: c_int) void; -pub extern fn SSL_set_early_data_enabled(ssl: ?*SSL, enabled: c_int) void; -pub extern fn SSL_in_early_data(ssl: ?*const SSL) c_int; -pub extern fn SSL_SESSION_early_data_capable(session: ?*const SSL_SESSION) c_int; -pub extern fn SSL_SESSION_copy_without_early_data(session: ?*SSL_SESSION) ?*SSL_SESSION; -pub extern fn SSL_early_data_accepted(ssl: ?*const SSL) c_int; -pub extern fn SSL_reset_early_data_reject(ssl: ?*SSL) void; -pub extern fn SSL_get_ticket_age_skew(ssl: ?*const SSL) i32; -pub const ssl_early_data_unknown: c_int = 0; -pub const ssl_early_data_disabled: c_int = 1; -pub const ssl_early_data_accepted: c_int = 2; -pub const ssl_early_data_protocol_version: c_int = 3; -pub const ssl_early_data_peer_declined: c_int = 4; -pub const ssl_early_data_no_session_offered: c_int = 5; -pub const ssl_early_data_session_not_resumed: c_int = 6; -pub const ssl_early_data_unsupported_for_session: c_int = 7; -pub const ssl_early_data_hello_retry_request: c_int = 8; -pub const ssl_early_data_alpn_mismatch: c_int = 9; -pub const ssl_early_data_channel_id: c_int = 10; -pub const ssl_early_data_ticket_age_skew: c_int = 12; -pub const ssl_early_data_quic_parameter_mismatch: c_int = 13; -pub const ssl_early_data_alps_mismatch: c_int = 14; -pub const ssl_early_data_reason_max_value: c_int = 14; -pub const enum_ssl_early_data_reason_t = c_uint; -pub extern fn SSL_get_early_data_reason(ssl: ?*const SSL) enum_ssl_early_data_reason_t; -pub extern fn SSL_early_data_reason_string(reason: enum_ssl_early_data_reason_t) [*c]const u8; -pub extern fn SSL_set_enable_ech_grease(ssl: ?*SSL, enable: c_int) void; -pub extern fn SSL_set1_ech_config_list(ssl: ?*SSL, ech_config_list: [*c]const u8, ech_config_list_len: usize) c_int; -pub extern fn SSL_get0_ech_name_override(ssl: ?*const SSL, out_name: [*c][*c]const u8, out_name_len: [*c]usize) void; -pub extern fn SSL_get0_ech_retry_configs(ssl: ?*const SSL, out_retry_configs: [*c][*c]const u8, out_retry_configs_len: [*c]usize) void; -pub extern fn SSL_marshal_ech_config(out: [*c][*c]u8, out_len: [*c]usize, config_id: u8, key: ?*const EVP_HPKE_KEY, public_name: [*c]const u8, max_name_len: usize) c_int; -pub extern fn SSL_ECH_KEYS_new() ?*SSL_ECH_KEYS; -pub extern fn SSL_ECH_KEYS_up_ref(keys: ?*SSL_ECH_KEYS) void; -pub extern fn SSL_ECH_KEYS_free(keys: ?*SSL_ECH_KEYS) void; -pub extern fn SSL_ECH_KEYS_add(keys: ?*SSL_ECH_KEYS, is_retry_config: c_int, ech_config: [*c]const u8, ech_config_len: usize, key: ?*const EVP_HPKE_KEY) c_int; -pub extern fn SSL_ECH_KEYS_has_duplicate_config_id(keys: ?*const SSL_ECH_KEYS) c_int; -pub extern fn SSL_ECH_KEYS_marshal_retry_configs(keys: ?*const SSL_ECH_KEYS, out: [*c][*c]u8, out_len: [*c]usize) c_int; -pub extern fn SSL_CTX_set1_ech_keys(ctx: ?*SSL_CTX, keys: ?*SSL_ECH_KEYS) c_int; -pub extern fn SSL_ech_accepted(ssl: ?*const SSL) c_int; -pub extern fn SSL_alert_type_string_long(value: c_int) [*c]const u8; -pub extern fn SSL_alert_desc_string_long(value: c_int) [*c]const u8; -pub extern fn SSL_send_fatal_alert(ssl: ?*SSL, alert: u8) c_int; -pub extern fn SSL_set_ex_data(ssl: ?*SSL, idx: c_int, data: ?*anyopaque) c_int; -pub extern fn SSL_get_ex_data(ssl: ?*const SSL, idx: c_int) ?*anyopaque; -pub extern fn SSL_get_ex_new_index(argl: c_long, argp: ?*anyopaque, unused: [*c]CRYPTO_EX_unused, dup_unused: ?*const CRYPTO_EX_dup, free_func: ?*const CRYPTO_EX_free) c_int; -pub extern fn SSL_SESSION_set_ex_data(session: ?*SSL_SESSION, idx: c_int, data: ?*anyopaque) c_int; -pub extern fn SSL_SESSION_get_ex_data(session: ?*const SSL_SESSION, idx: c_int) ?*anyopaque; -pub extern fn SSL_SESSION_get_ex_new_index(argl: c_long, argp: ?*anyopaque, unused: [*c]CRYPTO_EX_unused, dup_unused: ?*const CRYPTO_EX_dup, free_func: ?*const CRYPTO_EX_free) c_int; -pub extern fn SSL_CTX_set_ex_data(ctx: ?*SSL_CTX, idx: c_int, data: ?*anyopaque) c_int; -pub extern fn SSL_CTX_get_ex_data(ctx: ?*const SSL_CTX, idx: c_int) ?*anyopaque; -pub extern fn SSL_CTX_get_ex_new_index(argl: c_long, argp: ?*anyopaque, unused: [*c]CRYPTO_EX_unused, dup_unused: ?*const CRYPTO_EX_dup, free_func: ?*const CRYPTO_EX_free) c_int; -pub extern fn SSL_get_ivs(ssl: ?*const SSL, out_read_iv: [*c][*c]const u8, out_write_iv: [*c][*c]const u8, out_iv_len: [*c]usize) c_int; -pub extern fn SSL_get_key_block_len(ssl: ?*const SSL) usize; -pub extern fn SSL_generate_key_block(ssl: ?*const SSL, out: [*c]u8, out_len: usize) c_int; -pub extern fn SSL_get_read_sequence(ssl: ?*const SSL) u64; -pub extern fn SSL_get_write_sequence(ssl: ?*const SSL) u64; -pub extern fn SSL_CTX_set_record_protocol_version(ctx: ?*SSL_CTX, version: c_int) c_int; -pub extern fn SSL_serialize_capabilities(ssl: ?*const SSL, out: ?*CBB) c_int; -pub extern fn SSL_request_handshake_hints(ssl: ?*SSL, client_hello: [*c]const u8, client_hello_len: usize, capabilities: [*c]const u8, capabilities_len: usize) c_int; -pub extern fn SSL_serialize_handshake_hints(ssl: ?*const SSL, out: ?*CBB) c_int; -pub extern fn SSL_set_handshake_hints(ssl: ?*SSL, hints: [*c]const u8, hints_len: usize) c_int; -pub extern fn SSL_CTX_set_msg_callback(ctx: ?*SSL_CTX, cb: ?*const fn (c_int, c_int, c_int, ?*const anyopaque, usize, ?*SSL, ?*anyopaque) callconv(.c) void) void; -pub extern fn SSL_CTX_set_msg_callback_arg(ctx: ?*SSL_CTX, arg: ?*anyopaque) void; -pub extern fn SSL_set_msg_callback(ssl: ?*SSL, cb: ?*const fn (c_int, c_int, c_int, ?*const anyopaque, usize, ?*SSL, ?*anyopaque) callconv(.c) void) void; -pub extern fn SSL_set_msg_callback_arg(ssl: ?*SSL, arg: ?*anyopaque) void; -pub extern fn SSL_CTX_set_keylog_callback(ctx: ?*SSL_CTX, cb: ?*const fn (?*const SSL, [*c]const u8) callconv(.c) void) void; -pub extern fn SSL_CTX_get_keylog_callback(ctx: ?*const SSL_CTX) ?*const fn (?*const SSL, [*c]const u8) callconv(.c) void; -pub extern fn SSL_CTX_set_current_time_cb(ctx: ?*SSL_CTX, cb: ?*const fn (?*const SSL, [*c]struct_timeval) callconv(.c) void) void; -pub extern fn SSL_set_shed_handshake_config(ssl: ?*SSL, enable: c_int) void; -pub const ssl_renegotiate_never: c_int = 0; -pub const ssl_renegotiate_once: c_int = 1; -pub const ssl_renegotiate_freely: c_int = 2; -pub const ssl_renegotiate_ignore: c_int = 3; -pub const ssl_renegotiate_explicit: c_int = 4; -pub const enum_ssl_renegotiate_mode_t = c_uint; -pub extern fn SSL_set_renegotiate_mode(ssl: ?*SSL, mode: enum_ssl_renegotiate_mode_t) void; -pub extern fn SSL_renegotiate(ssl: ?*SSL) c_int; -pub extern fn SSL_renegotiate_pending(ssl: ?*SSL) c_int; -pub extern fn SSL_total_renegotiations(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_get_max_cert_list(ctx: ?*const SSL_CTX) usize; -pub extern fn SSL_CTX_set_max_cert_list(ctx: ?*SSL_CTX, max_cert_list: usize) void; -pub extern fn SSL_get_max_cert_list(ssl: ?*const SSL) usize; -pub extern fn SSL_set_max_cert_list(ssl: ?*SSL, max_cert_list: usize) void; -pub extern fn SSL_CTX_set_max_send_fragment(ctx: ?*SSL_CTX, max_send_fragment: usize) c_int; -pub extern fn SSL_set_max_send_fragment(ssl: ?*SSL, max_send_fragment: usize) c_int; -pub const ssl_select_cert_success: c_int = 1; -pub const ssl_select_cert_retry: c_int = 0; -pub const ssl_select_cert_error: c_int = -1; -pub const enum_ssl_select_cert_result_t = c_int; -pub extern fn SSL_early_callback_ctx_extension_get(client_hello: [*c]const SSL_CLIENT_HELLO, extension_type: u16, out_data: [*c][*c]const u8, out_len: [*c]usize) c_int; -pub extern fn SSL_CTX_set_select_certificate_cb(ctx: ?*SSL_CTX, cb: ?*const fn ([*c]const SSL_CLIENT_HELLO) callconv(.c) enum_ssl_select_cert_result_t) void; -pub extern fn SSL_CTX_set_dos_protection_cb(ctx: ?*SSL_CTX, cb: ?*const fn ([*c]const SSL_CLIENT_HELLO) callconv(.c) c_int) void; -pub extern fn SSL_CTX_set_reverify_on_resume(ctx: ?*SSL_CTX, enabled: c_int) void; -pub extern fn SSL_set_enforce_rsa_key_usage(ssl: ?*SSL, enabled: c_int) void; -pub extern fn SSL_was_key_usage_invalid(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_set_info_callback(ctx: ?*SSL_CTX, cb: ?*const fn (?*const SSL, c_int, c_int) callconv(.c) void) void; -pub extern fn SSL_CTX_get_info_callback(ctx: ?*SSL_CTX) ?*const fn (?*const SSL, c_int, c_int) callconv(.c) void; -pub extern fn SSL_set_info_callback(ssl: ?*SSL, cb: ?*const fn (?*const SSL, c_int, c_int) callconv(.c) void) void; -pub extern fn SSL_get_info_callback(ssl: ?*const SSL) ?*const fn (?*const SSL, c_int, c_int) callconv(.c) void; -pub extern fn SSL_state_string_long(ssl: ?*const SSL) [*c]const u8; -pub extern fn SSL_get_shutdown(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_peer_signature_algorithm(ssl: ?*const SSL) u16; -pub extern fn SSL_get_client_random(ssl: ?*const SSL, out: [*c]u8, max_out: usize) usize; -pub extern fn SSL_get_server_random(ssl: ?*const SSL, out: [*c]u8, max_out: usize) usize; -pub extern fn SSL_get_pending_cipher(ssl: ?*const SSL) ?*const SSL_CIPHER; -pub extern fn SSL_set_retain_only_sha256_of_client_certs(ssl: ?*SSL, enable: c_int) void; -pub extern fn SSL_CTX_set_retain_only_sha256_of_client_certs(ctx: ?*SSL_CTX, enable: c_int) void; -pub extern fn SSL_CTX_set_grease_enabled(ctx: ?*SSL_CTX, enabled: c_int) void; -pub extern fn SSL_CTX_set_permute_extensions(ctx: ?*SSL_CTX, enabled: c_int) void; -pub extern fn SSL_set_permute_extensions(ssl: ?*SSL, enabled: c_int) void; -pub extern fn SSL_max_seal_overhead(ssl: ?*const SSL) usize; -pub extern fn SSL_CTX_set_false_start_allowed_without_alpn(ctx: ?*SSL_CTX, allowed: c_int) void; -pub extern fn SSL_used_hello_retry_request(ssl: ?*const SSL) c_int; -pub extern fn SSL_set_jdk11_workaround(ssl: ?*SSL, enable: c_int) void; -pub extern fn SSL_library_init() c_int; -pub extern fn SSL_CIPHER_description(cipher: ?*const SSL_CIPHER, buf: [*c]u8, len: c_int) [*c]const u8; -pub extern fn SSL_CIPHER_get_version(cipher: ?*const SSL_CIPHER) [*c]const u8; -pub extern fn SSL_CIPHER_get_rfc_name(cipher: ?*const SSL_CIPHER) [*c]u8; -pub const COMP_METHOD = anyopaque; -pub const struct_ssl_comp_st = extern struct { - id: c_int, - name: [*c]const u8, - method: [*c]u8, -}; -pub const SSL_COMP = struct_ssl_comp_st; -pub const struct_stack_st_SSL_COMP = opaque {}; -pub extern fn SSL_COMP_get_compression_methods() ?*struct_stack_st_SSL_COMP; -pub extern fn SSL_COMP_add_compression_method(id: c_int, cm: ?*COMP_METHOD) c_int; -pub extern fn SSL_COMP_get_name(comp: ?*const COMP_METHOD) [*c]const u8; -pub extern fn SSL_COMP_get0_name(comp: [*c]const SSL_COMP) [*c]const u8; -pub extern fn SSL_COMP_get_id(comp: [*c]const SSL_COMP) c_int; -pub extern fn SSL_COMP_free_compression_methods() void; -pub extern fn SSLv23_method() ?*const SSL_METHOD; -pub extern fn TLSv1_method() ?*const SSL_METHOD; -pub extern fn TLSv1_1_method() ?*const SSL_METHOD; -pub extern fn TLSv1_2_method() ?*const SSL_METHOD; -pub extern fn DTLSv1_method() ?*const SSL_METHOD; -pub extern fn DTLSv1_2_method() ?*const SSL_METHOD; -pub extern fn TLS_server_method() ?*const SSL_METHOD; -pub extern fn TLS_client_method() ?*const SSL_METHOD; -pub extern fn SSLv23_server_method() ?*const SSL_METHOD; -pub extern fn SSLv23_client_method() ?*const SSL_METHOD; -pub extern fn TLSv1_server_method() ?*const SSL_METHOD; -pub extern fn TLSv1_client_method() ?*const SSL_METHOD; -pub extern fn TLSv1_1_server_method() ?*const SSL_METHOD; -pub extern fn TLSv1_1_client_method() ?*const SSL_METHOD; -pub extern fn TLSv1_2_server_method() ?*const SSL_METHOD; -pub extern fn TLSv1_2_client_method() ?*const SSL_METHOD; -pub extern fn DTLS_server_method() ?*const SSL_METHOD; -pub extern fn DTLS_client_method() ?*const SSL_METHOD; -pub extern fn DTLSv1_server_method() ?*const SSL_METHOD; -pub extern fn DTLSv1_client_method() ?*const SSL_METHOD; -pub extern fn DTLSv1_2_server_method() ?*const SSL_METHOD; -pub extern fn DTLSv1_2_client_method() ?*const SSL_METHOD; -pub extern fn SSL_clear(ssl: ?*SSL) c_int; -pub extern fn SSL_CTX_set_tmp_rsa_callback(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, c_int, c_int) callconv(.c) ?*RSA) void; -pub extern fn SSL_set_tmp_rsa_callback(ssl: ?*SSL, cb: ?*const fn (?*SSL, c_int, c_int) callconv(.c) ?*RSA) void; -pub extern fn SSL_CTX_sess_connect(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_connect_good(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_connect_renegotiate(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_accept(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_accept_renegotiate(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_accept_good(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_hits(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_cb_hits(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_misses(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_timeouts(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_sess_cache_full(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_cutthrough_complete(ssl: ?*const SSL) c_int; -pub extern fn SSL_num_renegotiations(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_need_tmp_RSA(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_need_tmp_RSA(ssl: ?*const SSL) c_int; -pub extern fn SSL_CTX_set_tmp_rsa(ctx: ?*SSL_CTX, rsa: ?*const RSA) c_int; -pub extern fn SSL_set_tmp_rsa(ssl: ?*SSL, rsa: ?*const RSA) c_int; -pub extern fn SSL_CTX_get_read_ahead(ctx: ?*const SSL_CTX) c_int; -pub extern fn SSL_CTX_set_read_ahead(ctx: ?*SSL_CTX, yes: c_int) c_int; -pub extern fn SSL_get_read_ahead(ssl: ?*const SSL) c_int; -pub extern fn SSL_set_read_ahead(ssl: ?*SSL, yes: c_int) c_int; -pub extern fn SSL_set_state(ssl: ?*SSL, state: c_int) void; -pub extern fn SSL_get_shared_ciphers(ssl: ?*const SSL, buf: [*c]u8, len: c_int) [*c]u8; -pub extern fn SSL_get_shared_sigalgs(ssl: ?*SSL, idx: c_int, psign: [*c]c_int, phash: [*c]c_int, psignandhash: [*c]c_int, rsig: [*c]u8, rhash: [*c]u8) c_int; -pub extern fn i2d_SSL_SESSION(in: ?*SSL_SESSION, pp: [*c][*c]u8) c_int; -pub extern fn d2i_SSL_SESSION(a: [*c]?*SSL_SESSION, pp: [*c][*c]const u8, length: c_long) ?*SSL_SESSION; -pub extern fn i2d_SSL_SESSION_bio(bio: [*c]BIO, session: ?*const SSL_SESSION) c_int; -pub extern fn d2i_SSL_SESSION_bio(bio: [*c]BIO, out: [*c]?*SSL_SESSION) ?*SSL_SESSION; -pub extern fn ERR_load_SSL_strings() void; -pub extern fn SSL_load_error_strings() void; -// pub extern fn SSL_CTX_set_tlsext_use_srtp(ctx: ?*SSL_CTX, profiles: [*c]const u8) c_int; -// pub extern fn SSL_set_tlsext_use_srtp(ssl: ?*SSL, profiles: [*c]const u8) c_int; -pub extern fn SSL_get_current_compression(ssl: ?*SSL) ?*const COMP_METHOD; -pub extern fn SSL_get_current_expansion(ssl: ?*SSL) ?*const COMP_METHOD; -pub extern fn SSL_get_server_tmp_key(ssl: ?*SSL, out_key: [*c][*c]EVP_PKEY) c_int; -pub extern fn SSL_CTX_set_tmp_dh(ctx: ?*SSL_CTX, dh: ?*const DH) c_int; -pub extern fn SSL_set_tmp_dh(ssl: ?*SSL, dh: ?*const DH) c_int; -pub extern fn SSL_CTX_set_tmp_dh_callback(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, c_int, c_int) callconv(.c) ?*DH) void; -pub extern fn SSL_set_tmp_dh_callback(ssl: ?*SSL, cb: ?*const fn (?*SSL, c_int, c_int) callconv(.c) ?*DH) void; -pub extern fn SSL_CTX_set1_sigalgs(ctx: ?*SSL_CTX, values: [*c]const c_int, num_values: usize) c_int; -pub extern fn SSL_set1_sigalgs(ssl: ?*SSL, values: [*c]const c_int, num_values: usize) c_int; -pub extern fn SSL_CTX_set1_sigalgs_list(ctx: ?*SSL_CTX, str: [*c]const u8) c_int; -pub extern fn SSL_set1_sigalgs_list(ssl: ?*SSL, str: [*c]const u8) c_int; -pub const sk_SSL_COMP_free_func = ?*const fn ([*c]SSL_COMP) callconv(.c) void; -pub const sk_SSL_COMP_copy_func = ?*const fn ([*c]SSL_COMP) callconv(.c) [*c]SSL_COMP; -pub const sk_SSL_COMP_cmp_func = ?*const fn ([*c][*c]const SSL_COMP, [*c][*c]const SSL_COMP) callconv(.c) c_int; -pub fn sk_SSL_COMP_call_free_func(arg_free_func: OPENSSL_sk_free_func, arg_ptr: ?*anyopaque) callconv(.c) void { - const free_func = arg_free_func; - const ptr = arg_ptr; - @as(sk_SSL_COMP_free_func, @ptrCast(@alignCast(free_func))).?(@as([*c]SSL_COMP, @ptrCast(@alignCast(ptr)))); -} -pub fn sk_SSL_COMP_call_copy_func(arg_copy_func: OPENSSL_sk_copy_func, arg_ptr: ?*anyopaque) callconv(.c) ?*anyopaque { - const copy_func = arg_copy_func; - const ptr = arg_ptr; - return @as(?*anyopaque, @ptrCast(@as(sk_SSL_COMP_copy_func, @ptrCast(@alignCast(copy_func))).?(@as([*c]SSL_COMP, @ptrCast(@alignCast(ptr)))))); -} -pub fn sk_SSL_COMP_call_cmp_func(arg_cmp_func: OPENSSL_sk_cmp_func, arg_a: [*c]const ?*const anyopaque, arg_b: [*c]const ?*const anyopaque) callconv(.c) c_int { - const cmp_func = arg_cmp_func; - const a = arg_a; - const b = arg_b; - var a_ptr: [*c]const SSL_COMP = @as([*c]const SSL_COMP, @ptrCast(@alignCast(a.*))); - var b_ptr: [*c]const SSL_COMP = @as([*c]const SSL_COMP, @ptrCast(@alignCast(b.*))); - return @as(sk_SSL_COMP_cmp_func, @ptrCast(@alignCast(cmp_func))).?(&a_ptr, &b_ptr); -} -pub fn sk_SSL_COMP_new(arg_comp: sk_SSL_COMP_cmp_func) callconv(.c) ?*struct_stack_st_SSL_COMP { - const comp = arg_comp; - return @as(?*struct_stack_st_SSL_COMP, @ptrCast(sk_new(@as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp)))))); -} -pub fn sk_SSL_COMP_new_null() callconv(.c) ?*struct_stack_st_SSL_COMP { - return @as(?*struct_stack_st_SSL_COMP, @ptrCast(sk_new_null())); -} -pub fn sk_SSL_COMP_num(arg_sk: ?*const struct_stack_st_SSL_COMP) callconv(.c) usize { - const sk = arg_sk; - return sk_num(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_COMP_zero(arg_sk: ?*struct_stack_st_SSL_COMP) callconv(.c) void { - const sk = arg_sk; - sk_zero(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_COMP_value(arg_sk: ?*const struct_stack_st_SSL_COMP, arg_i: usize) callconv(.c) [*c]SSL_COMP { - const sk = arg_sk; - const i = arg_i; - return @as([*c]SSL_COMP, @ptrCast(@alignCast(sk_value(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), i)))); -} -pub fn sk_SSL_COMP_set(arg_sk: ?*struct_stack_st_SSL_COMP, arg_i: usize, arg_p: [*c]SSL_COMP) callconv(.c) [*c]SSL_COMP { - const sk = arg_sk; - const i = arg_i; - const p = arg_p; - return @as([*c]SSL_COMP, @ptrCast(@alignCast(sk_set(@as([*c]_STACK, @ptrCast(@alignCast(sk))), i, @as(?*anyopaque, @ptrCast(p)))))); -} -pub fn sk_SSL_COMP_free(arg_sk: ?*struct_stack_st_SSL_COMP) callconv(.c) void { - const sk = arg_sk; - sk_free(@as([*c]_STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_COMP_pop_free(arg_sk: ?*struct_stack_st_SSL_COMP, arg_free_func: sk_SSL_COMP_free_func) callconv(.c) void { - const sk = arg_sk; - const free_func = arg_free_func; - sk_pop_free_ex(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_SSL_COMP_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))); -} -pub fn sk_SSL_COMP_insert(arg_sk: ?*struct_stack_st_SSL_COMP, arg_p: [*c]SSL_COMP, arg_where: usize) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - const where = arg_where; - return sk_insert(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p)), where); -} -pub fn sk_SSL_COMP_delete(arg_sk: ?*struct_stack_st_SSL_COMP, arg_where: usize) callconv(.c) [*c]SSL_COMP { - const sk = arg_sk; - const where = arg_where; - return @as([*c]SSL_COMP, @ptrCast(@alignCast(sk_delete(@as([*c]_STACK, @ptrCast(@alignCast(sk))), where)))); -} -pub fn sk_SSL_COMP_delete_ptr(arg_sk: ?*struct_stack_st_SSL_COMP, arg_p: [*c]const SSL_COMP) callconv(.c) [*c]SSL_COMP { - const sk = arg_sk; - const p = arg_p; - return @as([*c]SSL_COMP, @ptrCast(@alignCast(sk_delete_ptr(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*const anyopaque, @ptrCast(p)))))); -} -pub fn sk_SSL_COMP_find(arg_sk: ?*const struct_stack_st_SSL_COMP, arg_out_index: [*c]usize, arg_p: [*c]const SSL_COMP) callconv(.c) c_int { - const sk = arg_sk; - const out_index = arg_out_index; - const p = arg_p; - return sk_find(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), out_index, @as(?*const anyopaque, @ptrCast(p)), &sk_SSL_COMP_call_cmp_func); -} -pub fn sk_SSL_COMP_shift(arg_sk: ?*struct_stack_st_SSL_COMP) callconv(.c) [*c]SSL_COMP { - const sk = arg_sk; - return @as([*c]SSL_COMP, @ptrCast(@alignCast(sk_shift(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_SSL_COMP_push(arg_sk: ?*struct_stack_st_SSL_COMP, arg_p: [*c]SSL_COMP) callconv(.c) usize { - const sk = arg_sk; - const p = arg_p; - return sk_push(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(?*anyopaque, @ptrCast(p))); -} -pub fn sk_SSL_COMP_pop(arg_sk: ?*struct_stack_st_SSL_COMP) callconv(.c) [*c]SSL_COMP { - const sk = arg_sk; - return @as([*c]SSL_COMP, @ptrCast(@alignCast(sk_pop(@as([*c]_STACK, @ptrCast(@alignCast(sk))))))); -} -pub fn sk_SSL_COMP_dup(arg_sk: ?*const struct_stack_st_SSL_COMP) callconv(.c) ?*struct_stack_st_SSL_COMP { - const sk = arg_sk; - return @as(?*struct_stack_st_SSL_COMP, @ptrCast(sk_dup(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))))); -} -pub fn sk_SSL_COMP_sort(arg_sk: ?*struct_stack_st_SSL_COMP) callconv(.c) void { - const sk = arg_sk; - sk_sort(@as([*c]_STACK, @ptrCast(@alignCast(sk))), &sk_SSL_COMP_call_cmp_func); -} -pub fn sk_SSL_COMP_is_sorted(arg_sk: ?*const struct_stack_st_SSL_COMP) callconv(.c) c_int { - const sk = arg_sk; - return sk_is_sorted(@as([*c]const _STACK, @ptrCast(@alignCast(sk)))); -} -pub fn sk_SSL_COMP_set_cmp_func(arg_sk: ?*struct_stack_st_SSL_COMP, arg_comp: sk_SSL_COMP_cmp_func) callconv(.c) sk_SSL_COMP_cmp_func { - const sk = arg_sk; - const comp = arg_comp; - return @as(sk_SSL_COMP_cmp_func, @ptrCast(@alignCast(sk_set_cmp_func(@as([*c]_STACK, @ptrCast(@alignCast(sk))), @as(OPENSSL_sk_cmp_func, @ptrCast(@alignCast(comp))))))); -} -pub fn sk_SSL_COMP_deep_copy(arg_sk: ?*const struct_stack_st_SSL_COMP, arg_copy_func: sk_SSL_COMP_copy_func, arg_free_func: sk_SSL_COMP_free_func) callconv(.c) ?*struct_stack_st_SSL_COMP { - const sk = arg_sk; - const copy_func = arg_copy_func; - const free_func = arg_free_func; - return @as(?*struct_stack_st_SSL_COMP, @ptrCast(sk_deep_copy(@as([*c]const _STACK, @ptrCast(@alignCast(sk))), &sk_SSL_COMP_call_copy_func, @as(OPENSSL_sk_copy_func, @ptrCast(@alignCast(copy_func))), &sk_SSL_COMP_call_free_func, @as(OPENSSL_sk_free_func, @ptrCast(@alignCast(free_func)))))); -} -pub extern fn SSL_cache_hit(ssl: ?*SSL) c_int; -pub extern fn SSL_get_default_timeout(ssl: ?*const SSL) c_long; -pub extern fn SSL_get_version(ssl: ?*const SSL) [*c]const u8; -pub extern fn SSL_get_cipher_list(ssl: ?*const SSL, n: c_int) [*c]const u8; -pub extern fn SSL_CTX_set_client_cert_cb(ctx: ?*SSL_CTX, cb: ?*const fn (?*SSL, [*c]?*X509, [*c][*c]EVP_PKEY) callconv(.c) c_int) void; -pub extern fn SSL_want(ssl: ?*const SSL) c_int; -pub extern fn SSL_get_finished(ssl: ?*const SSL, buf: ?*anyopaque, count: usize) usize; -pub extern fn SSL_get_peer_finished(ssl: ?*const SSL, buf: ?*anyopaque, count: usize) usize; -pub extern fn SSL_alert_type_string(value: c_int) [*c]const u8; -pub extern fn SSL_alert_desc_string(value: c_int) [*c]const u8; -pub extern fn SSL_state_string(ssl: ?*const SSL) [*c]const u8; -pub const struct_ssl_conf_ctx_st = opaque {}; -pub const SSL_CONF_CTX = struct_ssl_conf_ctx_st; -pub extern fn SSL_state(ssl: ?*const SSL) c_int; -pub extern fn SSL_set_shutdown(ssl: ?*SSL, mode: c_int) void; -pub extern fn SSL_CTX_set_tmp_ecdh(ctx: ?*SSL_CTX, ec_key: ?*const EC_KEY) c_int; -pub extern fn SSL_set_tmp_ecdh(ssl: ?*SSL, ec_key: ?*const EC_KEY) c_int; -pub extern fn SSL_add_dir_cert_subjects_to_stack(out: ?*struct_stack_st_X509_NAME, dir: [*c]const u8) c_int; -pub extern fn SSL_CTX_enable_tls_channel_id(ctx: ?*SSL_CTX) c_int; -pub extern fn SSL_enable_tls_channel_id(ssl: ?*SSL) c_int; -pub extern fn BIO_f_ssl() [*c]const BIO_METHOD; -pub extern fn BIO_set_ssl(bio: [*c]BIO, ssl: ?*SSL, take_owership: c_int) c_long; -pub extern fn SSL_get_session(ssl: ?*const SSL) ?*SSL_SESSION; -pub extern fn SSL_get1_session(ssl: ?*SSL) ?*SSL_SESSION; -pub extern fn OPENSSL_init_ssl(opts: u64, settings: ?*const OPENSSL_INIT_SETTINGS) c_int; -pub extern fn SSL_set_tlsext_status_type(ssl: ?*SSL, @"type": c_int) c_int; -pub extern fn SSL_get_tlsext_status_type(ssl: ?*const SSL) c_int; -pub extern fn SSL_set_tlsext_status_ocsp_resp(ssl: ?*SSL, resp: [*c]u8, resp_len: usize) c_int; -pub extern fn SSL_get_tlsext_status_ocsp_resp(ssl: ?*const SSL, out: [*c][*c]const u8) usize; -pub extern fn SSL_CTX_set_tlsext_status_cb(ctx: ?*SSL_CTX, callback: ?*const fn (?*SSL, ?*anyopaque) callconv(.c) c_int) c_int; -pub extern fn SSL_CTX_set_tlsext_status_arg(ctx: ?*SSL_CTX, arg: ?*anyopaque) c_int; -pub extern fn SSL_CIPHER_get_value(cipher: ?*const SSL_CIPHER) u16; -pub const ssl_compliance_policy_fips_202205: c_int = 0; -pub const enum_ssl_compliance_policy_t = c_uint; -pub extern fn SSL_CTX_set_compliance_policy(ctx: ?*SSL_CTX, policy: enum_ssl_compliance_policy_t) c_int; -pub extern fn SSL_set_compliance_policy(ssl: ?*SSL, policy: enum_ssl_compliance_policy_t) c_int; -pub const OPENSSL_HEADER_OPENSSLCONF_H = ""; -pub const OPENSSL_NO_ASYNC = ""; -pub const OPENSSL_NO_BF = ""; -pub const OPENSSL_NO_BLAKE2 = ""; -pub const OPENSSL_NO_BUF_FREELISTS = ""; -pub const OPENSSL_NO_CAMELLIA = ""; -pub const OPENSSL_NO_CAPIENG = ""; -pub const OPENSSL_NO_CAST = ""; -pub const OPENSSL_NO_CMS = ""; -pub const OPENSSL_NO_COMP = ""; -pub const OPENSSL_NO_CT = ""; -pub const OPENSSL_NO_DANE = ""; -pub const OPENSSL_NO_DEPRECATED = ""; -pub const OPENSSL_NO_DGRAM = ""; -pub const OPENSSL_NO_DYNAMIC_ENGINE = ""; -pub const OPENSSL_NO_EC_NISTP_64_GCC_128 = ""; -pub const OPENSSL_NO_EC2M = ""; -pub const OPENSSL_NO_EGD = ""; -pub const OPENSSL_NO_ENGINE = ""; -pub const OPENSSL_NO_GMP = ""; -pub const OPENSSL_NO_GOST = ""; -pub const OPENSSL_NO_HEARTBEATS = ""; -pub const OPENSSL_NO_HW = ""; -pub const OPENSSL_NO_IDEA = ""; -pub const OPENSSL_NO_JPAKE = ""; -pub const OPENSSL_NO_KRB5 = ""; -pub const OPENSSL_NO_MD2 = ""; -pub const OPENSSL_NO_MDC2 = ""; -pub const OPENSSL_NO_OCB = ""; -pub const OPENSSL_NO_OCSP = ""; -pub const OPENSSL_NO_RC2 = ""; -pub const OPENSSL_NO_RC5 = ""; -pub const OPENSSL_NO_RFC3779 = ""; -pub const OPENSSL_NO_RIPEMD = ""; -pub const OPENSSL_NO_RMD160 = ""; -pub const OPENSSL_NO_SCTP = ""; -pub const OPENSSL_NO_SEED = ""; -pub const OPENSSL_NO_SM2 = ""; -pub const OPENSSL_NO_SM3 = ""; -pub const OPENSSL_NO_SM4 = ""; -pub const OPENSSL_NO_SRP = ""; -pub const OPENSSL_NO_SSL_TRACE = ""; -pub const OPENSSL_NO_SSL2 = ""; -pub const OPENSSL_NO_SSL3 = ""; -pub const OPENSSL_NO_SSL3_METHOD = ""; -pub const OPENSSL_NO_STATIC_ENGINE = ""; -pub const OPENSSL_NO_STORE = ""; -pub const OPENSSL_NO_WHIRLPOOL = ""; -pub const OPENSSL_64_BIT = ""; -pub const OPENSSL_AARCH64 = ""; -pub const OPENSSL_APPLE = ""; -pub const OPENSSL_MACOS = ""; -pub const OPENSSL_THREADS = ""; -pub const OPENSSL_IS_BORINGSSL = ""; -pub const OPENSSL_VERSION_NUMBER = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x1010107f, .hex); -pub const SSLEAY_VERSION_NUMBER = OPENSSL_VERSION_NUMBER; -pub const BORINGSSL_API_VERSION = @as(c_int, 18); -pub const OPENSSL_EXPORT = ""; -pub const BORINGSSL_ENUM_INT = ""; -pub const BORINGSSL_NO_CXX = ""; -pub const OPENSSL_HEADER_BIO_H = ""; -pub const _STDIO_H_ = ""; -pub const __STDIO_H_ = ""; -pub const __TYPES_H_ = ""; -pub const _FORTIFY_SOURCE = @as(c_int, 2); -pub const _VA_LIST_T = ""; -pub const _SYS_STDIO_H_ = ""; -pub const RENAME_SECLUDE = @as(c_int, 0x00000001); -pub const RENAME_SWAP = @as(c_int, 0x00000002); -pub const RENAME_EXCL = @as(c_int, 0x00000004); -pub const RENAME_RESERVED1 = @as(c_int, 0x00000008); -pub const RENAME_NOFOLLOW_ANY = @as(c_int, 0x00000010); -pub const _FSTDIO = ""; -pub const __SLBF = @as(c_int, 0x0001); -pub const __SNBF = @as(c_int, 0x0002); -pub const __SRD = @as(c_int, 0x0004); -pub const __SWR = @as(c_int, 0x0008); -pub const __SRW = @as(c_int, 0x0010); -pub const __SEOF = @as(c_int, 0x0020); -pub const __SERR = @as(c_int, 0x0040); -pub const __SMBF = @as(c_int, 0x0080); -pub const __SAPP = @as(c_int, 0x0100); -pub const __SSTR = @as(c_int, 0x0200); -pub const __SOPT = @as(c_int, 0x0400); -pub const __SNPT = @as(c_int, 0x0800); -pub const __SOFF = @as(c_int, 0x1000); -pub const __SMOD = @as(c_int, 0x2000); -pub const __SALC = @as(c_int, 0x4000); -pub const __SIGN = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex); -pub const _IOFBF = @as(c_int, 0); -pub const _IOLBF = @as(c_int, 1); -pub const _IONBF = @as(c_int, 2); -pub const BUFSIZ = @as(c_int, 1024); -pub const EOF = -@as(c_int, 1); -pub const FOPEN_MAX = @as(c_int, 20); -pub const FILENAME_MAX = @as(c_int, 1024); -pub const P_tmpdir = "/var/tmp/"; -pub const L_tmpnam = @as(c_int, 1024); -pub const TMP_MAX = @import("std").zig.c_translation.promoteIntLiteral(c_int, 308915776, .decimal); -pub const SEEK_SET = @as(c_int, 0); -pub const SEEK_CUR = @as(c_int, 1); -pub const SEEK_END = @as(c_int, 2); -pub const L_ctermid = @as(c_int, 1024); -pub const _CTERMID_H_ = ""; -pub const _SECURE__STDIO_H_ = ""; -pub const _SECURE__COMMON_H_ = ""; -pub const _USE_FORTIFY_LEVEL = @as(c_int, 2); -pub const OPENSSL_HEADER_BUFFER_H = ""; -pub const OPENSSL_HEADER_ERR_H = ""; -pub inline fn ERR_GET_LIB(packed_error: anytype) c_int { - return @import("std").zig.c_translation.cast(c_int, (packed_error >> @as(c_int, 24)) & @as(c_int, 0xff)); -} -pub inline fn ERR_GET_REASON(packed_error: anytype) c_int { - return @import("std").zig.c_translation.cast(c_int, packed_error & @as(c_int, 0xfff)); -} -pub const ERR_FLAG_STRING = @as(c_int, 1); -pub const ERR_FLAG_MALLOCED = @as(c_int, 2); -pub const ERR_R_SYS_LIB = ERR_LIB_SYS; -pub const ERR_R_BN_LIB = ERR_LIB_BN; -pub const ERR_R_RSA_LIB = ERR_LIB_RSA; -pub const ERR_R_DH_LIB = ERR_LIB_DH; -pub const ERR_R_EVP_LIB = ERR_LIB_EVP; -pub const ERR_R_BUF_LIB = ERR_LIB_BUF; -pub const ERR_R_OBJ_LIB = ERR_LIB_OBJ; -pub const ERR_R_PEM_LIB = ERR_LIB_PEM; -pub const ERR_R_DSA_LIB = ERR_LIB_DSA; -pub const ERR_R_X509_LIB = ERR_LIB_X509; -pub const ERR_R_ASN1_LIB = ERR_LIB_ASN1; -pub const ERR_R_CONF_LIB = ERR_LIB_CONF; -pub const ERR_R_CRYPTO_LIB = ERR_LIB_CRYPTO; -pub const ERR_R_EC_LIB = ERR_LIB_EC; -pub const ERR_R_SSL_LIB = ERR_LIB_SSL; -pub const ERR_R_BIO_LIB = ERR_LIB_BIO; -pub const ERR_R_PKCS7_LIB = ERR_LIB_PKCS7; -pub const ERR_R_PKCS8_LIB = ERR_LIB_PKCS8; -pub const ERR_R_X509V3_LIB = ERR_LIB_X509V3; -pub const ERR_R_RAND_LIB = ERR_LIB_RAND; -pub const ERR_R_ENGINE_LIB = ERR_LIB_ENGINE; -pub const ERR_R_OCSP_LIB = ERR_LIB_OCSP; -pub const ERR_R_UI_LIB = ERR_LIB_UI; -pub const ERR_R_COMP_LIB = ERR_LIB_COMP; -pub const ERR_R_ECDSA_LIB = ERR_LIB_ECDSA; -pub const ERR_R_ECDH_LIB = ERR_LIB_ECDH; -pub const ERR_R_HMAC_LIB = ERR_LIB_HMAC; -pub const ERR_R_USER_LIB = ERR_LIB_USER; -pub const ERR_R_DIGEST_LIB = ERR_LIB_DIGEST; -pub const ERR_R_CIPHER_LIB = ERR_LIB_CIPHER; -pub const ERR_R_HKDF_LIB = ERR_LIB_HKDF; -pub const ERR_R_TRUST_TOKEN_LIB = ERR_LIB_TRUST_TOKEN; -pub const ERR_R_FATAL = @as(c_int, 64); -pub const ERR_R_MALLOC_FAILURE = @as(c_int, 1) | ERR_R_FATAL; -pub const ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED = @as(c_int, 2) | ERR_R_FATAL; -pub const ERR_R_PASSED_NULL_PARAMETER = @as(c_int, 3) | ERR_R_FATAL; -pub const ERR_R_INTERNAL_ERROR = @as(c_int, 4) | ERR_R_FATAL; -pub const ERR_R_OVERFLOW = @as(c_int, 5) | ERR_R_FATAL; -pub const ERR_ERROR_STRING_BUF_LEN = @as(c_int, 120); -pub inline fn ERR_GET_FUNC(packed_error: anytype) @TypeOf(@as(c_int, 0)) { - _ = @TypeOf(packed_error); - return @as(c_int, 0); -} -pub const ERR_TXT_STRING = ERR_FLAG_STRING; -pub const ERR_TXT_MALLOCED = ERR_FLAG_MALLOCED; -pub const ERR_NUM_ERRORS = @as(c_int, 16); -pub inline fn ERR_PACK(lib: anytype, reason: anytype) @TypeOf(((@import("std").zig.c_translation.cast(u32, lib) & @as(c_int, 0xff)) << @as(c_int, 24)) | (@import("std").zig.c_translation.cast(u32, reason) & @as(c_int, 0xfff))) { - return ((@import("std").zig.c_translation.cast(u32, lib) & @as(c_int, 0xff)) << @as(c_int, 24)) | (@import("std").zig.c_translation.cast(u32, reason) & @as(c_int, 0xfff)); -} -pub const OPENSSL_HEADER_EX_DATA_H = ""; -pub const OPENSSL_HEADER_STACK_H = ""; -pub inline fn DEFINE_STACK_OF(@"type": anytype) @TypeOf(DEFINE_NAMED_STACK_OF(@"type", @"type")) { - return DEFINE_NAMED_STACK_OF(@"type", @"type"); -} -pub const OPENSSL_HEADER_THREAD_H = ""; -pub const CRYPTO_LOCK = @as(c_int, 1); -pub const CRYPTO_UNLOCK = @as(c_int, 2); -pub const CRYPTO_READ = @as(c_int, 4); -pub const CRYPTO_WRITE = @as(c_int, 8); -pub const BIO_RR_CONNECT = @as(c_int, 0x02); -pub const BIO_RR_ACCEPT = @as(c_int, 0x03); -pub const BIO_CB_FREE = @as(c_int, 0x01); -pub const BIO_CB_READ = @as(c_int, 0x02); -pub const BIO_CB_WRITE = @as(c_int, 0x03); -pub const BIO_CB_PUTS = @as(c_int, 0x04); -pub const BIO_CB_GETS = @as(c_int, 0x05); -pub const BIO_CB_CTRL = @as(c_int, 0x06); -pub const BIO_CB_RETURN = @as(c_int, 0x80); -pub const BIO_NOCLOSE = @as(c_int, 0); -pub const BIO_CLOSE = @as(c_int, 1); -pub const BIO_CTRL_DGRAM_QUERY_MTU = @as(c_int, 40); -pub const BIO_CTRL_DGRAM_SET_MTU = @as(c_int, 42); -pub const BIO_CTRL_DGRAM_MTU_EXCEEDED = @as(c_int, 43); -pub const BIO_CTRL_DGRAM_GET_PEER = @as(c_int, 46); -pub const BIO_CTRL_DGRAM_GET_FALLBACK_MTU = @as(c_int, 47); -pub const BIO_CTRL_RESET = @as(c_int, 1); -pub const BIO_CTRL_EOF = @as(c_int, 2); -pub const BIO_CTRL_INFO = @as(c_int, 3); -pub const BIO_CTRL_GET_CLOSE = @as(c_int, 8); -pub const BIO_CTRL_SET_CLOSE = @as(c_int, 9); -pub const BIO_CTRL_PENDING = @as(c_int, 10); -pub const BIO_CTRL_FLUSH = @as(c_int, 11); -pub const BIO_CTRL_WPENDING = @as(c_int, 13); -pub const BIO_CTRL_SET_CALLBACK = @as(c_int, 14); -pub const BIO_CTRL_GET_CALLBACK = @as(c_int, 15); -pub const BIO_CTRL_SET = @as(c_int, 4); -pub const BIO_CTRL_GET = @as(c_int, 5); -pub const BIO_CTRL_PUSH = @as(c_int, 6); -pub const BIO_CTRL_POP = @as(c_int, 7); -pub const BIO_CTRL_DUP = @as(c_int, 12); -pub const BIO_CTRL_SET_FILENAME = @as(c_int, 30); -pub const BIO_FLAGS_READ = @as(c_int, 0x01); -pub const BIO_FLAGS_WRITE = @as(c_int, 0x02); -pub const BIO_FLAGS_IO_SPECIAL = @as(c_int, 0x04); -pub const BIO_FLAGS_RWS = (BIO_FLAGS_READ | BIO_FLAGS_WRITE) | BIO_FLAGS_IO_SPECIAL; -pub const BIO_FLAGS_SHOULD_RETRY = @as(c_int, 0x08); -pub const BIO_FLAGS_BASE64_NO_NL = @as(c_int, 0x100); -pub const BIO_FLAGS_MEM_RDONLY = @as(c_int, 0x200); -pub const BIO_TYPE_NONE = @as(c_int, 0); -pub const BIO_TYPE_MEM = @as(c_int, 1) | @as(c_int, 0x0400); -pub const BIO_TYPE_FILE = @as(c_int, 2) | @as(c_int, 0x0400); -pub const BIO_TYPE_FD = (@as(c_int, 4) | @as(c_int, 0x0400)) | @as(c_int, 0x0100); -pub const BIO_TYPE_SOCKET = (@as(c_int, 5) | @as(c_int, 0x0400)) | @as(c_int, 0x0100); -pub const BIO_TYPE_NULL = @as(c_int, 6) | @as(c_int, 0x0400); -pub const BIO_TYPE_SSL = @as(c_int, 7) | @as(c_int, 0x0200); -pub const BIO_TYPE_MD = @as(c_int, 8) | @as(c_int, 0x0200); -pub const BIO_TYPE_BUFFER = @as(c_int, 9) | @as(c_int, 0x0200); -pub const BIO_TYPE_CIPHER = @as(c_int, 10) | @as(c_int, 0x0200); -pub const BIO_TYPE_BASE64 = @as(c_int, 11) | @as(c_int, 0x0200); -pub const BIO_TYPE_CONNECT = (@as(c_int, 12) | @as(c_int, 0x0400)) | @as(c_int, 0x0100); -pub const BIO_TYPE_ACCEPT = (@as(c_int, 13) | @as(c_int, 0x0400)) | @as(c_int, 0x0100); -pub const BIO_TYPE_PROXY_CLIENT = @as(c_int, 14) | @as(c_int, 0x0200); -pub const BIO_TYPE_PROXY_SERVER = @as(c_int, 15) | @as(c_int, 0x0200); -pub const BIO_TYPE_NBIO_TEST = @as(c_int, 16) | @as(c_int, 0x0200); -pub const BIO_TYPE_NULL_FILTER = @as(c_int, 17) | @as(c_int, 0x0200); -pub const BIO_TYPE_BER = @as(c_int, 18) | @as(c_int, 0x0200); -pub const BIO_TYPE_BIO = @as(c_int, 19) | @as(c_int, 0x0400); -pub const BIO_TYPE_LINEBUFFER = @as(c_int, 20) | @as(c_int, 0x0200); -pub const BIO_TYPE_DGRAM = (@as(c_int, 21) | @as(c_int, 0x0400)) | @as(c_int, 0x0100); -pub const BIO_TYPE_ASN1 = @as(c_int, 22) | @as(c_int, 0x0200); -pub const BIO_TYPE_COMP = @as(c_int, 23) | @as(c_int, 0x0200); -pub const BIO_TYPE_DESCRIPTOR = @as(c_int, 0x0100); -pub const BIO_TYPE_FILTER = @as(c_int, 0x0200); -pub const BIO_TYPE_SOURCE_SINK = @as(c_int, 0x0400); -pub const BIO_TYPE_START = @as(c_int, 128); -pub const BIO_C_SET_CONNECT = @as(c_int, 100); -pub const BIO_C_DO_STATE_MACHINE = @as(c_int, 101); -pub const BIO_C_SET_NBIO = @as(c_int, 102); -pub const BIO_C_SET_PROXY_PARAM = @as(c_int, 103); -pub const BIO_C_SET_FD = @as(c_int, 104); -pub const BIO_C_GET_FD = @as(c_int, 105); -pub const BIO_C_SET_FILE_PTR = @as(c_int, 106); -pub const BIO_C_GET_FILE_PTR = @as(c_int, 107); -pub const BIO_C_SET_FILENAME = @as(c_int, 108); -pub const BIO_C_SET_SSL = @as(c_int, 109); -pub const BIO_C_GET_SSL = @as(c_int, 110); -pub const BIO_C_SET_MD = @as(c_int, 111); -pub const BIO_C_GET_MD = @as(c_int, 112); -pub const BIO_C_GET_CIPHER_STATUS = @as(c_int, 113); -pub const BIO_C_SET_BUF_MEM = @as(c_int, 114); -pub const BIO_C_GET_BUF_MEM_PTR = @as(c_int, 115); -pub const BIO_C_GET_BUFF_NUM_LINES = @as(c_int, 116); -pub const BIO_C_SET_BUFF_SIZE = @as(c_int, 117); -pub const BIO_C_SET_ACCEPT = @as(c_int, 118); -pub const BIO_C_SSL_MODE = @as(c_int, 119); -pub const BIO_C_GET_MD_CTX = @as(c_int, 120); -pub const BIO_C_GET_PROXY_PARAM = @as(c_int, 121); -pub const BIO_C_SET_BUFF_READ_DATA = @as(c_int, 122); -pub const BIO_C_GET_ACCEPT = @as(c_int, 124); -pub const BIO_C_SET_SSL_RENEGOTIATE_BYTES = @as(c_int, 125); -pub const BIO_C_GET_SSL_NUM_RENEGOTIATES = @as(c_int, 126); -pub const BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT = @as(c_int, 127); -pub const BIO_C_FILE_SEEK = @as(c_int, 128); -pub const BIO_C_GET_CIPHER_CTX = @as(c_int, 129); -pub const BIO_C_SET_BUF_MEM_EOF_RETURN = @as(c_int, 130); -pub const BIO_C_SET_BIND_MODE = @as(c_int, 131); -pub const BIO_C_GET_BIND_MODE = @as(c_int, 132); -pub const BIO_C_FILE_TELL = @as(c_int, 133); -pub const BIO_C_GET_SOCKS = @as(c_int, 134); -pub const BIO_C_SET_SOCKS = @as(c_int, 135); -pub const BIO_C_SET_WRITE_BUF_SIZE = @as(c_int, 136); -pub const BIO_C_GET_WRITE_BUF_SIZE = @as(c_int, 137); -pub const BIO_C_GET_WRITE_GUARANTEE = @as(c_int, 140); -pub const BIO_C_GET_READ_REQUEST = @as(c_int, 141); -pub const BIO_C_SHUTDOWN_WR = @as(c_int, 142); -pub const BIO_C_NREAD0 = @as(c_int, 143); -pub const BIO_C_NREAD = @as(c_int, 144); -pub const BIO_C_NWRITE0 = @as(c_int, 145); -pub const BIO_C_NWRITE = @as(c_int, 146); -pub const BIO_C_RESET_READ_REQUEST = @as(c_int, 147); -pub const BIO_C_SET_MD_CTX = @as(c_int, 148); -pub const BIO_C_SET_PREFIX = @as(c_int, 149); -pub const BIO_C_GET_PREFIX = @as(c_int, 150); -pub const BIO_C_SET_SUFFIX = @as(c_int, 151); -pub const BIO_C_GET_SUFFIX = @as(c_int, 152); -pub const BIO_C_SET_EX_ARG = @as(c_int, 153); -pub const BIO_C_GET_EX_ARG = @as(c_int, 154); -pub const BIO_R_BAD_FOPEN_MODE = @as(c_int, 100); -pub const BIO_R_BROKEN_PIPE = @as(c_int, 101); -pub const BIO_R_CONNECT_ERROR = @as(c_int, 102); -pub const BIO_R_ERROR_SETTING_NBIO = @as(c_int, 103); -pub const BIO_R_INVALID_ARGUMENT = @as(c_int, 104); -pub const BIO_R_IN_USE = @as(c_int, 105); -pub const BIO_R_KEEPALIVE = @as(c_int, 106); -pub const BIO_R_NBIO_CONNECT_ERROR = @as(c_int, 107); -pub const BIO_R_NO_HOSTNAME_SPECIFIED = @as(c_int, 108); -pub const BIO_R_NO_PORT_SPECIFIED = @as(c_int, 109); -pub const BIO_R_NO_SUCH_FILE = @as(c_int, 110); -pub const BIO_R_NULL_PARAMETER = @as(c_int, 111); -pub const BIO_R_SYS_LIB = @as(c_int, 112); -pub const BIO_R_UNABLE_TO_CREATE_SOCKET = @as(c_int, 113); -pub const BIO_R_UNINITIALIZED = @as(c_int, 114); -pub const BIO_R_UNSUPPORTED_METHOD = @as(c_int, 115); -pub const BIO_R_WRITE_TO_READ_ONLY_BIO = @as(c_int, 116); -pub const OPENSSL_HEADER_PEM_H = ""; -pub const OPENSSL_HEADER_BASE64_H = ""; -pub const OPENSSL_HEADER_CIPHER_H = ""; -pub const EVP_CIPH_STREAM_CIPHER = @as(c_int, 0x0); -pub const EVP_CIPH_ECB_MODE = @as(c_int, 0x1); -pub const EVP_CIPH_CBC_MODE = @as(c_int, 0x2); -pub const EVP_CIPH_CFB_MODE = @as(c_int, 0x3); -pub const EVP_CIPH_OFB_MODE = @as(c_int, 0x4); -pub const EVP_CIPH_CTR_MODE = @as(c_int, 0x5); -pub const EVP_CIPH_GCM_MODE = @as(c_int, 0x6); -pub const EVP_CIPH_XTS_MODE = @as(c_int, 0x7); -pub const EVP_CIPH_VARIABLE_LENGTH = @as(c_int, 0x40); -pub const EVP_CIPH_ALWAYS_CALL_INIT = @as(c_int, 0x80); -pub const EVP_CIPH_CUSTOM_IV = @as(c_int, 0x100); -pub const EVP_CIPH_CTRL_INIT = @as(c_int, 0x200); -pub const EVP_CIPH_FLAG_CUSTOM_CIPHER = @as(c_int, 0x400); -pub const EVP_CIPH_FLAG_AEAD_CIPHER = @as(c_int, 0x800); -pub const EVP_CIPH_CUSTOM_COPY = @as(c_int, 0x1000); -pub const EVP_CIPH_FLAG_NON_FIPS_ALLOW = @as(c_int, 0); -pub const EVP_CIPH_CCM_MODE = -@as(c_int, 1); -pub const EVP_CIPH_OCB_MODE = -@as(c_int, 2); -pub const EVP_CIPH_WRAP_MODE = -@as(c_int, 3); -pub const EVP_CIPHER_CTX_FLAG_WRAP_ALLOW = @as(c_int, 0); -pub const EVP_CIPH_NO_PADDING = @as(c_int, 0x800); -pub const EVP_CTRL_INIT = @as(c_int, 0x0); -pub const EVP_CTRL_SET_KEY_LENGTH = @as(c_int, 0x1); -pub const EVP_CTRL_GET_RC2_KEY_BITS = @as(c_int, 0x2); -pub const EVP_CTRL_SET_RC2_KEY_BITS = @as(c_int, 0x3); -pub const EVP_CTRL_GET_RC5_ROUNDS = @as(c_int, 0x4); -pub const EVP_CTRL_SET_RC5_ROUNDS = @as(c_int, 0x5); -pub const EVP_CTRL_RAND_KEY = @as(c_int, 0x6); -pub const EVP_CTRL_PBE_PRF_NID = @as(c_int, 0x7); -pub const EVP_CTRL_COPY = @as(c_int, 0x8); -pub const EVP_CTRL_AEAD_SET_IVLEN = @as(c_int, 0x9); -pub const EVP_CTRL_AEAD_GET_TAG = @as(c_int, 0x10); -pub const EVP_CTRL_AEAD_SET_TAG = @as(c_int, 0x11); -pub const EVP_CTRL_AEAD_SET_IV_FIXED = @as(c_int, 0x12); -pub const EVP_CTRL_GCM_IV_GEN = @as(c_int, 0x13); -pub const EVP_CTRL_AEAD_SET_MAC_KEY = @as(c_int, 0x17); -pub const EVP_CTRL_GCM_SET_IV_INV = @as(c_int, 0x18); -pub const EVP_GCM_TLS_FIXED_IV_LEN = @as(c_int, 4); -pub const EVP_GCM_TLS_EXPLICIT_IV_LEN = @as(c_int, 8); -pub const EVP_GCM_TLS_TAG_LEN = @as(c_int, 16); -pub const EVP_CTRL_GCM_SET_IVLEN = EVP_CTRL_AEAD_SET_IVLEN; -pub const EVP_CTRL_GCM_GET_TAG = EVP_CTRL_AEAD_GET_TAG; -pub const EVP_CTRL_GCM_SET_TAG = EVP_CTRL_AEAD_SET_TAG; -pub const EVP_CTRL_GCM_SET_IV_FIXED = EVP_CTRL_AEAD_SET_IV_FIXED; -pub const EVP_MAX_KEY_LENGTH = @as(c_int, 64); -pub const EVP_MAX_IV_LENGTH = @as(c_int, 16); -pub const EVP_MAX_BLOCK_LENGTH = @as(c_int, 32); -pub const CIPHER_R_AES_KEY_SETUP_FAILED = @as(c_int, 100); -pub const CIPHER_R_BAD_DECRYPT = @as(c_int, 101); -pub const CIPHER_R_BAD_KEY_LENGTH = @as(c_int, 102); -pub const CIPHER_R_BUFFER_TOO_SMALL = @as(c_int, 103); -pub const CIPHER_R_CTRL_NOT_IMPLEMENTED = @as(c_int, 104); -pub const CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED = @as(c_int, 105); -pub const CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH = @as(c_int, 106); -pub const CIPHER_R_INITIALIZATION_ERROR = @as(c_int, 107); -pub const CIPHER_R_INPUT_NOT_INITIALIZED = @as(c_int, 108); -pub const CIPHER_R_INVALID_AD_SIZE = @as(c_int, 109); -pub const CIPHER_R_INVALID_KEY_LENGTH = @as(c_int, 110); -pub const CIPHER_R_INVALID_NONCE_SIZE = @as(c_int, 111); -pub const CIPHER_R_INVALID_OPERATION = @as(c_int, 112); -pub const CIPHER_R_IV_TOO_LARGE = @as(c_int, 113); -pub const CIPHER_R_NO_CIPHER_SET = @as(c_int, 114); -pub const CIPHER_R_OUTPUT_ALIASES_INPUT = @as(c_int, 115); -pub const CIPHER_R_TAG_TOO_LARGE = @as(c_int, 116); -pub const CIPHER_R_TOO_LARGE = @as(c_int, 117); -pub const CIPHER_R_UNSUPPORTED_AD_SIZE = @as(c_int, 118); -pub const CIPHER_R_UNSUPPORTED_INPUT_SIZE = @as(c_int, 119); -pub const CIPHER_R_UNSUPPORTED_KEY_SIZE = @as(c_int, 120); -pub const CIPHER_R_UNSUPPORTED_NONCE_SIZE = @as(c_int, 121); -pub const CIPHER_R_UNSUPPORTED_TAG_SIZE = @as(c_int, 122); -pub const CIPHER_R_WRONG_FINAL_BLOCK_LENGTH = @as(c_int, 123); -pub const CIPHER_R_NO_DIRECTION_SET = @as(c_int, 124); -pub const CIPHER_R_INVALID_NONCE = @as(c_int, 125); -pub const OPENSSL_HEADER_DIGEST_H = ""; -pub const EVP_MAX_MD_SIZE = @as(c_int, 64); -pub const EVP_MAX_MD_BLOCK_SIZE = @as(c_int, 144); -pub const EVP_MD_FLAG_PKEY_DIGEST = @as(c_int, 1); -pub const EVP_MD_FLAG_DIGALGID_ABSENT = @as(c_int, 2); -pub const EVP_MD_FLAG_XOF = @as(c_int, 4); -pub const EVP_MD_CTX_FLAG_NON_FIPS_ALLOW = @as(c_int, 0); -pub const DIGEST_R_INPUT_NOT_INITIALIZED = @as(c_int, 100); -pub const DIGEST_R_DECODE_ERROR = @as(c_int, 101); -pub const DIGEST_R_UNKNOWN_HASH = @as(c_int, 102); -pub const OPENSSL_HEADER_EVP_H = ""; -pub const OPENSSL_HEADER_EVP_ERRORS_H = ""; -pub const EVP_R_BUFFER_TOO_SMALL = @as(c_int, 100); -pub const EVP_R_COMMAND_NOT_SUPPORTED = @as(c_int, 101); -pub const EVP_R_DECODE_ERROR = @as(c_int, 102); -pub const EVP_R_DIFFERENT_KEY_TYPES = @as(c_int, 103); -pub const EVP_R_DIFFERENT_PARAMETERS = @as(c_int, 104); -pub const EVP_R_ENCODE_ERROR = @as(c_int, 105); -pub const EVP_R_EXPECTING_AN_EC_KEY_KEY = @as(c_int, 106); -pub const EVP_R_EXPECTING_AN_RSA_KEY = @as(c_int, 107); -pub const EVP_R_EXPECTING_A_DSA_KEY = @as(c_int, 108); -pub const EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE = @as(c_int, 109); -pub const EVP_R_INVALID_DIGEST_LENGTH = @as(c_int, 110); -pub const EVP_R_INVALID_DIGEST_TYPE = @as(c_int, 111); -pub const EVP_R_INVALID_KEYBITS = @as(c_int, 112); -pub const EVP_R_INVALID_MGF1_MD = @as(c_int, 113); -pub const EVP_R_INVALID_OPERATION = @as(c_int, 114); -pub const EVP_R_INVALID_PADDING_MODE = @as(c_int, 115); -pub const EVP_R_INVALID_PSS_SALTLEN = @as(c_int, 116); -pub const EVP_R_KEYS_NOT_SET = @as(c_int, 117); -pub const EVP_R_MISSING_PARAMETERS = @as(c_int, 118); -pub const EVP_R_NO_DEFAULT_DIGEST = @as(c_int, 119); -pub const EVP_R_NO_KEY_SET = @as(c_int, 120); -pub const EVP_R_NO_MDC2_SUPPORT = @as(c_int, 121); -pub const EVP_R_NO_NID_FOR_CURVE = @as(c_int, 122); -pub const EVP_R_NO_OPERATION_SET = @as(c_int, 123); -pub const EVP_R_NO_PARAMETERS_SET = @as(c_int, 124); -pub const EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE = @as(c_int, 125); -pub const EVP_R_OPERATON_NOT_INITIALIZED = @as(c_int, 126); -pub const EVP_R_UNKNOWN_PUBLIC_KEY_TYPE = @as(c_int, 127); -pub const EVP_R_UNSUPPORTED_ALGORITHM = @as(c_int, 128); -pub const EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE = @as(c_int, 129); -pub const EVP_R_NOT_A_PRIVATE_KEY = @as(c_int, 130); -pub const EVP_R_INVALID_SIGNATURE = @as(c_int, 131); -pub const EVP_R_MEMORY_LIMIT_EXCEEDED = @as(c_int, 132); -pub const EVP_R_INVALID_PARAMETERS = @as(c_int, 133); -pub const EVP_R_INVALID_PEER_KEY = @as(c_int, 134); -pub const EVP_R_NOT_XOF_OR_INVALID_LENGTH = @as(c_int, 135); -pub const EVP_R_EMPTY_PSK = @as(c_int, 136); -pub const EVP_R_INVALID_BUFFER_SIZE = @as(c_int, 137); -pub const OPENSSL_HEADER_AEAD_H = ""; -pub const EVP_AEAD_MAX_KEY_LENGTH = @as(c_int, 80); -pub const EVP_AEAD_MAX_NONCE_LENGTH = @as(c_int, 24); -pub const EVP_AEAD_MAX_OVERHEAD = @as(c_int, 64); -pub const EVP_AEAD_DEFAULT_TAG_LENGTH = @as(c_int, 0); -pub const OPENSSL_HEADER_NID_H = ""; -pub const SN_undef = "UNDEF"; -pub const LN_undef = "undefined"; -pub const NID_undef = @as(c_int, 0); -pub const OBJ_undef = @as(c_long, 0); -pub const SN_rsadsi = "rsadsi"; -pub const LN_rsadsi = "RSA Data Security, Inc."; -pub const NID_rsadsi = @as(c_int, 1); -pub const OBJ_rsadsi = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - break :blk @as(c_long, 113549); -}; -pub const SN_pkcs = "pkcs"; -pub const LN_pkcs = "RSA Data Security, Inc. PKCS"; -pub const NID_pkcs = @as(c_int, 2); -pub const OBJ_pkcs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - break :blk @as(c_long, 1); -}; -pub const SN_md2 = "MD2"; -pub const LN_md2 = "md2"; -pub const NID_md2 = @as(c_int, 3); -pub const OBJ_md2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_md5 = "MD5"; -pub const LN_md5 = "md5"; -pub const NID_md5 = @as(c_int, 4); -pub const OBJ_md5 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 5); -}; -pub const SN_rc4 = "RC4"; -pub const LN_rc4 = "rc4"; -pub const NID_rc4 = @as(c_int, 5); -pub const OBJ_rc4 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const LN_rsaEncryption = "rsaEncryption"; -pub const NID_rsaEncryption = @as(c_int, 6); -pub const OBJ_rsaEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_md2WithRSAEncryption = "RSA-MD2"; -pub const LN_md2WithRSAEncryption = "md2WithRSAEncryption"; -pub const NID_md2WithRSAEncryption = @as(c_int, 7); -pub const OBJ_md2WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_md5WithRSAEncryption = "RSA-MD5"; -pub const LN_md5WithRSAEncryption = "md5WithRSAEncryption"; -pub const NID_md5WithRSAEncryption = @as(c_int, 8); -pub const OBJ_md5WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_pbeWithMD2AndDES_CBC = "PBE-MD2-DES"; -pub const LN_pbeWithMD2AndDES_CBC = "pbeWithMD2AndDES-CBC"; -pub const NID_pbeWithMD2AndDES_CBC = @as(c_int, 9); -pub const OBJ_pbeWithMD2AndDES_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 1); -}; -pub const SN_pbeWithMD5AndDES_CBC = "PBE-MD5-DES"; -pub const LN_pbeWithMD5AndDES_CBC = "pbeWithMD5AndDES-CBC"; -pub const NID_pbeWithMD5AndDES_CBC = @as(c_int, 10); -pub const OBJ_pbeWithMD5AndDES_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 3); -}; -pub const SN_X500 = "X500"; -pub const LN_X500 = "directory services (X.500)"; -pub const NID_X500 = @as(c_int, 11); -pub const OBJ_X500 = blk: { - _ = @as(c_long, 2); - break :blk @as(c_long, 5); -}; -pub const SN_X509 = "X509"; -pub const NID_X509 = @as(c_int, 12); -pub const OBJ_X509 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - break :blk @as(c_long, 4); -}; -pub const SN_commonName = "CN"; -pub const LN_commonName = "commonName"; -pub const NID_commonName = @as(c_int, 13); -pub const OBJ_commonName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 3); -}; -pub const SN_countryName = "C"; -pub const LN_countryName = "countryName"; -pub const NID_countryName = @as(c_int, 14); -pub const OBJ_countryName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 6); -}; -pub const SN_localityName = "L"; -pub const LN_localityName = "localityName"; -pub const NID_localityName = @as(c_int, 15); -pub const OBJ_localityName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 7); -}; -pub const SN_stateOrProvinceName = "ST"; -pub const LN_stateOrProvinceName = "stateOrProvinceName"; -pub const NID_stateOrProvinceName = @as(c_int, 16); -pub const OBJ_stateOrProvinceName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 8); -}; -pub const SN_organizationName = "O"; -pub const LN_organizationName = "organizationName"; -pub const NID_organizationName = @as(c_int, 17); -pub const OBJ_organizationName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 10); -}; -pub const SN_organizationalUnitName = "OU"; -pub const LN_organizationalUnitName = "organizationalUnitName"; -pub const NID_organizationalUnitName = @as(c_int, 18); -pub const OBJ_organizationalUnitName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 11); -}; -pub const SN_rsa = "RSA"; -pub const LN_rsa = "rsa"; -pub const NID_rsa = @as(c_int, 19); -pub const OBJ_rsa = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_pkcs7 = "pkcs7"; -pub const NID_pkcs7 = @as(c_int, 20); -pub const OBJ_pkcs7 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const LN_pkcs7_data = "pkcs7-data"; -pub const NID_pkcs7_data = @as(c_int, 21); -pub const OBJ_pkcs7_data = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - break :blk @as(c_long, 1); -}; -pub const LN_pkcs7_signed = "pkcs7-signedData"; -pub const NID_pkcs7_signed = @as(c_int, 22); -pub const OBJ_pkcs7_signed = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - break :blk @as(c_long, 2); -}; -pub const LN_pkcs7_enveloped = "pkcs7-envelopedData"; -pub const NID_pkcs7_enveloped = @as(c_int, 23); -pub const OBJ_pkcs7_enveloped = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - break :blk @as(c_long, 3); -}; -pub const LN_pkcs7_signedAndEnveloped = "pkcs7-signedAndEnvelopedData"; -pub const NID_pkcs7_signedAndEnveloped = @as(c_int, 24); -pub const OBJ_pkcs7_signedAndEnveloped = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - break :blk @as(c_long, 4); -}; -pub const LN_pkcs7_digest = "pkcs7-digestData"; -pub const NID_pkcs7_digest = @as(c_int, 25); -pub const OBJ_pkcs7_digest = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - break :blk @as(c_long, 5); -}; -pub const LN_pkcs7_encrypted = "pkcs7-encryptedData"; -pub const NID_pkcs7_encrypted = @as(c_int, 26); -pub const OBJ_pkcs7_encrypted = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - break :blk @as(c_long, 6); -}; -pub const SN_pkcs3 = "pkcs3"; -pub const NID_pkcs3 = @as(c_int, 27); -pub const OBJ_pkcs3 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const LN_dhKeyAgreement = "dhKeyAgreement"; -pub const NID_dhKeyAgreement = @as(c_int, 28); -pub const OBJ_dhKeyAgreement = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_des_ecb = "DES-ECB"; -pub const LN_des_ecb = "des-ecb"; -pub const NID_des_ecb = @as(c_int, 29); -pub const OBJ_des_ecb = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 6); -}; -pub const SN_des_cfb64 = "DES-CFB"; -pub const LN_des_cfb64 = "des-cfb"; -pub const NID_des_cfb64 = @as(c_int, 30); -pub const OBJ_des_cfb64 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 9); -}; -pub const SN_des_cbc = "DES-CBC"; -pub const LN_des_cbc = "des-cbc"; -pub const NID_des_cbc = @as(c_int, 31); -pub const OBJ_des_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 7); -}; -pub const SN_des_ede_ecb = "DES-EDE"; -pub const LN_des_ede_ecb = "des-ede"; -pub const NID_des_ede_ecb = @as(c_int, 32); -pub const OBJ_des_ede_ecb = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 17); -}; -pub const SN_des_ede3_ecb = "DES-EDE3"; -pub const LN_des_ede3_ecb = "des-ede3"; -pub const NID_des_ede3_ecb = @as(c_int, 33); -pub const SN_idea_cbc = "IDEA-CBC"; -pub const LN_idea_cbc = "idea-cbc"; -pub const NID_idea_cbc = @as(c_int, 34); -pub const OBJ_idea_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 188); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_idea_cfb64 = "IDEA-CFB"; -pub const LN_idea_cfb64 = "idea-cfb"; -pub const NID_idea_cfb64 = @as(c_int, 35); -pub const SN_idea_ecb = "IDEA-ECB"; -pub const LN_idea_ecb = "idea-ecb"; -pub const NID_idea_ecb = @as(c_int, 36); -pub const SN_rc2_cbc = "RC2-CBC"; -pub const LN_rc2_cbc = "rc2-cbc"; -pub const NID_rc2_cbc = @as(c_int, 37); -pub const OBJ_rc2_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_rc2_ecb = "RC2-ECB"; -pub const LN_rc2_ecb = "rc2-ecb"; -pub const NID_rc2_ecb = @as(c_int, 38); -pub const SN_rc2_cfb64 = "RC2-CFB"; -pub const LN_rc2_cfb64 = "rc2-cfb"; -pub const NID_rc2_cfb64 = @as(c_int, 39); -pub const SN_rc2_ofb64 = "RC2-OFB"; -pub const LN_rc2_ofb64 = "rc2-ofb"; -pub const NID_rc2_ofb64 = @as(c_int, 40); -pub const SN_sha = "SHA"; -pub const LN_sha = "sha"; -pub const NID_sha = @as(c_int, 41); -pub const OBJ_sha = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 18); -}; -pub const SN_shaWithRSAEncryption = "RSA-SHA"; -pub const LN_shaWithRSAEncryption = "shaWithRSAEncryption"; -pub const NID_shaWithRSAEncryption = @as(c_int, 42); -pub const OBJ_shaWithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 15); -}; -pub const SN_des_ede_cbc = "DES-EDE-CBC"; -pub const LN_des_ede_cbc = "des-ede-cbc"; -pub const NID_des_ede_cbc = @as(c_int, 43); -pub const SN_des_ede3_cbc = "DES-EDE3-CBC"; -pub const LN_des_ede3_cbc = "des-ede3-cbc"; -pub const NID_des_ede3_cbc = @as(c_int, 44); -pub const OBJ_des_ede3_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 3); - break :blk @as(c_long, 7); -}; -pub const SN_des_ofb64 = "DES-OFB"; -pub const LN_des_ofb64 = "des-ofb"; -pub const NID_des_ofb64 = @as(c_int, 45); -pub const OBJ_des_ofb64 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 8); -}; -pub const SN_idea_ofb64 = "IDEA-OFB"; -pub const LN_idea_ofb64 = "idea-ofb"; -pub const NID_idea_ofb64 = @as(c_int, 46); -pub const SN_pkcs9 = "pkcs9"; -pub const NID_pkcs9 = @as(c_int, 47); -pub const OBJ_pkcs9 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - break :blk @as(c_long, 9); -}; -pub const LN_pkcs9_emailAddress = "emailAddress"; -pub const NID_pkcs9_emailAddress = @as(c_int, 48); -pub const OBJ_pkcs9_emailAddress = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 1); -}; -pub const LN_pkcs9_unstructuredName = "unstructuredName"; -pub const NID_pkcs9_unstructuredName = @as(c_int, 49); -pub const OBJ_pkcs9_unstructuredName = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 2); -}; -pub const LN_pkcs9_contentType = "contentType"; -pub const NID_pkcs9_contentType = @as(c_int, 50); -pub const OBJ_pkcs9_contentType = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 3); -}; -pub const LN_pkcs9_messageDigest = "messageDigest"; -pub const NID_pkcs9_messageDigest = @as(c_int, 51); -pub const OBJ_pkcs9_messageDigest = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 4); -}; -pub const LN_pkcs9_signingTime = "signingTime"; -pub const NID_pkcs9_signingTime = @as(c_int, 52); -pub const OBJ_pkcs9_signingTime = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 5); -}; -pub const LN_pkcs9_countersignature = "countersignature"; -pub const NID_pkcs9_countersignature = @as(c_int, 53); -pub const OBJ_pkcs9_countersignature = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 6); -}; -pub const LN_pkcs9_challengePassword = "challengePassword"; -pub const NID_pkcs9_challengePassword = @as(c_int, 54); -pub const OBJ_pkcs9_challengePassword = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 7); -}; -pub const LN_pkcs9_unstructuredAddress = "unstructuredAddress"; -pub const NID_pkcs9_unstructuredAddress = @as(c_int, 55); -pub const OBJ_pkcs9_unstructuredAddress = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 8); -}; -pub const LN_pkcs9_extCertAttributes = "extendedCertificateAttributes"; -pub const NID_pkcs9_extCertAttributes = @as(c_int, 56); -pub const OBJ_pkcs9_extCertAttributes = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 9); -}; -pub const SN_netscape = "Netscape"; -pub const LN_netscape = "Netscape Communications Corp."; -pub const NID_netscape = @as(c_int, 57); -pub const OBJ_netscape = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - break :blk @as(c_long, 113730); -}; -pub const SN_netscape_cert_extension = "nsCertExt"; -pub const LN_netscape_cert_extension = "Netscape Certificate Extension"; -pub const NID_netscape_cert_extension = @as(c_int, 58); -pub const OBJ_netscape_cert_extension = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - break :blk @as(c_long, 1); -}; -pub const SN_netscape_data_type = "nsDataType"; -pub const LN_netscape_data_type = "Netscape Data Type"; -pub const NID_netscape_data_type = @as(c_int, 59); -pub const OBJ_netscape_data_type = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - break :blk @as(c_long, 2); -}; -pub const SN_des_ede_cfb64 = "DES-EDE-CFB"; -pub const LN_des_ede_cfb64 = "des-ede-cfb"; -pub const NID_des_ede_cfb64 = @as(c_int, 60); -pub const SN_des_ede3_cfb64 = "DES-EDE3-CFB"; -pub const LN_des_ede3_cfb64 = "des-ede3-cfb"; -pub const NID_des_ede3_cfb64 = @as(c_int, 61); -pub const SN_des_ede_ofb64 = "DES-EDE-OFB"; -pub const LN_des_ede_ofb64 = "des-ede-ofb"; -pub const NID_des_ede_ofb64 = @as(c_int, 62); -pub const SN_des_ede3_ofb64 = "DES-EDE3-OFB"; -pub const LN_des_ede3_ofb64 = "des-ede3-ofb"; -pub const NID_des_ede3_ofb64 = @as(c_int, 63); -pub const SN_sha1 = "SHA1"; -pub const LN_sha1 = "sha1"; -pub const NID_sha1 = @as(c_int, 64); -pub const OBJ_sha1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 26); -}; -pub const SN_sha1WithRSAEncryption = "RSA-SHA1"; -pub const LN_sha1WithRSAEncryption = "sha1WithRSAEncryption"; -pub const NID_sha1WithRSAEncryption = @as(c_int, 65); -pub const OBJ_sha1WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_dsaWithSHA = "DSA-SHA"; -pub const LN_dsaWithSHA = "dsaWithSHA"; -pub const NID_dsaWithSHA = @as(c_int, 66); -pub const OBJ_dsaWithSHA = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 13); -}; -pub const SN_dsa_2 = "DSA-old"; -pub const LN_dsa_2 = "dsaEncryption-old"; -pub const NID_dsa_2 = @as(c_int, 67); -pub const OBJ_dsa_2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 12); -}; -pub const SN_pbeWithSHA1AndRC2_CBC = "PBE-SHA1-RC2-64"; -pub const LN_pbeWithSHA1AndRC2_CBC = "pbeWithSHA1AndRC2-CBC"; -pub const NID_pbeWithSHA1AndRC2_CBC = @as(c_int, 68); -pub const OBJ_pbeWithSHA1AndRC2_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 11); -}; -pub const LN_id_pbkdf2 = "PBKDF2"; -pub const NID_id_pbkdf2 = @as(c_int, 69); -pub const OBJ_id_pbkdf2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 12); -}; -pub const SN_dsaWithSHA1_2 = "DSA-SHA1-old"; -pub const LN_dsaWithSHA1_2 = "dsaWithSHA1-old"; -pub const NID_dsaWithSHA1_2 = @as(c_int, 70); -pub const OBJ_dsaWithSHA1_2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 27); -}; -pub const SN_netscape_cert_type = "nsCertType"; -pub const LN_netscape_cert_type = "Netscape Cert Type"; -pub const NID_netscape_cert_type = @as(c_int, 71); -pub const OBJ_netscape_cert_type = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_netscape_base_url = "nsBaseUrl"; -pub const LN_netscape_base_url = "Netscape Base Url"; -pub const NID_netscape_base_url = @as(c_int, 72); -pub const OBJ_netscape_base_url = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_netscape_revocation_url = "nsRevocationUrl"; -pub const LN_netscape_revocation_url = "Netscape Revocation Url"; -pub const NID_netscape_revocation_url = @as(c_int, 73); -pub const OBJ_netscape_revocation_url = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_netscape_ca_revocation_url = "nsCaRevocationUrl"; -pub const LN_netscape_ca_revocation_url = "Netscape CA Revocation Url"; -pub const NID_netscape_ca_revocation_url = @as(c_int, 74); -pub const OBJ_netscape_ca_revocation_url = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_netscape_renewal_url = "nsRenewalUrl"; -pub const LN_netscape_renewal_url = "Netscape Renewal Url"; -pub const NID_netscape_renewal_url = @as(c_int, 75); -pub const OBJ_netscape_renewal_url = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_netscape_ca_policy_url = "nsCaPolicyUrl"; -pub const LN_netscape_ca_policy_url = "Netscape CA Policy Url"; -pub const NID_netscape_ca_policy_url = @as(c_int, 76); -pub const OBJ_netscape_ca_policy_url = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_netscape_ssl_server_name = "nsSslServerName"; -pub const LN_netscape_ssl_server_name = "Netscape SSL Server Name"; -pub const NID_netscape_ssl_server_name = @as(c_int, 77); -pub const OBJ_netscape_ssl_server_name = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 12); -}; -pub const SN_netscape_comment = "nsComment"; -pub const LN_netscape_comment = "Netscape Comment"; -pub const NID_netscape_comment = @as(c_int, 78); -pub const OBJ_netscape_comment = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 1); - break :blk @as(c_long, 13); -}; -pub const SN_netscape_cert_sequence = "nsCertSequence"; -pub const LN_netscape_cert_sequence = "Netscape Certificate Sequence"; -pub const NID_netscape_cert_sequence = @as(c_int, 79); -pub const OBJ_netscape_cert_sequence = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 2); - break :blk @as(c_long, 5); -}; -pub const SN_desx_cbc = "DESX-CBC"; -pub const LN_desx_cbc = "desx-cbc"; -pub const NID_desx_cbc = @as(c_int, 80); -pub const SN_id_ce = "id-ce"; -pub const NID_id_ce = @as(c_int, 81); -pub const OBJ_id_ce = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - break :blk @as(c_long, 29); -}; -pub const SN_subject_key_identifier = "subjectKeyIdentifier"; -pub const LN_subject_key_identifier = "X509v3 Subject Key Identifier"; -pub const NID_subject_key_identifier = @as(c_int, 82); -pub const OBJ_subject_key_identifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 14); -}; -pub const SN_key_usage = "keyUsage"; -pub const LN_key_usage = "X509v3 Key Usage"; -pub const NID_key_usage = @as(c_int, 83); -pub const OBJ_key_usage = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 15); -}; -pub const SN_private_key_usage_period = "privateKeyUsagePeriod"; -pub const LN_private_key_usage_period = "X509v3 Private Key Usage Period"; -pub const NID_private_key_usage_period = @as(c_int, 84); -pub const OBJ_private_key_usage_period = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 16); -}; -pub const SN_subject_alt_name = "subjectAltName"; -pub const LN_subject_alt_name = "X509v3 Subject Alternative Name"; -pub const NID_subject_alt_name = @as(c_int, 85); -pub const OBJ_subject_alt_name = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 17); -}; -pub const SN_issuer_alt_name = "issuerAltName"; -pub const LN_issuer_alt_name = "X509v3 Issuer Alternative Name"; -pub const NID_issuer_alt_name = @as(c_int, 86); -pub const OBJ_issuer_alt_name = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 18); -}; -pub const SN_basic_constraints = "basicConstraints"; -pub const LN_basic_constraints = "X509v3 Basic Constraints"; -pub const NID_basic_constraints = @as(c_int, 87); -pub const OBJ_basic_constraints = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 19); -}; -pub const SN_crl_number = "crlNumber"; -pub const LN_crl_number = "X509v3 CRL Number"; -pub const NID_crl_number = @as(c_int, 88); -pub const OBJ_crl_number = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 20); -}; -pub const SN_certificate_policies = "certificatePolicies"; -pub const LN_certificate_policies = "X509v3 Certificate Policies"; -pub const NID_certificate_policies = @as(c_int, 89); -pub const OBJ_certificate_policies = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 32); -}; -pub const SN_authority_key_identifier = "authorityKeyIdentifier"; -pub const LN_authority_key_identifier = "X509v3 Authority Key Identifier"; -pub const NID_authority_key_identifier = @as(c_int, 90); -pub const OBJ_authority_key_identifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 35); -}; -pub const SN_bf_cbc = "BF-CBC"; -pub const LN_bf_cbc = "bf-cbc"; -pub const NID_bf_cbc = @as(c_int, 91); -pub const OBJ_bf_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 3029); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_bf_ecb = "BF-ECB"; -pub const LN_bf_ecb = "bf-ecb"; -pub const NID_bf_ecb = @as(c_int, 92); -pub const SN_bf_cfb64 = "BF-CFB"; -pub const LN_bf_cfb64 = "bf-cfb"; -pub const NID_bf_cfb64 = @as(c_int, 93); -pub const SN_bf_ofb64 = "BF-OFB"; -pub const LN_bf_ofb64 = "bf-ofb"; -pub const NID_bf_ofb64 = @as(c_int, 94); -pub const SN_mdc2 = "MDC2"; -pub const LN_mdc2 = "mdc2"; -pub const NID_mdc2 = @as(c_int, 95); -pub const OBJ_mdc2 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 8); - _ = @as(c_long, 3); - break :blk @as(c_long, 101); -}; -pub const SN_mdc2WithRSA = "RSA-MDC2"; -pub const LN_mdc2WithRSA = "mdc2WithRSA"; -pub const NID_mdc2WithRSA = @as(c_int, 96); -pub const OBJ_mdc2WithRSA = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 8); - _ = @as(c_long, 3); - break :blk @as(c_long, 100); -}; -pub const SN_rc4_40 = "RC4-40"; -pub const LN_rc4_40 = "rc4-40"; -pub const NID_rc4_40 = @as(c_int, 97); -pub const SN_rc2_40_cbc = "RC2-40-CBC"; -pub const LN_rc2_40_cbc = "rc2-40-cbc"; -pub const NID_rc2_40_cbc = @as(c_int, 98); -pub const SN_givenName = "GN"; -pub const LN_givenName = "givenName"; -pub const NID_givenName = @as(c_int, 99); -pub const OBJ_givenName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 42); -}; -pub const SN_surname = "SN"; -pub const LN_surname = "surname"; -pub const NID_surname = @as(c_int, 100); -pub const OBJ_surname = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 4); -}; -pub const SN_initials = "initials"; -pub const LN_initials = "initials"; -pub const NID_initials = @as(c_int, 101); -pub const OBJ_initials = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 43); -}; -pub const SN_crl_distribution_points = "crlDistributionPoints"; -pub const LN_crl_distribution_points = "X509v3 CRL Distribution Points"; -pub const NID_crl_distribution_points = @as(c_int, 103); -pub const OBJ_crl_distribution_points = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 31); -}; -pub const SN_md5WithRSA = "RSA-NP-MD5"; -pub const LN_md5WithRSA = "md5WithRSA"; -pub const NID_md5WithRSA = @as(c_int, 104); -pub const OBJ_md5WithRSA = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const LN_serialNumber = "serialNumber"; -pub const NID_serialNumber = @as(c_int, 105); -pub const OBJ_serialNumber = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 5); -}; -pub const SN_title = "title"; -pub const LN_title = "title"; -pub const NID_title = @as(c_int, 106); -pub const OBJ_title = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 12); -}; -pub const LN_description = "description"; -pub const NID_description = @as(c_int, 107); -pub const OBJ_description = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 13); -}; -pub const SN_cast5_cbc = "CAST5-CBC"; -pub const LN_cast5_cbc = "cast5-cbc"; -pub const NID_cast5_cbc = @as(c_int, 108); -pub const OBJ_cast5_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113533); - _ = @as(c_long, 7); - _ = @as(c_long, 66); - break :blk @as(c_long, 10); -}; -pub const SN_cast5_ecb = "CAST5-ECB"; -pub const LN_cast5_ecb = "cast5-ecb"; -pub const NID_cast5_ecb = @as(c_int, 109); -pub const SN_cast5_cfb64 = "CAST5-CFB"; -pub const LN_cast5_cfb64 = "cast5-cfb"; -pub const NID_cast5_cfb64 = @as(c_int, 110); -pub const SN_cast5_ofb64 = "CAST5-OFB"; -pub const LN_cast5_ofb64 = "cast5-ofb"; -pub const NID_cast5_ofb64 = @as(c_int, 111); -pub const LN_pbeWithMD5AndCast5_CBC = "pbeWithMD5AndCast5CBC"; -pub const NID_pbeWithMD5AndCast5_CBC = @as(c_int, 112); -pub const OBJ_pbeWithMD5AndCast5_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113533); - _ = @as(c_long, 7); - _ = @as(c_long, 66); - break :blk @as(c_long, 12); -}; -pub const SN_dsaWithSHA1 = "DSA-SHA1"; -pub const LN_dsaWithSHA1 = "dsaWithSHA1"; -pub const NID_dsaWithSHA1 = @as(c_int, 113); -pub const OBJ_dsaWithSHA1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10040); - _ = @as(c_long, 4); - break :blk @as(c_long, 3); -}; -pub const SN_md5_sha1 = "MD5-SHA1"; -pub const LN_md5_sha1 = "md5-sha1"; -pub const NID_md5_sha1 = @as(c_int, 114); -pub const SN_sha1WithRSA = "RSA-SHA1-2"; -pub const LN_sha1WithRSA = "sha1WithRSA"; -pub const NID_sha1WithRSA = @as(c_int, 115); -pub const OBJ_sha1WithRSA = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 29); -}; -pub const SN_dsa = "DSA"; -pub const LN_dsa = "dsaEncryption"; -pub const NID_dsa = @as(c_int, 116); -pub const OBJ_dsa = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10040); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_ripemd160 = "RIPEMD160"; -pub const LN_ripemd160 = "ripemd160"; -pub const NID_ripemd160 = @as(c_int, 117); -pub const OBJ_ripemd160 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_ripemd160WithRSA = "RSA-RIPEMD160"; -pub const LN_ripemd160WithRSA = "ripemd160WithRSA"; -pub const NID_ripemd160WithRSA = @as(c_int, 119); -pub const OBJ_ripemd160WithRSA = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_rc5_cbc = "RC5-CBC"; -pub const LN_rc5_cbc = "rc5-cbc"; -pub const NID_rc5_cbc = @as(c_int, 120); -pub const OBJ_rc5_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 3); - break :blk @as(c_long, 8); -}; -pub const SN_rc5_ecb = "RC5-ECB"; -pub const LN_rc5_ecb = "rc5-ecb"; -pub const NID_rc5_ecb = @as(c_int, 121); -pub const SN_rc5_cfb64 = "RC5-CFB"; -pub const LN_rc5_cfb64 = "rc5-cfb"; -pub const NID_rc5_cfb64 = @as(c_int, 122); -pub const SN_rc5_ofb64 = "RC5-OFB"; -pub const LN_rc5_ofb64 = "rc5-ofb"; -pub const NID_rc5_ofb64 = @as(c_int, 123); -pub const SN_zlib_compression = "ZLIB"; -pub const LN_zlib_compression = "zlib compression"; -pub const NID_zlib_compression = @as(c_int, 125); -pub const OBJ_zlib_compression = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 8); -}; -pub const SN_ext_key_usage = "extendedKeyUsage"; -pub const LN_ext_key_usage = "X509v3 Extended Key Usage"; -pub const NID_ext_key_usage = @as(c_int, 126); -pub const OBJ_ext_key_usage = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 37); -}; -pub const SN_id_pkix = "PKIX"; -pub const NID_id_pkix = @as(c_int, 127); -pub const OBJ_id_pkix = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - break :blk @as(c_long, 7); -}; -pub const SN_id_kp = "id-kp"; -pub const NID_id_kp = @as(c_int, 128); -pub const OBJ_id_kp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 3); -}; -pub const SN_server_auth = "serverAuth"; -pub const LN_server_auth = "TLS Web Server Authentication"; -pub const NID_server_auth = @as(c_int, 129); -pub const OBJ_server_auth = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_client_auth = "clientAuth"; -pub const LN_client_auth = "TLS Web Client Authentication"; -pub const NID_client_auth = @as(c_int, 130); -pub const OBJ_client_auth = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_code_sign = "codeSigning"; -pub const LN_code_sign = "Code Signing"; -pub const NID_code_sign = @as(c_int, 131); -pub const OBJ_code_sign = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_email_protect = "emailProtection"; -pub const LN_email_protect = "E-mail Protection"; -pub const NID_email_protect = @as(c_int, 132); -pub const OBJ_email_protect = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const SN_time_stamp = "timeStamping"; -pub const LN_time_stamp = "Time Stamping"; -pub const NID_time_stamp = @as(c_int, 133); -pub const OBJ_time_stamp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 8); -}; -pub const SN_ms_code_ind = "msCodeInd"; -pub const LN_ms_code_ind = "Microsoft Individual Code Signing"; -pub const NID_ms_code_ind = @as(c_int, 134); -pub const OBJ_ms_code_ind = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 2); - _ = @as(c_long, 1); - break :blk @as(c_long, 21); -}; -pub const SN_ms_code_com = "msCodeCom"; -pub const LN_ms_code_com = "Microsoft Commercial Code Signing"; -pub const NID_ms_code_com = @as(c_int, 135); -pub const OBJ_ms_code_com = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 2); - _ = @as(c_long, 1); - break :blk @as(c_long, 22); -}; -pub const SN_ms_ctl_sign = "msCTLSign"; -pub const LN_ms_ctl_sign = "Microsoft Trust List Signing"; -pub const NID_ms_ctl_sign = @as(c_int, 136); -pub const OBJ_ms_ctl_sign = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 10); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_ms_sgc = "msSGC"; -pub const LN_ms_sgc = "Microsoft Server Gated Crypto"; -pub const NID_ms_sgc = @as(c_int, 137); -pub const OBJ_ms_sgc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 10); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_ms_efs = "msEFS"; -pub const LN_ms_efs = "Microsoft Encrypted File System"; -pub const NID_ms_efs = @as(c_int, 138); -pub const OBJ_ms_efs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 10); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const SN_ns_sgc = "nsSGC"; -pub const LN_ns_sgc = "Netscape Server Gated Crypto"; -pub const NID_ns_sgc = @as(c_int, 139); -pub const OBJ_ns_sgc = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 113730); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_delta_crl = "deltaCRL"; -pub const LN_delta_crl = "X509v3 Delta CRL Indicator"; -pub const NID_delta_crl = @as(c_int, 140); -pub const OBJ_delta_crl = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 27); -}; -pub const SN_crl_reason = "CRLReason"; -pub const LN_crl_reason = "X509v3 CRL Reason Code"; -pub const NID_crl_reason = @as(c_int, 141); -pub const OBJ_crl_reason = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 21); -}; -pub const SN_invalidity_date = "invalidityDate"; -pub const LN_invalidity_date = "Invalidity Date"; -pub const NID_invalidity_date = @as(c_int, 142); -pub const OBJ_invalidity_date = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 24); -}; -pub const SN_sxnet = "SXNetID"; -pub const LN_sxnet = "Strong Extranet ID"; -pub const NID_sxnet = @as(c_int, 143); -pub const OBJ_sxnet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 101); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_pbe_WithSHA1And128BitRC4 = "PBE-SHA1-RC4-128"; -pub const LN_pbe_WithSHA1And128BitRC4 = "pbeWithSHA1And128BitRC4"; -pub const NID_pbe_WithSHA1And128BitRC4 = @as(c_int, 144); -pub const OBJ_pbe_WithSHA1And128BitRC4 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_pbe_WithSHA1And40BitRC4 = "PBE-SHA1-RC4-40"; -pub const LN_pbe_WithSHA1And40BitRC4 = "pbeWithSHA1And40BitRC4"; -pub const NID_pbe_WithSHA1And40BitRC4 = @as(c_int, 145); -pub const OBJ_pbe_WithSHA1And40BitRC4 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_pbe_WithSHA1And3_Key_TripleDES_CBC = "PBE-SHA1-3DES"; -pub const LN_pbe_WithSHA1And3_Key_TripleDES_CBC = "pbeWithSHA1And3-KeyTripleDES-CBC"; -pub const NID_pbe_WithSHA1And3_Key_TripleDES_CBC = @as(c_int, 146); -pub const OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_pbe_WithSHA1And2_Key_TripleDES_CBC = "PBE-SHA1-2DES"; -pub const LN_pbe_WithSHA1And2_Key_TripleDES_CBC = "pbeWithSHA1And2-KeyTripleDES-CBC"; -pub const NID_pbe_WithSHA1And2_Key_TripleDES_CBC = @as(c_int, 147); -pub const OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_pbe_WithSHA1And128BitRC2_CBC = "PBE-SHA1-RC2-128"; -pub const LN_pbe_WithSHA1And128BitRC2_CBC = "pbeWithSHA1And128BitRC2-CBC"; -pub const NID_pbe_WithSHA1And128BitRC2_CBC = @as(c_int, 148); -pub const OBJ_pbe_WithSHA1And128BitRC2_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_pbe_WithSHA1And40BitRC2_CBC = "PBE-SHA1-RC2-40"; -pub const LN_pbe_WithSHA1And40BitRC2_CBC = "pbeWithSHA1And40BitRC2-CBC"; -pub const NID_pbe_WithSHA1And40BitRC2_CBC = @as(c_int, 149); -pub const OBJ_pbe_WithSHA1And40BitRC2_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const LN_keyBag = "keyBag"; -pub const NID_keyBag = @as(c_int, 150); -pub const OBJ_keyBag = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 10); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const LN_pkcs8ShroudedKeyBag = "pkcs8ShroudedKeyBag"; -pub const NID_pkcs8ShroudedKeyBag = @as(c_int, 151); -pub const OBJ_pkcs8ShroudedKeyBag = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 10); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const LN_certBag = "certBag"; -pub const NID_certBag = @as(c_int, 152); -pub const OBJ_certBag = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 10); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const LN_crlBag = "crlBag"; -pub const NID_crlBag = @as(c_int, 153); -pub const OBJ_crlBag = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 10); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const LN_secretBag = "secretBag"; -pub const NID_secretBag = @as(c_int, 154); -pub const OBJ_secretBag = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 10); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const LN_safeContentsBag = "safeContentsBag"; -pub const NID_safeContentsBag = @as(c_int, 155); -pub const OBJ_safeContentsBag = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 12); - _ = @as(c_long, 10); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const LN_friendlyName = "friendlyName"; -pub const NID_friendlyName = @as(c_int, 156); -pub const OBJ_friendlyName = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 20); -}; -pub const LN_localKeyID = "localKeyID"; -pub const NID_localKeyID = @as(c_int, 157); -pub const OBJ_localKeyID = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 21); -}; -pub const LN_x509Certificate = "x509Certificate"; -pub const NID_x509Certificate = @as(c_int, 158); -pub const OBJ_x509Certificate = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 22); - break :blk @as(c_long, 1); -}; -pub const LN_sdsiCertificate = "sdsiCertificate"; -pub const NID_sdsiCertificate = @as(c_int, 159); -pub const OBJ_sdsiCertificate = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 22); - break :blk @as(c_long, 2); -}; -pub const LN_x509Crl = "x509Crl"; -pub const NID_x509Crl = @as(c_int, 160); -pub const OBJ_x509Crl = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 23); - break :blk @as(c_long, 1); -}; -pub const LN_pbes2 = "PBES2"; -pub const NID_pbes2 = @as(c_int, 161); -pub const OBJ_pbes2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 13); -}; -pub const LN_pbmac1 = "PBMAC1"; -pub const NID_pbmac1 = @as(c_int, 162); -pub const OBJ_pbmac1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 14); -}; -pub const LN_hmacWithSHA1 = "hmacWithSHA1"; -pub const NID_hmacWithSHA1 = @as(c_int, 163); -pub const OBJ_hmacWithSHA1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 7); -}; -pub const SN_id_qt_cps = "id-qt-cps"; -pub const LN_id_qt_cps = "Policy Qualifier CPS"; -pub const NID_id_qt_cps = @as(c_int, 164); -pub const OBJ_id_qt_cps = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_id_qt_unotice = "id-qt-unotice"; -pub const LN_id_qt_unotice = "Policy Qualifier User Notice"; -pub const NID_id_qt_unotice = @as(c_int, 165); -pub const OBJ_id_qt_unotice = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_rc2_64_cbc = "RC2-64-CBC"; -pub const LN_rc2_64_cbc = "rc2-64-cbc"; -pub const NID_rc2_64_cbc = @as(c_int, 166); -pub const SN_SMIMECapabilities = "SMIME-CAPS"; -pub const LN_SMIMECapabilities = "S/MIME Capabilities"; -pub const NID_SMIMECapabilities = @as(c_int, 167); -pub const OBJ_SMIMECapabilities = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 15); -}; -pub const SN_pbeWithMD2AndRC2_CBC = "PBE-MD2-RC2-64"; -pub const LN_pbeWithMD2AndRC2_CBC = "pbeWithMD2AndRC2-CBC"; -pub const NID_pbeWithMD2AndRC2_CBC = @as(c_int, 168); -pub const OBJ_pbeWithMD2AndRC2_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 4); -}; -pub const SN_pbeWithMD5AndRC2_CBC = "PBE-MD5-RC2-64"; -pub const LN_pbeWithMD5AndRC2_CBC = "pbeWithMD5AndRC2-CBC"; -pub const NID_pbeWithMD5AndRC2_CBC = @as(c_int, 169); -pub const OBJ_pbeWithMD5AndRC2_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 6); -}; -pub const SN_pbeWithSHA1AndDES_CBC = "PBE-SHA1-DES"; -pub const LN_pbeWithSHA1AndDES_CBC = "pbeWithSHA1AndDES-CBC"; -pub const NID_pbeWithSHA1AndDES_CBC = @as(c_int, 170); -pub const OBJ_pbeWithSHA1AndDES_CBC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 10); -}; -pub const SN_ms_ext_req = "msExtReq"; -pub const LN_ms_ext_req = "Microsoft Extension Request"; -pub const NID_ms_ext_req = @as(c_int, 171); -pub const OBJ_ms_ext_req = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 2); - _ = @as(c_long, 1); - break :blk @as(c_long, 14); -}; -pub const SN_ext_req = "extReq"; -pub const LN_ext_req = "Extension Request"; -pub const NID_ext_req = @as(c_int, 172); -pub const OBJ_ext_req = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 14); -}; -pub const SN_name = "name"; -pub const LN_name = "name"; -pub const NID_name = @as(c_int, 173); -pub const OBJ_name = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 41); -}; -pub const SN_dnQualifier = "dnQualifier"; -pub const LN_dnQualifier = "dnQualifier"; -pub const NID_dnQualifier = @as(c_int, 174); -pub const OBJ_dnQualifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 46); -}; -pub const SN_id_pe = "id-pe"; -pub const NID_id_pe = @as(c_int, 175); -pub const OBJ_id_pe = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 1); -}; -pub const SN_id_ad = "id-ad"; -pub const NID_id_ad = @as(c_int, 176); -pub const OBJ_id_ad = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 48); -}; -pub const SN_info_access = "authorityInfoAccess"; -pub const LN_info_access = "Authority Information Access"; -pub const NID_info_access = @as(c_int, 177); -pub const OBJ_info_access = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_ad_OCSP = "OCSP"; -pub const LN_ad_OCSP = "OCSP"; -pub const NID_ad_OCSP = @as(c_int, 178); -pub const OBJ_ad_OCSP = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - break :blk @as(c_long, 1); -}; -pub const SN_ad_ca_issuers = "caIssuers"; -pub const LN_ad_ca_issuers = "CA Issuers"; -pub const NID_ad_ca_issuers = @as(c_int, 179); -pub const OBJ_ad_ca_issuers = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - break :blk @as(c_long, 2); -}; -pub const SN_OCSP_sign = "OCSPSigning"; -pub const LN_OCSP_sign = "OCSP Signing"; -pub const NID_OCSP_sign = @as(c_int, 180); -pub const OBJ_OCSP_sign = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 9); -}; -pub const SN_iso = "ISO"; -pub const LN_iso = "iso"; -pub const NID_iso = @as(c_int, 181); -pub const OBJ_iso = @as(c_long, 1); -pub const SN_member_body = "member-body"; -pub const LN_member_body = "ISO Member Body"; -pub const NID_member_body = @as(c_int, 182); -pub const OBJ_member_body = blk: { - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_ISO_US = "ISO-US"; -pub const LN_ISO_US = "ISO US Member Body"; -pub const NID_ISO_US = @as(c_int, 183); -pub const OBJ_ISO_US = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - break :blk @as(c_long, 840); -}; -pub const SN_X9_57 = "X9-57"; -pub const LN_X9_57 = "X9.57"; -pub const NID_X9_57 = @as(c_int, 184); -pub const OBJ_X9_57 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - break :blk @as(c_long, 10040); -}; -pub const SN_X9cm = "X9cm"; -pub const LN_X9cm = "X9.57 CM ?"; -pub const NID_X9cm = @as(c_int, 185); -pub const OBJ_X9cm = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10040); - break :blk @as(c_long, 4); -}; -pub const SN_pkcs1 = "pkcs1"; -pub const NID_pkcs1 = @as(c_int, 186); -pub const OBJ_pkcs1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_pkcs5 = "pkcs5"; -pub const NID_pkcs5 = @as(c_int, 187); -pub const OBJ_pkcs5 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_SMIME = "SMIME"; -pub const LN_SMIME = "S/MIME"; -pub const NID_SMIME = @as(c_int, 188); -pub const OBJ_SMIME = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 16); -}; -pub const SN_id_smime_mod = "id-smime-mod"; -pub const NID_id_smime_mod = @as(c_int, 189); -pub const OBJ_id_smime_mod = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - break :blk @as(c_long, 0); -}; -pub const SN_id_smime_ct = "id-smime-ct"; -pub const NID_id_smime_ct = @as(c_int, 190); -pub const OBJ_id_smime_ct = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_aa = "id-smime-aa"; -pub const NID_id_smime_aa = @as(c_int, 191); -pub const OBJ_id_smime_aa = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - break :blk @as(c_long, 2); -}; -pub const SN_id_smime_alg = "id-smime-alg"; -pub const NID_id_smime_alg = @as(c_int, 192); -pub const OBJ_id_smime_alg = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - break :blk @as(c_long, 3); -}; -pub const SN_id_smime_cd = "id-smime-cd"; -pub const NID_id_smime_cd = @as(c_int, 193); -pub const OBJ_id_smime_cd = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - break :blk @as(c_long, 4); -}; -pub const SN_id_smime_spq = "id-smime-spq"; -pub const NID_id_smime_spq = @as(c_int, 194); -pub const OBJ_id_smime_spq = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - break :blk @as(c_long, 5); -}; -pub const SN_id_smime_cti = "id-smime-cti"; -pub const NID_id_smime_cti = @as(c_int, 195); -pub const OBJ_id_smime_cti = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - break :blk @as(c_long, 6); -}; -pub const SN_id_smime_mod_cms = "id-smime-mod-cms"; -pub const NID_id_smime_mod_cms = @as(c_int, 196); -pub const OBJ_id_smime_mod_cms = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_mod_ess = "id-smime-mod-ess"; -pub const NID_id_smime_mod_ess = @as(c_int, 197); -pub const OBJ_id_smime_mod_ess = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 2); -}; -pub const SN_id_smime_mod_oid = "id-smime-mod-oid"; -pub const NID_id_smime_mod_oid = @as(c_int, 198); -pub const OBJ_id_smime_mod_oid = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 3); -}; -pub const SN_id_smime_mod_msg_v3 = "id-smime-mod-msg-v3"; -pub const NID_id_smime_mod_msg_v3 = @as(c_int, 199); -pub const OBJ_id_smime_mod_msg_v3 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 4); -}; -pub const SN_id_smime_mod_ets_eSignature_88 = "id-smime-mod-ets-eSignature-88"; -pub const NID_id_smime_mod_ets_eSignature_88 = @as(c_int, 200); -pub const OBJ_id_smime_mod_ets_eSignature_88 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 5); -}; -pub const SN_id_smime_mod_ets_eSignature_97 = "id-smime-mod-ets-eSignature-97"; -pub const NID_id_smime_mod_ets_eSignature_97 = @as(c_int, 201); -pub const OBJ_id_smime_mod_ets_eSignature_97 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 6); -}; -pub const SN_id_smime_mod_ets_eSigPolicy_88 = "id-smime-mod-ets-eSigPolicy-88"; -pub const NID_id_smime_mod_ets_eSigPolicy_88 = @as(c_int, 202); -pub const OBJ_id_smime_mod_ets_eSigPolicy_88 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 7); -}; -pub const SN_id_smime_mod_ets_eSigPolicy_97 = "id-smime-mod-ets-eSigPolicy-97"; -pub const NID_id_smime_mod_ets_eSigPolicy_97 = @as(c_int, 203); -pub const OBJ_id_smime_mod_ets_eSigPolicy_97 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 0); - break :blk @as(c_long, 8); -}; -pub const SN_id_smime_ct_receipt = "id-smime-ct-receipt"; -pub const NID_id_smime_ct_receipt = @as(c_int, 204); -pub const OBJ_id_smime_ct_receipt = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_ct_authData = "id-smime-ct-authData"; -pub const NID_id_smime_ct_authData = @as(c_int, 205); -pub const OBJ_id_smime_ct_authData = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_id_smime_ct_publishCert = "id-smime-ct-publishCert"; -pub const NID_id_smime_ct_publishCert = @as(c_int, 206); -pub const OBJ_id_smime_ct_publishCert = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_id_smime_ct_TSTInfo = "id-smime-ct-TSTInfo"; -pub const NID_id_smime_ct_TSTInfo = @as(c_int, 207); -pub const OBJ_id_smime_ct_TSTInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_id_smime_ct_TDTInfo = "id-smime-ct-TDTInfo"; -pub const NID_id_smime_ct_TDTInfo = @as(c_int, 208); -pub const OBJ_id_smime_ct_TDTInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_id_smime_ct_contentInfo = "id-smime-ct-contentInfo"; -pub const NID_id_smime_ct_contentInfo = @as(c_int, 209); -pub const OBJ_id_smime_ct_contentInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_id_smime_ct_DVCSRequestData = "id-smime-ct-DVCSRequestData"; -pub const NID_id_smime_ct_DVCSRequestData = @as(c_int, 210); -pub const OBJ_id_smime_ct_DVCSRequestData = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_id_smime_ct_DVCSResponseData = "id-smime-ct-DVCSResponseData"; -pub const NID_id_smime_ct_DVCSResponseData = @as(c_int, 211); -pub const OBJ_id_smime_ct_DVCSResponseData = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_id_smime_aa_receiptRequest = "id-smime-aa-receiptRequest"; -pub const NID_id_smime_aa_receiptRequest = @as(c_int, 212); -pub const OBJ_id_smime_aa_receiptRequest = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_aa_securityLabel = "id-smime-aa-securityLabel"; -pub const NID_id_smime_aa_securityLabel = @as(c_int, 213); -pub const OBJ_id_smime_aa_securityLabel = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_id_smime_aa_mlExpandHistory = "id-smime-aa-mlExpandHistory"; -pub const NID_id_smime_aa_mlExpandHistory = @as(c_int, 214); -pub const OBJ_id_smime_aa_mlExpandHistory = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const SN_id_smime_aa_contentHint = "id-smime-aa-contentHint"; -pub const NID_id_smime_aa_contentHint = @as(c_int, 215); -pub const OBJ_id_smime_aa_contentHint = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 4); -}; -pub const SN_id_smime_aa_msgSigDigest = "id-smime-aa-msgSigDigest"; -pub const NID_id_smime_aa_msgSigDigest = @as(c_int, 216); -pub const OBJ_id_smime_aa_msgSigDigest = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 5); -}; -pub const SN_id_smime_aa_encapContentType = "id-smime-aa-encapContentType"; -pub const NID_id_smime_aa_encapContentType = @as(c_int, 217); -pub const OBJ_id_smime_aa_encapContentType = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 6); -}; -pub const SN_id_smime_aa_contentIdentifier = "id-smime-aa-contentIdentifier"; -pub const NID_id_smime_aa_contentIdentifier = @as(c_int, 218); -pub const OBJ_id_smime_aa_contentIdentifier = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 7); -}; -pub const SN_id_smime_aa_macValue = "id-smime-aa-macValue"; -pub const NID_id_smime_aa_macValue = @as(c_int, 219); -pub const OBJ_id_smime_aa_macValue = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 8); -}; -pub const SN_id_smime_aa_equivalentLabels = "id-smime-aa-equivalentLabels"; -pub const NID_id_smime_aa_equivalentLabels = @as(c_int, 220); -pub const OBJ_id_smime_aa_equivalentLabels = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 9); -}; -pub const SN_id_smime_aa_contentReference = "id-smime-aa-contentReference"; -pub const NID_id_smime_aa_contentReference = @as(c_int, 221); -pub const OBJ_id_smime_aa_contentReference = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 10); -}; -pub const SN_id_smime_aa_encrypKeyPref = "id-smime-aa-encrypKeyPref"; -pub const NID_id_smime_aa_encrypKeyPref = @as(c_int, 222); -pub const OBJ_id_smime_aa_encrypKeyPref = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 11); -}; -pub const SN_id_smime_aa_signingCertificate = "id-smime-aa-signingCertificate"; -pub const NID_id_smime_aa_signingCertificate = @as(c_int, 223); -pub const OBJ_id_smime_aa_signingCertificate = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 12); -}; -pub const SN_id_smime_aa_smimeEncryptCerts = "id-smime-aa-smimeEncryptCerts"; -pub const NID_id_smime_aa_smimeEncryptCerts = @as(c_int, 224); -pub const OBJ_id_smime_aa_smimeEncryptCerts = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 13); -}; -pub const SN_id_smime_aa_timeStampToken = "id-smime-aa-timeStampToken"; -pub const NID_id_smime_aa_timeStampToken = @as(c_int, 225); -pub const OBJ_id_smime_aa_timeStampToken = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 14); -}; -pub const SN_id_smime_aa_ets_sigPolicyId = "id-smime-aa-ets-sigPolicyId"; -pub const NID_id_smime_aa_ets_sigPolicyId = @as(c_int, 226); -pub const OBJ_id_smime_aa_ets_sigPolicyId = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 15); -}; -pub const SN_id_smime_aa_ets_commitmentType = "id-smime-aa-ets-commitmentType"; -pub const NID_id_smime_aa_ets_commitmentType = @as(c_int, 227); -pub const OBJ_id_smime_aa_ets_commitmentType = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 16); -}; -pub const SN_id_smime_aa_ets_signerLocation = "id-smime-aa-ets-signerLocation"; -pub const NID_id_smime_aa_ets_signerLocation = @as(c_int, 228); -pub const OBJ_id_smime_aa_ets_signerLocation = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 17); -}; -pub const SN_id_smime_aa_ets_signerAttr = "id-smime-aa-ets-signerAttr"; -pub const NID_id_smime_aa_ets_signerAttr = @as(c_int, 229); -pub const OBJ_id_smime_aa_ets_signerAttr = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 18); -}; -pub const SN_id_smime_aa_ets_otherSigCert = "id-smime-aa-ets-otherSigCert"; -pub const NID_id_smime_aa_ets_otherSigCert = @as(c_int, 230); -pub const OBJ_id_smime_aa_ets_otherSigCert = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 19); -}; -pub const SN_id_smime_aa_ets_contentTimestamp = "id-smime-aa-ets-contentTimestamp"; -pub const NID_id_smime_aa_ets_contentTimestamp = @as(c_int, 231); -pub const OBJ_id_smime_aa_ets_contentTimestamp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 20); -}; -pub const SN_id_smime_aa_ets_CertificateRefs = "id-smime-aa-ets-CertificateRefs"; -pub const NID_id_smime_aa_ets_CertificateRefs = @as(c_int, 232); -pub const OBJ_id_smime_aa_ets_CertificateRefs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 21); -}; -pub const SN_id_smime_aa_ets_RevocationRefs = "id-smime-aa-ets-RevocationRefs"; -pub const NID_id_smime_aa_ets_RevocationRefs = @as(c_int, 233); -pub const OBJ_id_smime_aa_ets_RevocationRefs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 22); -}; -pub const SN_id_smime_aa_ets_certValues = "id-smime-aa-ets-certValues"; -pub const NID_id_smime_aa_ets_certValues = @as(c_int, 234); -pub const OBJ_id_smime_aa_ets_certValues = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 23); -}; -pub const SN_id_smime_aa_ets_revocationValues = "id-smime-aa-ets-revocationValues"; -pub const NID_id_smime_aa_ets_revocationValues = @as(c_int, 235); -pub const OBJ_id_smime_aa_ets_revocationValues = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 24); -}; -pub const SN_id_smime_aa_ets_escTimeStamp = "id-smime-aa-ets-escTimeStamp"; -pub const NID_id_smime_aa_ets_escTimeStamp = @as(c_int, 236); -pub const OBJ_id_smime_aa_ets_escTimeStamp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 25); -}; -pub const SN_id_smime_aa_ets_certCRLTimestamp = "id-smime-aa-ets-certCRLTimestamp"; -pub const NID_id_smime_aa_ets_certCRLTimestamp = @as(c_int, 237); -pub const OBJ_id_smime_aa_ets_certCRLTimestamp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 26); -}; -pub const SN_id_smime_aa_ets_archiveTimeStamp = "id-smime-aa-ets-archiveTimeStamp"; -pub const NID_id_smime_aa_ets_archiveTimeStamp = @as(c_int, 238); -pub const OBJ_id_smime_aa_ets_archiveTimeStamp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 27); -}; -pub const SN_id_smime_aa_signatureType = "id-smime-aa-signatureType"; -pub const NID_id_smime_aa_signatureType = @as(c_int, 239); -pub const OBJ_id_smime_aa_signatureType = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 28); -}; -pub const SN_id_smime_aa_dvcs_dvc = "id-smime-aa-dvcs-dvc"; -pub const NID_id_smime_aa_dvcs_dvc = @as(c_int, 240); -pub const OBJ_id_smime_aa_dvcs_dvc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 2); - break :blk @as(c_long, 29); -}; -pub const SN_id_smime_alg_ESDHwith3DES = "id-smime-alg-ESDHwith3DES"; -pub const NID_id_smime_alg_ESDHwith3DES = @as(c_int, 241); -pub const OBJ_id_smime_alg_ESDHwith3DES = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_alg_ESDHwithRC2 = "id-smime-alg-ESDHwithRC2"; -pub const NID_id_smime_alg_ESDHwithRC2 = @as(c_int, 242); -pub const OBJ_id_smime_alg_ESDHwithRC2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_id_smime_alg_3DESwrap = "id-smime-alg-3DESwrap"; -pub const NID_id_smime_alg_3DESwrap = @as(c_int, 243); -pub const OBJ_id_smime_alg_3DESwrap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_id_smime_alg_RC2wrap = "id-smime-alg-RC2wrap"; -pub const NID_id_smime_alg_RC2wrap = @as(c_int, 244); -pub const OBJ_id_smime_alg_RC2wrap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const SN_id_smime_alg_ESDH = "id-smime-alg-ESDH"; -pub const NID_id_smime_alg_ESDH = @as(c_int, 245); -pub const OBJ_id_smime_alg_ESDH = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 5); -}; -pub const SN_id_smime_alg_CMS3DESwrap = "id-smime-alg-CMS3DESwrap"; -pub const NID_id_smime_alg_CMS3DESwrap = @as(c_int, 246); -pub const OBJ_id_smime_alg_CMS3DESwrap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 6); -}; -pub const SN_id_smime_alg_CMSRC2wrap = "id-smime-alg-CMSRC2wrap"; -pub const NID_id_smime_alg_CMSRC2wrap = @as(c_int, 247); -pub const OBJ_id_smime_alg_CMSRC2wrap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 7); -}; -pub const SN_id_smime_cd_ldap = "id-smime-cd-ldap"; -pub const NID_id_smime_cd_ldap = @as(c_int, 248); -pub const OBJ_id_smime_cd_ldap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_spq_ets_sqt_uri = "id-smime-spq-ets-sqt-uri"; -pub const NID_id_smime_spq_ets_sqt_uri = @as(c_int, 249); -pub const OBJ_id_smime_spq_ets_sqt_uri = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 5); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_spq_ets_sqt_unotice = "id-smime-spq-ets-sqt-unotice"; -pub const NID_id_smime_spq_ets_sqt_unotice = @as(c_int, 250); -pub const OBJ_id_smime_spq_ets_sqt_unotice = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 5); - break :blk @as(c_long, 2); -}; -pub const SN_id_smime_cti_ets_proofOfOrigin = "id-smime-cti-ets-proofOfOrigin"; -pub const NID_id_smime_cti_ets_proofOfOrigin = @as(c_int, 251); -pub const OBJ_id_smime_cti_ets_proofOfOrigin = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 6); - break :blk @as(c_long, 1); -}; -pub const SN_id_smime_cti_ets_proofOfReceipt = "id-smime-cti-ets-proofOfReceipt"; -pub const NID_id_smime_cti_ets_proofOfReceipt = @as(c_int, 252); -pub const OBJ_id_smime_cti_ets_proofOfReceipt = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 6); - break :blk @as(c_long, 2); -}; -pub const SN_id_smime_cti_ets_proofOfDelivery = "id-smime-cti-ets-proofOfDelivery"; -pub const NID_id_smime_cti_ets_proofOfDelivery = @as(c_int, 253); -pub const OBJ_id_smime_cti_ets_proofOfDelivery = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 6); - break :blk @as(c_long, 3); -}; -pub const SN_id_smime_cti_ets_proofOfSender = "id-smime-cti-ets-proofOfSender"; -pub const NID_id_smime_cti_ets_proofOfSender = @as(c_int, 254); -pub const OBJ_id_smime_cti_ets_proofOfSender = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 6); - break :blk @as(c_long, 4); -}; -pub const SN_id_smime_cti_ets_proofOfApproval = "id-smime-cti-ets-proofOfApproval"; -pub const NID_id_smime_cti_ets_proofOfApproval = @as(c_int, 255); -pub const OBJ_id_smime_cti_ets_proofOfApproval = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 6); - break :blk @as(c_long, 5); -}; -pub const SN_id_smime_cti_ets_proofOfCreation = "id-smime-cti-ets-proofOfCreation"; -pub const NID_id_smime_cti_ets_proofOfCreation = @as(c_int, 256); -pub const OBJ_id_smime_cti_ets_proofOfCreation = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 6); - break :blk @as(c_long, 6); -}; -pub const SN_md4 = "MD4"; -pub const LN_md4 = "md4"; -pub const NID_md4 = @as(c_int, 257); -pub const OBJ_md4 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 4); -}; -pub const SN_id_pkix_mod = "id-pkix-mod"; -pub const NID_id_pkix_mod = @as(c_int, 258); -pub const OBJ_id_pkix_mod = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 0); -}; -pub const SN_id_qt = "id-qt"; -pub const NID_id_qt = @as(c_int, 259); -pub const OBJ_id_qt = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 2); -}; -pub const SN_id_it = "id-it"; -pub const NID_id_it = @as(c_int, 260); -pub const OBJ_id_it = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 4); -}; -pub const SN_id_pkip = "id-pkip"; -pub const NID_id_pkip = @as(c_int, 261); -pub const OBJ_id_pkip = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 5); -}; -pub const SN_id_alg = "id-alg"; -pub const NID_id_alg = @as(c_int, 262); -pub const OBJ_id_alg = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 6); -}; -pub const SN_id_cmc = "id-cmc"; -pub const NID_id_cmc = @as(c_int, 263); -pub const OBJ_id_cmc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 7); -}; -pub const SN_id_on = "id-on"; -pub const NID_id_on = @as(c_int, 264); -pub const OBJ_id_on = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 8); -}; -pub const SN_id_pda = "id-pda"; -pub const NID_id_pda = @as(c_int, 265); -pub const OBJ_id_pda = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 9); -}; -pub const SN_id_aca = "id-aca"; -pub const NID_id_aca = @as(c_int, 266); -pub const OBJ_id_aca = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 10); -}; -pub const SN_id_qcs = "id-qcs"; -pub const NID_id_qcs = @as(c_int, 267); -pub const OBJ_id_qcs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 11); -}; -pub const SN_id_cct = "id-cct"; -pub const NID_id_cct = @as(c_int, 268); -pub const OBJ_id_cct = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 12); -}; -pub const SN_id_pkix1_explicit_88 = "id-pkix1-explicit-88"; -pub const NID_id_pkix1_explicit_88 = @as(c_int, 269); -pub const OBJ_id_pkix1_explicit_88 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 1); -}; -pub const SN_id_pkix1_implicit_88 = "id-pkix1-implicit-88"; -pub const NID_id_pkix1_implicit_88 = @as(c_int, 270); -pub const OBJ_id_pkix1_implicit_88 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 2); -}; -pub const SN_id_pkix1_explicit_93 = "id-pkix1-explicit-93"; -pub const NID_id_pkix1_explicit_93 = @as(c_int, 271); -pub const OBJ_id_pkix1_explicit_93 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 3); -}; -pub const SN_id_pkix1_implicit_93 = "id-pkix1-implicit-93"; -pub const NID_id_pkix1_implicit_93 = @as(c_int, 272); -pub const OBJ_id_pkix1_implicit_93 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 4); -}; -pub const SN_id_mod_crmf = "id-mod-crmf"; -pub const NID_id_mod_crmf = @as(c_int, 273); -pub const OBJ_id_mod_crmf = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 5); -}; -pub const SN_id_mod_cmc = "id-mod-cmc"; -pub const NID_id_mod_cmc = @as(c_int, 274); -pub const OBJ_id_mod_cmc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 6); -}; -pub const SN_id_mod_kea_profile_88 = "id-mod-kea-profile-88"; -pub const NID_id_mod_kea_profile_88 = @as(c_int, 275); -pub const OBJ_id_mod_kea_profile_88 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 7); -}; -pub const SN_id_mod_kea_profile_93 = "id-mod-kea-profile-93"; -pub const NID_id_mod_kea_profile_93 = @as(c_int, 276); -pub const OBJ_id_mod_kea_profile_93 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 8); -}; -pub const SN_id_mod_cmp = "id-mod-cmp"; -pub const NID_id_mod_cmp = @as(c_int, 277); -pub const OBJ_id_mod_cmp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 9); -}; -pub const SN_id_mod_qualified_cert_88 = "id-mod-qualified-cert-88"; -pub const NID_id_mod_qualified_cert_88 = @as(c_int, 278); -pub const OBJ_id_mod_qualified_cert_88 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 10); -}; -pub const SN_id_mod_qualified_cert_93 = "id-mod-qualified-cert-93"; -pub const NID_id_mod_qualified_cert_93 = @as(c_int, 279); -pub const OBJ_id_mod_qualified_cert_93 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 11); -}; -pub const SN_id_mod_attribute_cert = "id-mod-attribute-cert"; -pub const NID_id_mod_attribute_cert = @as(c_int, 280); -pub const OBJ_id_mod_attribute_cert = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 12); -}; -pub const SN_id_mod_timestamp_protocol = "id-mod-timestamp-protocol"; -pub const NID_id_mod_timestamp_protocol = @as(c_int, 281); -pub const OBJ_id_mod_timestamp_protocol = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 13); -}; -pub const SN_id_mod_ocsp = "id-mod-ocsp"; -pub const NID_id_mod_ocsp = @as(c_int, 282); -pub const OBJ_id_mod_ocsp = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 14); -}; -pub const SN_id_mod_dvcs = "id-mod-dvcs"; -pub const NID_id_mod_dvcs = @as(c_int, 283); -pub const OBJ_id_mod_dvcs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 15); -}; -pub const SN_id_mod_cmp2000 = "id-mod-cmp2000"; -pub const NID_id_mod_cmp2000 = @as(c_int, 284); -pub const OBJ_id_mod_cmp2000 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 0); - break :blk @as(c_long, 16); -}; -pub const SN_biometricInfo = "biometricInfo"; -pub const LN_biometricInfo = "Biometric Info"; -pub const NID_biometricInfo = @as(c_int, 285); -pub const OBJ_biometricInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_qcStatements = "qcStatements"; -pub const NID_qcStatements = @as(c_int, 286); -pub const OBJ_qcStatements = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_ac_auditEntity = "ac-auditEntity"; -pub const NID_ac_auditEntity = @as(c_int, 287); -pub const OBJ_ac_auditEntity = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_ac_targeting = "ac-targeting"; -pub const NID_ac_targeting = @as(c_int, 288); -pub const OBJ_ac_targeting = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_aaControls = "aaControls"; -pub const NID_aaControls = @as(c_int, 289); -pub const OBJ_aaControls = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_sbgp_ipAddrBlock = "sbgp-ipAddrBlock"; -pub const NID_sbgp_ipAddrBlock = @as(c_int, 290); -pub const OBJ_sbgp_ipAddrBlock = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_sbgp_autonomousSysNum = "sbgp-autonomousSysNum"; -pub const NID_sbgp_autonomousSysNum = @as(c_int, 291); -pub const OBJ_sbgp_autonomousSysNum = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_sbgp_routerIdentifier = "sbgp-routerIdentifier"; -pub const NID_sbgp_routerIdentifier = @as(c_int, 292); -pub const OBJ_sbgp_routerIdentifier = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 9); -}; -pub const SN_textNotice = "textNotice"; -pub const NID_textNotice = @as(c_int, 293); -pub const OBJ_textNotice = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const SN_ipsecEndSystem = "ipsecEndSystem"; -pub const LN_ipsecEndSystem = "IPSec End System"; -pub const NID_ipsecEndSystem = @as(c_int, 294); -pub const OBJ_ipsecEndSystem = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 5); -}; -pub const SN_ipsecTunnel = "ipsecTunnel"; -pub const LN_ipsecTunnel = "IPSec Tunnel"; -pub const NID_ipsecTunnel = @as(c_int, 295); -pub const OBJ_ipsecTunnel = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 6); -}; -pub const SN_ipsecUser = "ipsecUser"; -pub const LN_ipsecUser = "IPSec User"; -pub const NID_ipsecUser = @as(c_int, 296); -pub const OBJ_ipsecUser = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 7); -}; -pub const SN_dvcs = "DVCS"; -pub const LN_dvcs = "dvcs"; -pub const NID_dvcs = @as(c_int, 297); -pub const OBJ_dvcs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 3); - break :blk @as(c_long, 10); -}; -pub const SN_id_it_caProtEncCert = "id-it-caProtEncCert"; -pub const NID_id_it_caProtEncCert = @as(c_int, 298); -pub const OBJ_id_it_caProtEncCert = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_id_it_signKeyPairTypes = "id-it-signKeyPairTypes"; -pub const NID_id_it_signKeyPairTypes = @as(c_int, 299); -pub const OBJ_id_it_signKeyPairTypes = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 2); -}; -pub const SN_id_it_encKeyPairTypes = "id-it-encKeyPairTypes"; -pub const NID_id_it_encKeyPairTypes = @as(c_int, 300); -pub const OBJ_id_it_encKeyPairTypes = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 3); -}; -pub const SN_id_it_preferredSymmAlg = "id-it-preferredSymmAlg"; -pub const NID_id_it_preferredSymmAlg = @as(c_int, 301); -pub const OBJ_id_it_preferredSymmAlg = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 4); -}; -pub const SN_id_it_caKeyUpdateInfo = "id-it-caKeyUpdateInfo"; -pub const NID_id_it_caKeyUpdateInfo = @as(c_int, 302); -pub const OBJ_id_it_caKeyUpdateInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 5); -}; -pub const SN_id_it_currentCRL = "id-it-currentCRL"; -pub const NID_id_it_currentCRL = @as(c_int, 303); -pub const OBJ_id_it_currentCRL = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 6); -}; -pub const SN_id_it_unsupportedOIDs = "id-it-unsupportedOIDs"; -pub const NID_id_it_unsupportedOIDs = @as(c_int, 304); -pub const OBJ_id_it_unsupportedOIDs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 7); -}; -pub const SN_id_it_subscriptionRequest = "id-it-subscriptionRequest"; -pub const NID_id_it_subscriptionRequest = @as(c_int, 305); -pub const OBJ_id_it_subscriptionRequest = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 8); -}; -pub const SN_id_it_subscriptionResponse = "id-it-subscriptionResponse"; -pub const NID_id_it_subscriptionResponse = @as(c_int, 306); -pub const OBJ_id_it_subscriptionResponse = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 9); -}; -pub const SN_id_it_keyPairParamReq = "id-it-keyPairParamReq"; -pub const NID_id_it_keyPairParamReq = @as(c_int, 307); -pub const OBJ_id_it_keyPairParamReq = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 10); -}; -pub const SN_id_it_keyPairParamRep = "id-it-keyPairParamRep"; -pub const NID_id_it_keyPairParamRep = @as(c_int, 308); -pub const OBJ_id_it_keyPairParamRep = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 11); -}; -pub const SN_id_it_revPassphrase = "id-it-revPassphrase"; -pub const NID_id_it_revPassphrase = @as(c_int, 309); -pub const OBJ_id_it_revPassphrase = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 12); -}; -pub const SN_id_it_implicitConfirm = "id-it-implicitConfirm"; -pub const NID_id_it_implicitConfirm = @as(c_int, 310); -pub const OBJ_id_it_implicitConfirm = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 13); -}; -pub const SN_id_it_confirmWaitTime = "id-it-confirmWaitTime"; -pub const NID_id_it_confirmWaitTime = @as(c_int, 311); -pub const OBJ_id_it_confirmWaitTime = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 14); -}; -pub const SN_id_it_origPKIMessage = "id-it-origPKIMessage"; -pub const NID_id_it_origPKIMessage = @as(c_int, 312); -pub const OBJ_id_it_origPKIMessage = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 15); -}; -pub const SN_id_regCtrl = "id-regCtrl"; -pub const NID_id_regCtrl = @as(c_int, 313); -pub const OBJ_id_regCtrl = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - break :blk @as(c_long, 1); -}; -pub const SN_id_regInfo = "id-regInfo"; -pub const NID_id_regInfo = @as(c_int, 314); -pub const OBJ_id_regInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - break :blk @as(c_long, 2); -}; -pub const SN_id_regCtrl_regToken = "id-regCtrl-regToken"; -pub const NID_id_regCtrl_regToken = @as(c_int, 315); -pub const OBJ_id_regCtrl_regToken = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_id_regCtrl_authenticator = "id-regCtrl-authenticator"; -pub const NID_id_regCtrl_authenticator = @as(c_int, 316); -pub const OBJ_id_regCtrl_authenticator = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_id_regCtrl_pkiPublicationInfo = "id-regCtrl-pkiPublicationInfo"; -pub const NID_id_regCtrl_pkiPublicationInfo = @as(c_int, 317); -pub const OBJ_id_regCtrl_pkiPublicationInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_id_regCtrl_pkiArchiveOptions = "id-regCtrl-pkiArchiveOptions"; -pub const NID_id_regCtrl_pkiArchiveOptions = @as(c_int, 318); -pub const OBJ_id_regCtrl_pkiArchiveOptions = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_id_regCtrl_oldCertID = "id-regCtrl-oldCertID"; -pub const NID_id_regCtrl_oldCertID = @as(c_int, 319); -pub const OBJ_id_regCtrl_oldCertID = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_id_regCtrl_protocolEncrKey = "id-regCtrl-protocolEncrKey"; -pub const NID_id_regCtrl_protocolEncrKey = @as(c_int, 320); -pub const OBJ_id_regCtrl_protocolEncrKey = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_id_regInfo_utf8Pairs = "id-regInfo-utf8Pairs"; -pub const NID_id_regInfo_utf8Pairs = @as(c_int, 321); -pub const OBJ_id_regInfo_utf8Pairs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_id_regInfo_certReq = "id-regInfo-certReq"; -pub const NID_id_regInfo_certReq = @as(c_int, 322); -pub const OBJ_id_regInfo_certReq = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 5); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_id_alg_des40 = "id-alg-des40"; -pub const NID_id_alg_des40 = @as(c_int, 323); -pub const OBJ_id_alg_des40 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 6); - break :blk @as(c_long, 1); -}; -pub const SN_id_alg_noSignature = "id-alg-noSignature"; -pub const NID_id_alg_noSignature = @as(c_int, 324); -pub const OBJ_id_alg_noSignature = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 6); - break :blk @as(c_long, 2); -}; -pub const SN_id_alg_dh_sig_hmac_sha1 = "id-alg-dh-sig-hmac-sha1"; -pub const NID_id_alg_dh_sig_hmac_sha1 = @as(c_int, 325); -pub const OBJ_id_alg_dh_sig_hmac_sha1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 6); - break :blk @as(c_long, 3); -}; -pub const SN_id_alg_dh_pop = "id-alg-dh-pop"; -pub const NID_id_alg_dh_pop = @as(c_int, 326); -pub const OBJ_id_alg_dh_pop = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 6); - break :blk @as(c_long, 4); -}; -pub const SN_id_cmc_statusInfo = "id-cmc-statusInfo"; -pub const NID_id_cmc_statusInfo = @as(c_int, 327); -pub const OBJ_id_cmc_statusInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 1); -}; -pub const SN_id_cmc_identification = "id-cmc-identification"; -pub const NID_id_cmc_identification = @as(c_int, 328); -pub const OBJ_id_cmc_identification = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 2); -}; -pub const SN_id_cmc_identityProof = "id-cmc-identityProof"; -pub const NID_id_cmc_identityProof = @as(c_int, 329); -pub const OBJ_id_cmc_identityProof = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 3); -}; -pub const SN_id_cmc_dataReturn = "id-cmc-dataReturn"; -pub const NID_id_cmc_dataReturn = @as(c_int, 330); -pub const OBJ_id_cmc_dataReturn = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 4); -}; -pub const SN_id_cmc_transactionId = "id-cmc-transactionId"; -pub const NID_id_cmc_transactionId = @as(c_int, 331); -pub const OBJ_id_cmc_transactionId = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 5); -}; -pub const SN_id_cmc_senderNonce = "id-cmc-senderNonce"; -pub const NID_id_cmc_senderNonce = @as(c_int, 332); -pub const OBJ_id_cmc_senderNonce = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 6); -}; -pub const SN_id_cmc_recipientNonce = "id-cmc-recipientNonce"; -pub const NID_id_cmc_recipientNonce = @as(c_int, 333); -pub const OBJ_id_cmc_recipientNonce = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 7); -}; -pub const SN_id_cmc_addExtensions = "id-cmc-addExtensions"; -pub const NID_id_cmc_addExtensions = @as(c_int, 334); -pub const OBJ_id_cmc_addExtensions = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 8); -}; -pub const SN_id_cmc_encryptedPOP = "id-cmc-encryptedPOP"; -pub const NID_id_cmc_encryptedPOP = @as(c_int, 335); -pub const OBJ_id_cmc_encryptedPOP = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 9); -}; -pub const SN_id_cmc_decryptedPOP = "id-cmc-decryptedPOP"; -pub const NID_id_cmc_decryptedPOP = @as(c_int, 336); -pub const OBJ_id_cmc_decryptedPOP = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 10); -}; -pub const SN_id_cmc_lraPOPWitness = "id-cmc-lraPOPWitness"; -pub const NID_id_cmc_lraPOPWitness = @as(c_int, 337); -pub const OBJ_id_cmc_lraPOPWitness = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 11); -}; -pub const SN_id_cmc_getCert = "id-cmc-getCert"; -pub const NID_id_cmc_getCert = @as(c_int, 338); -pub const OBJ_id_cmc_getCert = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 15); -}; -pub const SN_id_cmc_getCRL = "id-cmc-getCRL"; -pub const NID_id_cmc_getCRL = @as(c_int, 339); -pub const OBJ_id_cmc_getCRL = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 16); -}; -pub const SN_id_cmc_revokeRequest = "id-cmc-revokeRequest"; -pub const NID_id_cmc_revokeRequest = @as(c_int, 340); -pub const OBJ_id_cmc_revokeRequest = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 17); -}; -pub const SN_id_cmc_regInfo = "id-cmc-regInfo"; -pub const NID_id_cmc_regInfo = @as(c_int, 341); -pub const OBJ_id_cmc_regInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 18); -}; -pub const SN_id_cmc_responseInfo = "id-cmc-responseInfo"; -pub const NID_id_cmc_responseInfo = @as(c_int, 342); -pub const OBJ_id_cmc_responseInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 19); -}; -pub const SN_id_cmc_queryPending = "id-cmc-queryPending"; -pub const NID_id_cmc_queryPending = @as(c_int, 343); -pub const OBJ_id_cmc_queryPending = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 21); -}; -pub const SN_id_cmc_popLinkRandom = "id-cmc-popLinkRandom"; -pub const NID_id_cmc_popLinkRandom = @as(c_int, 344); -pub const OBJ_id_cmc_popLinkRandom = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 22); -}; -pub const SN_id_cmc_popLinkWitness = "id-cmc-popLinkWitness"; -pub const NID_id_cmc_popLinkWitness = @as(c_int, 345); -pub const OBJ_id_cmc_popLinkWitness = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 23); -}; -pub const SN_id_cmc_confirmCertAcceptance = "id-cmc-confirmCertAcceptance"; -pub const NID_id_cmc_confirmCertAcceptance = @as(c_int, 346); -pub const OBJ_id_cmc_confirmCertAcceptance = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 7); - break :blk @as(c_long, 24); -}; -pub const SN_id_on_personalData = "id-on-personalData"; -pub const NID_id_on_personalData = @as(c_int, 347); -pub const OBJ_id_on_personalData = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 8); - break :blk @as(c_long, 1); -}; -pub const SN_id_pda_dateOfBirth = "id-pda-dateOfBirth"; -pub const NID_id_pda_dateOfBirth = @as(c_int, 348); -pub const OBJ_id_pda_dateOfBirth = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 9); - break :blk @as(c_long, 1); -}; -pub const SN_id_pda_placeOfBirth = "id-pda-placeOfBirth"; -pub const NID_id_pda_placeOfBirth = @as(c_int, 349); -pub const OBJ_id_pda_placeOfBirth = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 9); - break :blk @as(c_long, 2); -}; -pub const SN_id_pda_gender = "id-pda-gender"; -pub const NID_id_pda_gender = @as(c_int, 351); -pub const OBJ_id_pda_gender = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 9); - break :blk @as(c_long, 3); -}; -pub const SN_id_pda_countryOfCitizenship = "id-pda-countryOfCitizenship"; -pub const NID_id_pda_countryOfCitizenship = @as(c_int, 352); -pub const OBJ_id_pda_countryOfCitizenship = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 9); - break :blk @as(c_long, 4); -}; -pub const SN_id_pda_countryOfResidence = "id-pda-countryOfResidence"; -pub const NID_id_pda_countryOfResidence = @as(c_int, 353); -pub const OBJ_id_pda_countryOfResidence = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 9); - break :blk @as(c_long, 5); -}; -pub const SN_id_aca_authenticationInfo = "id-aca-authenticationInfo"; -pub const NID_id_aca_authenticationInfo = @as(c_int, 354); -pub const OBJ_id_aca_authenticationInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 10); - break :blk @as(c_long, 1); -}; -pub const SN_id_aca_accessIdentity = "id-aca-accessIdentity"; -pub const NID_id_aca_accessIdentity = @as(c_int, 355); -pub const OBJ_id_aca_accessIdentity = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 10); - break :blk @as(c_long, 2); -}; -pub const SN_id_aca_chargingIdentity = "id-aca-chargingIdentity"; -pub const NID_id_aca_chargingIdentity = @as(c_int, 356); -pub const OBJ_id_aca_chargingIdentity = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 10); - break :blk @as(c_long, 3); -}; -pub const SN_id_aca_group = "id-aca-group"; -pub const NID_id_aca_group = @as(c_int, 357); -pub const OBJ_id_aca_group = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 10); - break :blk @as(c_long, 4); -}; -pub const SN_id_aca_role = "id-aca-role"; -pub const NID_id_aca_role = @as(c_int, 358); -pub const OBJ_id_aca_role = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 10); - break :blk @as(c_long, 5); -}; -pub const SN_id_qcs_pkixQCSyntax_v1 = "id-qcs-pkixQCSyntax-v1"; -pub const NID_id_qcs_pkixQCSyntax_v1 = @as(c_int, 359); -pub const OBJ_id_qcs_pkixQCSyntax_v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 11); - break :blk @as(c_long, 1); -}; -pub const SN_id_cct_crs = "id-cct-crs"; -pub const NID_id_cct_crs = @as(c_int, 360); -pub const OBJ_id_cct_crs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 12); - break :blk @as(c_long, 1); -}; -pub const SN_id_cct_PKIData = "id-cct-PKIData"; -pub const NID_id_cct_PKIData = @as(c_int, 361); -pub const OBJ_id_cct_PKIData = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 12); - break :blk @as(c_long, 2); -}; -pub const SN_id_cct_PKIResponse = "id-cct-PKIResponse"; -pub const NID_id_cct_PKIResponse = @as(c_int, 362); -pub const OBJ_id_cct_PKIResponse = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 12); - break :blk @as(c_long, 3); -}; -pub const SN_ad_timeStamping = "ad_timestamping"; -pub const LN_ad_timeStamping = "AD Time Stamping"; -pub const NID_ad_timeStamping = @as(c_int, 363); -pub const OBJ_ad_timeStamping = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - break :blk @as(c_long, 3); -}; -pub const SN_ad_dvcs = "AD_DVCS"; -pub const LN_ad_dvcs = "ad dvcs"; -pub const NID_ad_dvcs = @as(c_int, 364); -pub const OBJ_ad_dvcs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - break :blk @as(c_long, 4); -}; -pub const SN_id_pkix_OCSP_basic = "basicOCSPResponse"; -pub const LN_id_pkix_OCSP_basic = "Basic OCSP Response"; -pub const NID_id_pkix_OCSP_basic = @as(c_int, 365); -pub const OBJ_id_pkix_OCSP_basic = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_id_pkix_OCSP_Nonce = "Nonce"; -pub const LN_id_pkix_OCSP_Nonce = "OCSP Nonce"; -pub const NID_id_pkix_OCSP_Nonce = @as(c_int, 366); -pub const OBJ_id_pkix_OCSP_Nonce = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_id_pkix_OCSP_CrlID = "CrlID"; -pub const LN_id_pkix_OCSP_CrlID = "OCSP CRL ID"; -pub const NID_id_pkix_OCSP_CrlID = @as(c_int, 367); -pub const OBJ_id_pkix_OCSP_CrlID = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_id_pkix_OCSP_acceptableResponses = "acceptableResponses"; -pub const LN_id_pkix_OCSP_acceptableResponses = "Acceptable OCSP Responses"; -pub const NID_id_pkix_OCSP_acceptableResponses = @as(c_int, 368); -pub const OBJ_id_pkix_OCSP_acceptableResponses = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_id_pkix_OCSP_noCheck = "noCheck"; -pub const LN_id_pkix_OCSP_noCheck = "OCSP No Check"; -pub const NID_id_pkix_OCSP_noCheck = @as(c_int, 369); -pub const OBJ_id_pkix_OCSP_noCheck = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_id_pkix_OCSP_archiveCutoff = "archiveCutoff"; -pub const LN_id_pkix_OCSP_archiveCutoff = "OCSP Archive Cutoff"; -pub const NID_id_pkix_OCSP_archiveCutoff = @as(c_int, 370); -pub const OBJ_id_pkix_OCSP_archiveCutoff = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_id_pkix_OCSP_serviceLocator = "serviceLocator"; -pub const LN_id_pkix_OCSP_serviceLocator = "OCSP Service Locator"; -pub const NID_id_pkix_OCSP_serviceLocator = @as(c_int, 371); -pub const OBJ_id_pkix_OCSP_serviceLocator = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_id_pkix_OCSP_extendedStatus = "extendedStatus"; -pub const LN_id_pkix_OCSP_extendedStatus = "Extended OCSP Status"; -pub const NID_id_pkix_OCSP_extendedStatus = @as(c_int, 372); -pub const OBJ_id_pkix_OCSP_extendedStatus = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_id_pkix_OCSP_valid = "valid"; -pub const NID_id_pkix_OCSP_valid = @as(c_int, 373); -pub const OBJ_id_pkix_OCSP_valid = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 9); -}; -pub const SN_id_pkix_OCSP_path = "path"; -pub const NID_id_pkix_OCSP_path = @as(c_int, 374); -pub const OBJ_id_pkix_OCSP_path = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 10); -}; -pub const SN_id_pkix_OCSP_trustRoot = "trustRoot"; -pub const LN_id_pkix_OCSP_trustRoot = "Trust Root"; -pub const NID_id_pkix_OCSP_trustRoot = @as(c_int, 375); -pub const OBJ_id_pkix_OCSP_trustRoot = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - _ = @as(c_long, 1); - break :blk @as(c_long, 11); -}; -pub const SN_algorithm = "algorithm"; -pub const LN_algorithm = "algorithm"; -pub const NID_algorithm = @as(c_int, 376); -pub const OBJ_algorithm = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_rsaSignature = "rsaSignature"; -pub const NID_rsaSignature = @as(c_int, 377); -pub const OBJ_rsaSignature = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 14); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 11); -}; -pub const SN_X500algorithms = "X500algorithms"; -pub const LN_X500algorithms = "directory services - algorithms"; -pub const NID_X500algorithms = @as(c_int, 378); -pub const OBJ_X500algorithms = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - break :blk @as(c_long, 8); -}; -pub const SN_org = "ORG"; -pub const LN_org = "org"; -pub const NID_org = @as(c_int, 379); -pub const OBJ_org = blk: { - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_dod = "DOD"; -pub const LN_dod = "dod"; -pub const NID_dod = @as(c_int, 380); -pub const OBJ_dod = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 6); -}; -pub const SN_iana = "IANA"; -pub const LN_iana = "iana"; -pub const NID_iana = @as(c_int, 381); -pub const OBJ_iana = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - break :blk @as(c_long, 1); -}; -pub const SN_Directory = "directory"; -pub const LN_Directory = "Directory"; -pub const NID_Directory = @as(c_int, 382); -pub const OBJ_Directory = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_Management = "mgmt"; -pub const LN_Management = "Management"; -pub const NID_Management = @as(c_int, 383); -pub const OBJ_Management = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_Experimental = "experimental"; -pub const LN_Experimental = "Experimental"; -pub const NID_Experimental = @as(c_int, 384); -pub const OBJ_Experimental = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_Private = "private"; -pub const LN_Private = "Private"; -pub const NID_Private = @as(c_int, 385); -pub const OBJ_Private = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_Security = "security"; -pub const LN_Security = "Security"; -pub const NID_Security = @as(c_int, 386); -pub const OBJ_Security = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_SNMPv2 = "snmpv2"; -pub const LN_SNMPv2 = "SNMPv2"; -pub const NID_SNMPv2 = @as(c_int, 387); -pub const OBJ_SNMPv2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const LN_Mail = "Mail"; -pub const NID_Mail = @as(c_int, 388); -pub const OBJ_Mail = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_Enterprises = "enterprises"; -pub const LN_Enterprises = "Enterprises"; -pub const NID_Enterprises = @as(c_int, 389); -pub const OBJ_Enterprises = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_dcObject = "dcobject"; -pub const LN_dcObject = "dcObject"; -pub const NID_dcObject = @as(c_int, 390); -pub const OBJ_dcObject = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 1466); - break :blk @as(c_long, 344); -}; -pub const SN_domainComponent = "DC"; -pub const LN_domainComponent = "domainComponent"; -pub const NID_domainComponent = @as(c_int, 391); -pub const OBJ_domainComponent = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 25); -}; -pub const SN_Domain = "domain"; -pub const LN_Domain = "Domain"; -pub const NID_Domain = @as(c_int, 392); -pub const OBJ_Domain = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 13); -}; -pub const SN_selected_attribute_types = "selected-attribute-types"; -pub const LN_selected_attribute_types = "Selected Attribute Types"; -pub const NID_selected_attribute_types = @as(c_int, 394); -pub const OBJ_selected_attribute_types = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_clearance = "clearance"; -pub const NID_clearance = @as(c_int, 395); -pub const OBJ_clearance = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 55); -}; -pub const SN_md4WithRSAEncryption = "RSA-MD4"; -pub const LN_md4WithRSAEncryption = "md4WithRSAEncryption"; -pub const NID_md4WithRSAEncryption = @as(c_int, 396); -pub const OBJ_md4WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_ac_proxying = "ac-proxying"; -pub const NID_ac_proxying = @as(c_int, 397); -pub const OBJ_ac_proxying = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 10); -}; -pub const SN_sinfo_access = "subjectInfoAccess"; -pub const LN_sinfo_access = "Subject Information Access"; -pub const NID_sinfo_access = @as(c_int, 398); -pub const OBJ_sinfo_access = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 11); -}; -pub const SN_id_aca_encAttrs = "id-aca-encAttrs"; -pub const NID_id_aca_encAttrs = @as(c_int, 399); -pub const OBJ_id_aca_encAttrs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 10); - break :blk @as(c_long, 6); -}; -pub const SN_role = "role"; -pub const LN_role = "role"; -pub const NID_role = @as(c_int, 400); -pub const OBJ_role = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 72); -}; -pub const SN_policy_constraints = "policyConstraints"; -pub const LN_policy_constraints = "X509v3 Policy Constraints"; -pub const NID_policy_constraints = @as(c_int, 401); -pub const OBJ_policy_constraints = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 36); -}; -pub const SN_target_information = "targetInformation"; -pub const LN_target_information = "X509v3 AC Targeting"; -pub const NID_target_information = @as(c_int, 402); -pub const OBJ_target_information = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 55); -}; -pub const SN_no_rev_avail = "noRevAvail"; -pub const LN_no_rev_avail = "X509v3 No Revocation Available"; -pub const NID_no_rev_avail = @as(c_int, 403); -pub const OBJ_no_rev_avail = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 56); -}; -pub const SN_ansi_X9_62 = "ansi-X9-62"; -pub const LN_ansi_X9_62 = "ANSI X9.62"; -pub const NID_ansi_X9_62 = @as(c_int, 405); -pub const OBJ_ansi_X9_62 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - break :blk @as(c_long, 10045); -}; -pub const SN_X9_62_prime_field = "prime-field"; -pub const NID_X9_62_prime_field = @as(c_int, 406); -pub const OBJ_X9_62_prime_field = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_X9_62_characteristic_two_field = "characteristic-two-field"; -pub const NID_X9_62_characteristic_two_field = @as(c_int, 407); -pub const OBJ_X9_62_characteristic_two_field = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_X9_62_id_ecPublicKey = "id-ecPublicKey"; -pub const NID_X9_62_id_ecPublicKey = @as(c_int, 408); -pub const OBJ_X9_62_id_ecPublicKey = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_X9_62_prime192v1 = "prime192v1"; -pub const NID_X9_62_prime192v1 = @as(c_int, 409); -pub const OBJ_X9_62_prime192v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_X9_62_prime192v2 = "prime192v2"; -pub const NID_X9_62_prime192v2 = @as(c_int, 410); -pub const OBJ_X9_62_prime192v2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_X9_62_prime192v3 = "prime192v3"; -pub const NID_X9_62_prime192v3 = @as(c_int, 411); -pub const OBJ_X9_62_prime192v3 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_X9_62_prime239v1 = "prime239v1"; -pub const NID_X9_62_prime239v1 = @as(c_int, 412); -pub const OBJ_X9_62_prime239v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_X9_62_prime239v2 = "prime239v2"; -pub const NID_X9_62_prime239v2 = @as(c_int, 413); -pub const OBJ_X9_62_prime239v2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_X9_62_prime239v3 = "prime239v3"; -pub const NID_X9_62_prime239v3 = @as(c_int, 414); -pub const OBJ_X9_62_prime239v3 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_X9_62_prime256v1 = "prime256v1"; -pub const NID_X9_62_prime256v1 = @as(c_int, 415); -pub const OBJ_X9_62_prime256v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_ecdsa_with_SHA1 = "ecdsa-with-SHA1"; -pub const NID_ecdsa_with_SHA1 = @as(c_int, 416); -pub const OBJ_ecdsa_with_SHA1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_ms_csp_name = "CSPName"; -pub const LN_ms_csp_name = "Microsoft CSP Name"; -pub const NID_ms_csp_name = @as(c_int, 417); -pub const OBJ_ms_csp_name = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 17); - break :blk @as(c_long, 1); -}; -pub const SN_aes_128_ecb = "AES-128-ECB"; -pub const LN_aes_128_ecb = "aes-128-ecb"; -pub const NID_aes_128_ecb = @as(c_int, 418); -pub const OBJ_aes_128_ecb = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_aes_128_cbc = "AES-128-CBC"; -pub const LN_aes_128_cbc = "aes-128-cbc"; -pub const NID_aes_128_cbc = @as(c_int, 419); -pub const OBJ_aes_128_cbc = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_aes_128_ofb128 = "AES-128-OFB"; -pub const LN_aes_128_ofb128 = "aes-128-ofb"; -pub const NID_aes_128_ofb128 = @as(c_int, 420); -pub const OBJ_aes_128_ofb128 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_aes_128_cfb128 = "AES-128-CFB"; -pub const LN_aes_128_cfb128 = "aes-128-cfb"; -pub const NID_aes_128_cfb128 = @as(c_int, 421); -pub const OBJ_aes_128_cfb128 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_aes_192_ecb = "AES-192-ECB"; -pub const LN_aes_192_ecb = "aes-192-ecb"; -pub const NID_aes_192_ecb = @as(c_int, 422); -pub const OBJ_aes_192_ecb = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 21); -}; -pub const SN_aes_192_cbc = "AES-192-CBC"; -pub const LN_aes_192_cbc = "aes-192-cbc"; -pub const NID_aes_192_cbc = @as(c_int, 423); -pub const OBJ_aes_192_cbc = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 22); -}; -pub const SN_aes_192_ofb128 = "AES-192-OFB"; -pub const LN_aes_192_ofb128 = "aes-192-ofb"; -pub const NID_aes_192_ofb128 = @as(c_int, 424); -pub const OBJ_aes_192_ofb128 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 23); -}; -pub const SN_aes_192_cfb128 = "AES-192-CFB"; -pub const LN_aes_192_cfb128 = "aes-192-cfb"; -pub const NID_aes_192_cfb128 = @as(c_int, 425); -pub const OBJ_aes_192_cfb128 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 24); -}; -pub const SN_aes_256_ecb = "AES-256-ECB"; -pub const LN_aes_256_ecb = "aes-256-ecb"; -pub const NID_aes_256_ecb = @as(c_int, 426); -pub const OBJ_aes_256_ecb = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 41); -}; -pub const SN_aes_256_cbc = "AES-256-CBC"; -pub const LN_aes_256_cbc = "aes-256-cbc"; -pub const NID_aes_256_cbc = @as(c_int, 427); -pub const OBJ_aes_256_cbc = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 42); -}; -pub const SN_aes_256_ofb128 = "AES-256-OFB"; -pub const LN_aes_256_ofb128 = "aes-256-ofb"; -pub const NID_aes_256_ofb128 = @as(c_int, 428); -pub const OBJ_aes_256_ofb128 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 43); -}; -pub const SN_aes_256_cfb128 = "AES-256-CFB"; -pub const LN_aes_256_cfb128 = "aes-256-cfb"; -pub const NID_aes_256_cfb128 = @as(c_int, 429); -pub const OBJ_aes_256_cfb128 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 44); -}; -pub const SN_hold_instruction_code = "holdInstructionCode"; -pub const LN_hold_instruction_code = "Hold Instruction Code"; -pub const NID_hold_instruction_code = @as(c_int, 430); -pub const OBJ_hold_instruction_code = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 23); -}; -pub const SN_hold_instruction_none = "holdInstructionNone"; -pub const LN_hold_instruction_none = "Hold Instruction None"; -pub const NID_hold_instruction_none = @as(c_int, 431); -pub const OBJ_hold_instruction_none = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10040); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_hold_instruction_call_issuer = "holdInstructionCallIssuer"; -pub const LN_hold_instruction_call_issuer = "Hold Instruction Call Issuer"; -pub const NID_hold_instruction_call_issuer = @as(c_int, 432); -pub const OBJ_hold_instruction_call_issuer = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10040); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_hold_instruction_reject = "holdInstructionReject"; -pub const LN_hold_instruction_reject = "Hold Instruction Reject"; -pub const NID_hold_instruction_reject = @as(c_int, 433); -pub const OBJ_hold_instruction_reject = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10040); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const SN_data = "data"; -pub const NID_data = @as(c_int, 434); -pub const OBJ_data = blk: { - _ = @as(c_long, 0); - break :blk @as(c_long, 9); -}; -pub const SN_pss = "pss"; -pub const NID_pss = @as(c_int, 435); -pub const OBJ_pss = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - break :blk @as(c_long, 2342); -}; -pub const SN_ucl = "ucl"; -pub const NID_ucl = @as(c_int, 436); -pub const OBJ_ucl = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - break :blk @as(c_long, 19200300); -}; -pub const SN_pilot = "pilot"; -pub const NID_pilot = @as(c_int, 437); -pub const OBJ_pilot = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - break :blk @as(c_long, 100); -}; -pub const LN_pilotAttributeType = "pilotAttributeType"; -pub const NID_pilotAttributeType = @as(c_int, 438); -pub const OBJ_pilotAttributeType = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - break :blk @as(c_long, 1); -}; -pub const LN_pilotAttributeSyntax = "pilotAttributeSyntax"; -pub const NID_pilotAttributeSyntax = @as(c_int, 439); -pub const OBJ_pilotAttributeSyntax = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - break :blk @as(c_long, 3); -}; -pub const LN_pilotObjectClass = "pilotObjectClass"; -pub const NID_pilotObjectClass = @as(c_int, 440); -pub const OBJ_pilotObjectClass = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - break :blk @as(c_long, 4); -}; -pub const LN_pilotGroups = "pilotGroups"; -pub const NID_pilotGroups = @as(c_int, 441); -pub const OBJ_pilotGroups = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - break :blk @as(c_long, 10); -}; -pub const LN_iA5StringSyntax = "iA5StringSyntax"; -pub const NID_iA5StringSyntax = @as(c_int, 442); -pub const OBJ_iA5StringSyntax = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const LN_caseIgnoreIA5StringSyntax = "caseIgnoreIA5StringSyntax"; -pub const NID_caseIgnoreIA5StringSyntax = @as(c_int, 443); -pub const OBJ_caseIgnoreIA5StringSyntax = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 3); - break :blk @as(c_long, 5); -}; -pub const LN_pilotObject = "pilotObject"; -pub const NID_pilotObject = @as(c_int, 444); -pub const OBJ_pilotObject = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 3); -}; -pub const LN_pilotPerson = "pilotPerson"; -pub const NID_pilotPerson = @as(c_int, 445); -pub const OBJ_pilotPerson = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 4); -}; -pub const SN_account = "account"; -pub const NID_account = @as(c_int, 446); -pub const OBJ_account = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 5); -}; -pub const SN_document = "document"; -pub const NID_document = @as(c_int, 447); -pub const OBJ_document = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 6); -}; -pub const SN_room = "room"; -pub const NID_room = @as(c_int, 448); -pub const OBJ_room = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 7); -}; -pub const LN_documentSeries = "documentSeries"; -pub const NID_documentSeries = @as(c_int, 449); -pub const OBJ_documentSeries = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 9); -}; -pub const LN_rFC822localPart = "rFC822localPart"; -pub const NID_rFC822localPart = @as(c_int, 450); -pub const OBJ_rFC822localPart = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 14); -}; -pub const LN_dNSDomain = "dNSDomain"; -pub const NID_dNSDomain = @as(c_int, 451); -pub const OBJ_dNSDomain = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 15); -}; -pub const LN_domainRelatedObject = "domainRelatedObject"; -pub const NID_domainRelatedObject = @as(c_int, 452); -pub const OBJ_domainRelatedObject = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 17); -}; -pub const LN_friendlyCountry = "friendlyCountry"; -pub const NID_friendlyCountry = @as(c_int, 453); -pub const OBJ_friendlyCountry = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 18); -}; -pub const LN_simpleSecurityObject = "simpleSecurityObject"; -pub const NID_simpleSecurityObject = @as(c_int, 454); -pub const OBJ_simpleSecurityObject = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 19); -}; -pub const LN_pilotOrganization = "pilotOrganization"; -pub const NID_pilotOrganization = @as(c_int, 455); -pub const OBJ_pilotOrganization = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 20); -}; -pub const LN_pilotDSA = "pilotDSA"; -pub const NID_pilotDSA = @as(c_int, 456); -pub const OBJ_pilotDSA = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 21); -}; -pub const LN_qualityLabelledData = "qualityLabelledData"; -pub const NID_qualityLabelledData = @as(c_int, 457); -pub const OBJ_qualityLabelledData = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 4); - break :blk @as(c_long, 22); -}; -pub const SN_userId = "UID"; -pub const LN_userId = "userId"; -pub const NID_userId = @as(c_int, 458); -pub const OBJ_userId = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const LN_textEncodedORAddress = "textEncodedORAddress"; -pub const NID_textEncodedORAddress = @as(c_int, 459); -pub const OBJ_textEncodedORAddress = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_rfc822Mailbox = "mail"; -pub const LN_rfc822Mailbox = "rfc822Mailbox"; -pub const NID_rfc822Mailbox = @as(c_int, 460); -pub const OBJ_rfc822Mailbox = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_info = "info"; -pub const NID_info = @as(c_int, 461); -pub const OBJ_info = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const LN_favouriteDrink = "favouriteDrink"; -pub const NID_favouriteDrink = @as(c_int, 462); -pub const OBJ_favouriteDrink = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const LN_roomNumber = "roomNumber"; -pub const NID_roomNumber = @as(c_int, 463); -pub const OBJ_roomNumber = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_photo = "photo"; -pub const NID_photo = @as(c_int, 464); -pub const OBJ_photo = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const LN_userClass = "userClass"; -pub const NID_userClass = @as(c_int, 465); -pub const OBJ_userClass = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_host = "host"; -pub const NID_host = @as(c_int, 466); -pub const OBJ_host = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 9); -}; -pub const SN_manager = "manager"; -pub const NID_manager = @as(c_int, 467); -pub const OBJ_manager = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 10); -}; -pub const LN_documentIdentifier = "documentIdentifier"; -pub const NID_documentIdentifier = @as(c_int, 468); -pub const OBJ_documentIdentifier = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 11); -}; -pub const LN_documentTitle = "documentTitle"; -pub const NID_documentTitle = @as(c_int, 469); -pub const OBJ_documentTitle = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 12); -}; -pub const LN_documentVersion = "documentVersion"; -pub const NID_documentVersion = @as(c_int, 470); -pub const OBJ_documentVersion = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 13); -}; -pub const LN_documentAuthor = "documentAuthor"; -pub const NID_documentAuthor = @as(c_int, 471); -pub const OBJ_documentAuthor = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 14); -}; -pub const LN_documentLocation = "documentLocation"; -pub const NID_documentLocation = @as(c_int, 472); -pub const OBJ_documentLocation = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 15); -}; -pub const LN_homeTelephoneNumber = "homeTelephoneNumber"; -pub const NID_homeTelephoneNumber = @as(c_int, 473); -pub const OBJ_homeTelephoneNumber = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 20); -}; -pub const SN_secretary = "secretary"; -pub const NID_secretary = @as(c_int, 474); -pub const OBJ_secretary = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 21); -}; -pub const LN_otherMailbox = "otherMailbox"; -pub const NID_otherMailbox = @as(c_int, 475); -pub const OBJ_otherMailbox = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 22); -}; -pub const LN_lastModifiedTime = "lastModifiedTime"; -pub const NID_lastModifiedTime = @as(c_int, 476); -pub const OBJ_lastModifiedTime = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 23); -}; -pub const LN_lastModifiedBy = "lastModifiedBy"; -pub const NID_lastModifiedBy = @as(c_int, 477); -pub const OBJ_lastModifiedBy = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 24); -}; -pub const LN_aRecord = "aRecord"; -pub const NID_aRecord = @as(c_int, 478); -pub const OBJ_aRecord = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 26); -}; -pub const LN_pilotAttributeType27 = "pilotAttributeType27"; -pub const NID_pilotAttributeType27 = @as(c_int, 479); -pub const OBJ_pilotAttributeType27 = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 27); -}; -pub const LN_mXRecord = "mXRecord"; -pub const NID_mXRecord = @as(c_int, 480); -pub const OBJ_mXRecord = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 28); -}; -pub const LN_nSRecord = "nSRecord"; -pub const NID_nSRecord = @as(c_int, 481); -pub const OBJ_nSRecord = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 29); -}; -pub const LN_sOARecord = "sOARecord"; -pub const NID_sOARecord = @as(c_int, 482); -pub const OBJ_sOARecord = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 30); -}; -pub const LN_cNAMERecord = "cNAMERecord"; -pub const NID_cNAMERecord = @as(c_int, 483); -pub const OBJ_cNAMERecord = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 31); -}; -pub const LN_associatedDomain = "associatedDomain"; -pub const NID_associatedDomain = @as(c_int, 484); -pub const OBJ_associatedDomain = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 37); -}; -pub const LN_associatedName = "associatedName"; -pub const NID_associatedName = @as(c_int, 485); -pub const OBJ_associatedName = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 38); -}; -pub const LN_homePostalAddress = "homePostalAddress"; -pub const NID_homePostalAddress = @as(c_int, 486); -pub const OBJ_homePostalAddress = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 39); -}; -pub const LN_personalTitle = "personalTitle"; -pub const NID_personalTitle = @as(c_int, 487); -pub const OBJ_personalTitle = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 40); -}; -pub const LN_mobileTelephoneNumber = "mobileTelephoneNumber"; -pub const NID_mobileTelephoneNumber = @as(c_int, 488); -pub const OBJ_mobileTelephoneNumber = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 41); -}; -pub const LN_pagerTelephoneNumber = "pagerTelephoneNumber"; -pub const NID_pagerTelephoneNumber = @as(c_int, 489); -pub const OBJ_pagerTelephoneNumber = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 42); -}; -pub const LN_friendlyCountryName = "friendlyCountryName"; -pub const NID_friendlyCountryName = @as(c_int, 490); -pub const OBJ_friendlyCountryName = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 43); -}; -pub const LN_organizationalStatus = "organizationalStatus"; -pub const NID_organizationalStatus = @as(c_int, 491); -pub const OBJ_organizationalStatus = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 45); -}; -pub const LN_janetMailbox = "janetMailbox"; -pub const NID_janetMailbox = @as(c_int, 492); -pub const OBJ_janetMailbox = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 46); -}; -pub const LN_mailPreferenceOption = "mailPreferenceOption"; -pub const NID_mailPreferenceOption = @as(c_int, 493); -pub const OBJ_mailPreferenceOption = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 47); -}; -pub const LN_buildingName = "buildingName"; -pub const NID_buildingName = @as(c_int, 494); -pub const OBJ_buildingName = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 48); -}; -pub const LN_dSAQuality = "dSAQuality"; -pub const NID_dSAQuality = @as(c_int, 495); -pub const OBJ_dSAQuality = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 49); -}; -pub const LN_singleLevelQuality = "singleLevelQuality"; -pub const NID_singleLevelQuality = @as(c_int, 496); -pub const OBJ_singleLevelQuality = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 50); -}; -pub const LN_subtreeMinimumQuality = "subtreeMinimumQuality"; -pub const NID_subtreeMinimumQuality = @as(c_int, 497); -pub const OBJ_subtreeMinimumQuality = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 51); -}; -pub const LN_subtreeMaximumQuality = "subtreeMaximumQuality"; -pub const NID_subtreeMaximumQuality = @as(c_int, 498); -pub const OBJ_subtreeMaximumQuality = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 52); -}; -pub const LN_personalSignature = "personalSignature"; -pub const NID_personalSignature = @as(c_int, 499); -pub const OBJ_personalSignature = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 53); -}; -pub const LN_dITRedirect = "dITRedirect"; -pub const NID_dITRedirect = @as(c_int, 500); -pub const OBJ_dITRedirect = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 54); -}; -pub const SN_audio = "audio"; -pub const NID_audio = @as(c_int, 501); -pub const OBJ_audio = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 55); -}; -pub const LN_documentPublisher = "documentPublisher"; -pub const NID_documentPublisher = @as(c_int, 502); -pub const OBJ_documentPublisher = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 9); - _ = @as(c_long, 2342); - _ = @as(c_long, 19200300); - _ = @as(c_long, 100); - _ = @as(c_long, 1); - break :blk @as(c_long, 56); -}; -pub const LN_x500UniqueIdentifier = "x500UniqueIdentifier"; -pub const NID_x500UniqueIdentifier = @as(c_int, 503); -pub const OBJ_x500UniqueIdentifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 45); -}; -pub const SN_mime_mhs = "mime-mhs"; -pub const LN_mime_mhs = "MIME MHS"; -pub const NID_mime_mhs = @as(c_int, 504); -pub const OBJ_mime_mhs = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - break :blk @as(c_long, 1); -}; -pub const SN_mime_mhs_headings = "mime-mhs-headings"; -pub const LN_mime_mhs_headings = "mime-mhs-headings"; -pub const NID_mime_mhs_headings = @as(c_int, 505); -pub const OBJ_mime_mhs_headings = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_mime_mhs_bodies = "mime-mhs-bodies"; -pub const LN_mime_mhs_bodies = "mime-mhs-bodies"; -pub const NID_mime_mhs_bodies = @as(c_int, 506); -pub const OBJ_mime_mhs_bodies = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_id_hex_partial_message = "id-hex-partial-message"; -pub const LN_id_hex_partial_message = "id-hex-partial-message"; -pub const NID_id_hex_partial_message = @as(c_int, 507); -pub const OBJ_id_hex_partial_message = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_id_hex_multipart_message = "id-hex-multipart-message"; -pub const LN_id_hex_multipart_message = "id-hex-multipart-message"; -pub const NID_id_hex_multipart_message = @as(c_int, 508); -pub const OBJ_id_hex_multipart_message = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const LN_generationQualifier = "generationQualifier"; -pub const NID_generationQualifier = @as(c_int, 509); -pub const OBJ_generationQualifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 44); -}; -pub const LN_pseudonym = "pseudonym"; -pub const NID_pseudonym = @as(c_int, 510); -pub const OBJ_pseudonym = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 65); -}; -pub const SN_id_set = "id-set"; -pub const LN_id_set = "Secure Electronic Transactions"; -pub const NID_id_set = @as(c_int, 512); -pub const OBJ_id_set = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - break :blk @as(c_long, 42); -}; -pub const SN_set_ctype = "set-ctype"; -pub const LN_set_ctype = "content types"; -pub const NID_set_ctype = @as(c_int, 513); -pub const OBJ_set_ctype = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - break :blk @as(c_long, 0); -}; -pub const SN_set_msgExt = "set-msgExt"; -pub const LN_set_msgExt = "message extensions"; -pub const NID_set_msgExt = @as(c_int, 514); -pub const OBJ_set_msgExt = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - break :blk @as(c_long, 1); -}; -pub const SN_set_attr = "set-attr"; -pub const NID_set_attr = @as(c_int, 515); -pub const OBJ_set_attr = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - break :blk @as(c_long, 3); -}; -pub const SN_set_policy = "set-policy"; -pub const NID_set_policy = @as(c_int, 516); -pub const OBJ_set_policy = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - break :blk @as(c_long, 5); -}; -pub const SN_set_certExt = "set-certExt"; -pub const LN_set_certExt = "certificate extensions"; -pub const NID_set_certExt = @as(c_int, 517); -pub const OBJ_set_certExt = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - break :blk @as(c_long, 7); -}; -pub const SN_set_brand = "set-brand"; -pub const NID_set_brand = @as(c_int, 518); -pub const OBJ_set_brand = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - break :blk @as(c_long, 8); -}; -pub const SN_setct_PANData = "setct-PANData"; -pub const NID_setct_PANData = @as(c_int, 519); -pub const OBJ_setct_PANData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 0); -}; -pub const SN_setct_PANToken = "setct-PANToken"; -pub const NID_setct_PANToken = @as(c_int, 520); -pub const OBJ_setct_PANToken = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 1); -}; -pub const SN_setct_PANOnly = "setct-PANOnly"; -pub const NID_setct_PANOnly = @as(c_int, 521); -pub const OBJ_setct_PANOnly = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 2); -}; -pub const SN_setct_OIData = "setct-OIData"; -pub const NID_setct_OIData = @as(c_int, 522); -pub const OBJ_setct_OIData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 3); -}; -pub const SN_setct_PI = "setct-PI"; -pub const NID_setct_PI = @as(c_int, 523); -pub const OBJ_setct_PI = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 4); -}; -pub const SN_setct_PIData = "setct-PIData"; -pub const NID_setct_PIData = @as(c_int, 524); -pub const OBJ_setct_PIData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 5); -}; -pub const SN_setct_PIDataUnsigned = "setct-PIDataUnsigned"; -pub const NID_setct_PIDataUnsigned = @as(c_int, 525); -pub const OBJ_setct_PIDataUnsigned = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 6); -}; -pub const SN_setct_HODInput = "setct-HODInput"; -pub const NID_setct_HODInput = @as(c_int, 526); -pub const OBJ_setct_HODInput = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 7); -}; -pub const SN_setct_AuthResBaggage = "setct-AuthResBaggage"; -pub const NID_setct_AuthResBaggage = @as(c_int, 527); -pub const OBJ_setct_AuthResBaggage = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 8); -}; -pub const SN_setct_AuthRevReqBaggage = "setct-AuthRevReqBaggage"; -pub const NID_setct_AuthRevReqBaggage = @as(c_int, 528); -pub const OBJ_setct_AuthRevReqBaggage = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 9); -}; -pub const SN_setct_AuthRevResBaggage = "setct-AuthRevResBaggage"; -pub const NID_setct_AuthRevResBaggage = @as(c_int, 529); -pub const OBJ_setct_AuthRevResBaggage = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 10); -}; -pub const SN_setct_CapTokenSeq = "setct-CapTokenSeq"; -pub const NID_setct_CapTokenSeq = @as(c_int, 530); -pub const OBJ_setct_CapTokenSeq = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 11); -}; -pub const SN_setct_PInitResData = "setct-PInitResData"; -pub const NID_setct_PInitResData = @as(c_int, 531); -pub const OBJ_setct_PInitResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 12); -}; -pub const SN_setct_PI_TBS = "setct-PI-TBS"; -pub const NID_setct_PI_TBS = @as(c_int, 532); -pub const OBJ_setct_PI_TBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 13); -}; -pub const SN_setct_PResData = "setct-PResData"; -pub const NID_setct_PResData = @as(c_int, 533); -pub const OBJ_setct_PResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 14); -}; -pub const SN_setct_AuthReqTBS = "setct-AuthReqTBS"; -pub const NID_setct_AuthReqTBS = @as(c_int, 534); -pub const OBJ_setct_AuthReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 16); -}; -pub const SN_setct_AuthResTBS = "setct-AuthResTBS"; -pub const NID_setct_AuthResTBS = @as(c_int, 535); -pub const OBJ_setct_AuthResTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 17); -}; -pub const SN_setct_AuthResTBSX = "setct-AuthResTBSX"; -pub const NID_setct_AuthResTBSX = @as(c_int, 536); -pub const OBJ_setct_AuthResTBSX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 18); -}; -pub const SN_setct_AuthTokenTBS = "setct-AuthTokenTBS"; -pub const NID_setct_AuthTokenTBS = @as(c_int, 537); -pub const OBJ_setct_AuthTokenTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 19); -}; -pub const SN_setct_CapTokenData = "setct-CapTokenData"; -pub const NID_setct_CapTokenData = @as(c_int, 538); -pub const OBJ_setct_CapTokenData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 20); -}; -pub const SN_setct_CapTokenTBS = "setct-CapTokenTBS"; -pub const NID_setct_CapTokenTBS = @as(c_int, 539); -pub const OBJ_setct_CapTokenTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 21); -}; -pub const SN_setct_AcqCardCodeMsg = "setct-AcqCardCodeMsg"; -pub const NID_setct_AcqCardCodeMsg = @as(c_int, 540); -pub const OBJ_setct_AcqCardCodeMsg = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 22); -}; -pub const SN_setct_AuthRevReqTBS = "setct-AuthRevReqTBS"; -pub const NID_setct_AuthRevReqTBS = @as(c_int, 541); -pub const OBJ_setct_AuthRevReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 23); -}; -pub const SN_setct_AuthRevResData = "setct-AuthRevResData"; -pub const NID_setct_AuthRevResData = @as(c_int, 542); -pub const OBJ_setct_AuthRevResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 24); -}; -pub const SN_setct_AuthRevResTBS = "setct-AuthRevResTBS"; -pub const NID_setct_AuthRevResTBS = @as(c_int, 543); -pub const OBJ_setct_AuthRevResTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 25); -}; -pub const SN_setct_CapReqTBS = "setct-CapReqTBS"; -pub const NID_setct_CapReqTBS = @as(c_int, 544); -pub const OBJ_setct_CapReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 26); -}; -pub const SN_setct_CapReqTBSX = "setct-CapReqTBSX"; -pub const NID_setct_CapReqTBSX = @as(c_int, 545); -pub const OBJ_setct_CapReqTBSX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 27); -}; -pub const SN_setct_CapResData = "setct-CapResData"; -pub const NID_setct_CapResData = @as(c_int, 546); -pub const OBJ_setct_CapResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 28); -}; -pub const SN_setct_CapRevReqTBS = "setct-CapRevReqTBS"; -pub const NID_setct_CapRevReqTBS = @as(c_int, 547); -pub const OBJ_setct_CapRevReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 29); -}; -pub const SN_setct_CapRevReqTBSX = "setct-CapRevReqTBSX"; -pub const NID_setct_CapRevReqTBSX = @as(c_int, 548); -pub const OBJ_setct_CapRevReqTBSX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 30); -}; -pub const SN_setct_CapRevResData = "setct-CapRevResData"; -pub const NID_setct_CapRevResData = @as(c_int, 549); -pub const OBJ_setct_CapRevResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 31); -}; -pub const SN_setct_CredReqTBS = "setct-CredReqTBS"; -pub const NID_setct_CredReqTBS = @as(c_int, 550); -pub const OBJ_setct_CredReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 32); -}; -pub const SN_setct_CredReqTBSX = "setct-CredReqTBSX"; -pub const NID_setct_CredReqTBSX = @as(c_int, 551); -pub const OBJ_setct_CredReqTBSX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 33); -}; -pub const SN_setct_CredResData = "setct-CredResData"; -pub const NID_setct_CredResData = @as(c_int, 552); -pub const OBJ_setct_CredResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 34); -}; -pub const SN_setct_CredRevReqTBS = "setct-CredRevReqTBS"; -pub const NID_setct_CredRevReqTBS = @as(c_int, 553); -pub const OBJ_setct_CredRevReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 35); -}; -pub const SN_setct_CredRevReqTBSX = "setct-CredRevReqTBSX"; -pub const NID_setct_CredRevReqTBSX = @as(c_int, 554); -pub const OBJ_setct_CredRevReqTBSX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 36); -}; -pub const SN_setct_CredRevResData = "setct-CredRevResData"; -pub const NID_setct_CredRevResData = @as(c_int, 555); -pub const OBJ_setct_CredRevResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 37); -}; -pub const SN_setct_PCertReqData = "setct-PCertReqData"; -pub const NID_setct_PCertReqData = @as(c_int, 556); -pub const OBJ_setct_PCertReqData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 38); -}; -pub const SN_setct_PCertResTBS = "setct-PCertResTBS"; -pub const NID_setct_PCertResTBS = @as(c_int, 557); -pub const OBJ_setct_PCertResTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 39); -}; -pub const SN_setct_BatchAdminReqData = "setct-BatchAdminReqData"; -pub const NID_setct_BatchAdminReqData = @as(c_int, 558); -pub const OBJ_setct_BatchAdminReqData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 40); -}; -pub const SN_setct_BatchAdminResData = "setct-BatchAdminResData"; -pub const NID_setct_BatchAdminResData = @as(c_int, 559); -pub const OBJ_setct_BatchAdminResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 41); -}; -pub const SN_setct_CardCInitResTBS = "setct-CardCInitResTBS"; -pub const NID_setct_CardCInitResTBS = @as(c_int, 560); -pub const OBJ_setct_CardCInitResTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 42); -}; -pub const SN_setct_MeAqCInitResTBS = "setct-MeAqCInitResTBS"; -pub const NID_setct_MeAqCInitResTBS = @as(c_int, 561); -pub const OBJ_setct_MeAqCInitResTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 43); -}; -pub const SN_setct_RegFormResTBS = "setct-RegFormResTBS"; -pub const NID_setct_RegFormResTBS = @as(c_int, 562); -pub const OBJ_setct_RegFormResTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 44); -}; -pub const SN_setct_CertReqData = "setct-CertReqData"; -pub const NID_setct_CertReqData = @as(c_int, 563); -pub const OBJ_setct_CertReqData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 45); -}; -pub const SN_setct_CertReqTBS = "setct-CertReqTBS"; -pub const NID_setct_CertReqTBS = @as(c_int, 564); -pub const OBJ_setct_CertReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 46); -}; -pub const SN_setct_CertResData = "setct-CertResData"; -pub const NID_setct_CertResData = @as(c_int, 565); -pub const OBJ_setct_CertResData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 47); -}; -pub const SN_setct_CertInqReqTBS = "setct-CertInqReqTBS"; -pub const NID_setct_CertInqReqTBS = @as(c_int, 566); -pub const OBJ_setct_CertInqReqTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 48); -}; -pub const SN_setct_ErrorTBS = "setct-ErrorTBS"; -pub const NID_setct_ErrorTBS = @as(c_int, 567); -pub const OBJ_setct_ErrorTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 49); -}; -pub const SN_setct_PIDualSignedTBE = "setct-PIDualSignedTBE"; -pub const NID_setct_PIDualSignedTBE = @as(c_int, 568); -pub const OBJ_setct_PIDualSignedTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 50); -}; -pub const SN_setct_PIUnsignedTBE = "setct-PIUnsignedTBE"; -pub const NID_setct_PIUnsignedTBE = @as(c_int, 569); -pub const OBJ_setct_PIUnsignedTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 51); -}; -pub const SN_setct_AuthReqTBE = "setct-AuthReqTBE"; -pub const NID_setct_AuthReqTBE = @as(c_int, 570); -pub const OBJ_setct_AuthReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 52); -}; -pub const SN_setct_AuthResTBE = "setct-AuthResTBE"; -pub const NID_setct_AuthResTBE = @as(c_int, 571); -pub const OBJ_setct_AuthResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 53); -}; -pub const SN_setct_AuthResTBEX = "setct-AuthResTBEX"; -pub const NID_setct_AuthResTBEX = @as(c_int, 572); -pub const OBJ_setct_AuthResTBEX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 54); -}; -pub const SN_setct_AuthTokenTBE = "setct-AuthTokenTBE"; -pub const NID_setct_AuthTokenTBE = @as(c_int, 573); -pub const OBJ_setct_AuthTokenTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 55); -}; -pub const SN_setct_CapTokenTBE = "setct-CapTokenTBE"; -pub const NID_setct_CapTokenTBE = @as(c_int, 574); -pub const OBJ_setct_CapTokenTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 56); -}; -pub const SN_setct_CapTokenTBEX = "setct-CapTokenTBEX"; -pub const NID_setct_CapTokenTBEX = @as(c_int, 575); -pub const OBJ_setct_CapTokenTBEX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 57); -}; -pub const SN_setct_AcqCardCodeMsgTBE = "setct-AcqCardCodeMsgTBE"; -pub const NID_setct_AcqCardCodeMsgTBE = @as(c_int, 576); -pub const OBJ_setct_AcqCardCodeMsgTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 58); -}; -pub const SN_setct_AuthRevReqTBE = "setct-AuthRevReqTBE"; -pub const NID_setct_AuthRevReqTBE = @as(c_int, 577); -pub const OBJ_setct_AuthRevReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 59); -}; -pub const SN_setct_AuthRevResTBE = "setct-AuthRevResTBE"; -pub const NID_setct_AuthRevResTBE = @as(c_int, 578); -pub const OBJ_setct_AuthRevResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 60); -}; -pub const SN_setct_AuthRevResTBEB = "setct-AuthRevResTBEB"; -pub const NID_setct_AuthRevResTBEB = @as(c_int, 579); -pub const OBJ_setct_AuthRevResTBEB = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 61); -}; -pub const SN_setct_CapReqTBE = "setct-CapReqTBE"; -pub const NID_setct_CapReqTBE = @as(c_int, 580); -pub const OBJ_setct_CapReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 62); -}; -pub const SN_setct_CapReqTBEX = "setct-CapReqTBEX"; -pub const NID_setct_CapReqTBEX = @as(c_int, 581); -pub const OBJ_setct_CapReqTBEX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 63); -}; -pub const SN_setct_CapResTBE = "setct-CapResTBE"; -pub const NID_setct_CapResTBE = @as(c_int, 582); -pub const OBJ_setct_CapResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 64); -}; -pub const SN_setct_CapRevReqTBE = "setct-CapRevReqTBE"; -pub const NID_setct_CapRevReqTBE = @as(c_int, 583); -pub const OBJ_setct_CapRevReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 65); -}; -pub const SN_setct_CapRevReqTBEX = "setct-CapRevReqTBEX"; -pub const NID_setct_CapRevReqTBEX = @as(c_int, 584); -pub const OBJ_setct_CapRevReqTBEX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 66); -}; -pub const SN_setct_CapRevResTBE = "setct-CapRevResTBE"; -pub const NID_setct_CapRevResTBE = @as(c_int, 585); -pub const OBJ_setct_CapRevResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 67); -}; -pub const SN_setct_CredReqTBE = "setct-CredReqTBE"; -pub const NID_setct_CredReqTBE = @as(c_int, 586); -pub const OBJ_setct_CredReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 68); -}; -pub const SN_setct_CredReqTBEX = "setct-CredReqTBEX"; -pub const NID_setct_CredReqTBEX = @as(c_int, 587); -pub const OBJ_setct_CredReqTBEX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 69); -}; -pub const SN_setct_CredResTBE = "setct-CredResTBE"; -pub const NID_setct_CredResTBE = @as(c_int, 588); -pub const OBJ_setct_CredResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 70); -}; -pub const SN_setct_CredRevReqTBE = "setct-CredRevReqTBE"; -pub const NID_setct_CredRevReqTBE = @as(c_int, 589); -pub const OBJ_setct_CredRevReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 71); -}; -pub const SN_setct_CredRevReqTBEX = "setct-CredRevReqTBEX"; -pub const NID_setct_CredRevReqTBEX = @as(c_int, 590); -pub const OBJ_setct_CredRevReqTBEX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 72); -}; -pub const SN_setct_CredRevResTBE = "setct-CredRevResTBE"; -pub const NID_setct_CredRevResTBE = @as(c_int, 591); -pub const OBJ_setct_CredRevResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 73); -}; -pub const SN_setct_BatchAdminReqTBE = "setct-BatchAdminReqTBE"; -pub const NID_setct_BatchAdminReqTBE = @as(c_int, 592); -pub const OBJ_setct_BatchAdminReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 74); -}; -pub const SN_setct_BatchAdminResTBE = "setct-BatchAdminResTBE"; -pub const NID_setct_BatchAdminResTBE = @as(c_int, 593); -pub const OBJ_setct_BatchAdminResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 75); -}; -pub const SN_setct_RegFormReqTBE = "setct-RegFormReqTBE"; -pub const NID_setct_RegFormReqTBE = @as(c_int, 594); -pub const OBJ_setct_RegFormReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 76); -}; -pub const SN_setct_CertReqTBE = "setct-CertReqTBE"; -pub const NID_setct_CertReqTBE = @as(c_int, 595); -pub const OBJ_setct_CertReqTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 77); -}; -pub const SN_setct_CertReqTBEX = "setct-CertReqTBEX"; -pub const NID_setct_CertReqTBEX = @as(c_int, 596); -pub const OBJ_setct_CertReqTBEX = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 78); -}; -pub const SN_setct_CertResTBE = "setct-CertResTBE"; -pub const NID_setct_CertResTBE = @as(c_int, 597); -pub const OBJ_setct_CertResTBE = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 79); -}; -pub const SN_setct_CRLNotificationTBS = "setct-CRLNotificationTBS"; -pub const NID_setct_CRLNotificationTBS = @as(c_int, 598); -pub const OBJ_setct_CRLNotificationTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 80); -}; -pub const SN_setct_CRLNotificationResTBS = "setct-CRLNotificationResTBS"; -pub const NID_setct_CRLNotificationResTBS = @as(c_int, 599); -pub const OBJ_setct_CRLNotificationResTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 81); -}; -pub const SN_setct_BCIDistributionTBS = "setct-BCIDistributionTBS"; -pub const NID_setct_BCIDistributionTBS = @as(c_int, 600); -pub const OBJ_setct_BCIDistributionTBS = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 0); - break :blk @as(c_long, 82); -}; -pub const SN_setext_genCrypt = "setext-genCrypt"; -pub const LN_setext_genCrypt = "generic cryptogram"; -pub const NID_setext_genCrypt = @as(c_int, 601); -pub const OBJ_setext_genCrypt = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_setext_miAuth = "setext-miAuth"; -pub const LN_setext_miAuth = "merchant initiated auth"; -pub const NID_setext_miAuth = @as(c_int, 602); -pub const OBJ_setext_miAuth = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_setext_pinSecure = "setext-pinSecure"; -pub const NID_setext_pinSecure = @as(c_int, 603); -pub const OBJ_setext_pinSecure = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_setext_pinAny = "setext-pinAny"; -pub const NID_setext_pinAny = @as(c_int, 604); -pub const OBJ_setext_pinAny = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_setext_track2 = "setext-track2"; -pub const NID_setext_track2 = @as(c_int, 605); -pub const OBJ_setext_track2 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_setext_cv = "setext-cv"; -pub const LN_setext_cv = "additional verification"; -pub const NID_setext_cv = @as(c_int, 606); -pub const OBJ_setext_cv = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_set_policy_root = "set-policy-root"; -pub const NID_set_policy_root = @as(c_int, 607); -pub const OBJ_set_policy_root = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 5); - break :blk @as(c_long, 0); -}; -pub const SN_setCext_hashedRoot = "setCext-hashedRoot"; -pub const NID_setCext_hashedRoot = @as(c_int, 608); -pub const OBJ_setCext_hashedRoot = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 0); -}; -pub const SN_setCext_certType = "setCext-certType"; -pub const NID_setCext_certType = @as(c_int, 609); -pub const OBJ_setCext_certType = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 1); -}; -pub const SN_setCext_merchData = "setCext-merchData"; -pub const NID_setCext_merchData = @as(c_int, 610); -pub const OBJ_setCext_merchData = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 2); -}; -pub const SN_setCext_cCertRequired = "setCext-cCertRequired"; -pub const NID_setCext_cCertRequired = @as(c_int, 611); -pub const OBJ_setCext_cCertRequired = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 3); -}; -pub const SN_setCext_tunneling = "setCext-tunneling"; -pub const NID_setCext_tunneling = @as(c_int, 612); -pub const OBJ_setCext_tunneling = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 4); -}; -pub const SN_setCext_setExt = "setCext-setExt"; -pub const NID_setCext_setExt = @as(c_int, 613); -pub const OBJ_setCext_setExt = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 5); -}; -pub const SN_setCext_setQualf = "setCext-setQualf"; -pub const NID_setCext_setQualf = @as(c_int, 614); -pub const OBJ_setCext_setQualf = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 6); -}; -pub const SN_setCext_PGWYcapabilities = "setCext-PGWYcapabilities"; -pub const NID_setCext_PGWYcapabilities = @as(c_int, 615); -pub const OBJ_setCext_PGWYcapabilities = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 7); -}; -pub const SN_setCext_TokenIdentifier = "setCext-TokenIdentifier"; -pub const NID_setCext_TokenIdentifier = @as(c_int, 616); -pub const OBJ_setCext_TokenIdentifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 8); -}; -pub const SN_setCext_Track2Data = "setCext-Track2Data"; -pub const NID_setCext_Track2Data = @as(c_int, 617); -pub const OBJ_setCext_Track2Data = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 9); -}; -pub const SN_setCext_TokenType = "setCext-TokenType"; -pub const NID_setCext_TokenType = @as(c_int, 618); -pub const OBJ_setCext_TokenType = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 10); -}; -pub const SN_setCext_IssuerCapabilities = "setCext-IssuerCapabilities"; -pub const NID_setCext_IssuerCapabilities = @as(c_int, 619); -pub const OBJ_setCext_IssuerCapabilities = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 7); - break :blk @as(c_long, 11); -}; -pub const SN_setAttr_Cert = "setAttr-Cert"; -pub const NID_setAttr_Cert = @as(c_int, 620); -pub const OBJ_setAttr_Cert = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - break :blk @as(c_long, 0); -}; -pub const SN_setAttr_PGWYcap = "setAttr-PGWYcap"; -pub const LN_setAttr_PGWYcap = "payment gateway capabilities"; -pub const NID_setAttr_PGWYcap = @as(c_int, 621); -pub const OBJ_setAttr_PGWYcap = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_setAttr_TokenType = "setAttr-TokenType"; -pub const NID_setAttr_TokenType = @as(c_int, 622); -pub const OBJ_setAttr_TokenType = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_setAttr_IssCap = "setAttr-IssCap"; -pub const LN_setAttr_IssCap = "issuer capabilities"; -pub const NID_setAttr_IssCap = @as(c_int, 623); -pub const OBJ_setAttr_IssCap = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_set_rootKeyThumb = "set-rootKeyThumb"; -pub const NID_set_rootKeyThumb = @as(c_int, 624); -pub const OBJ_set_rootKeyThumb = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 0); -}; -pub const SN_set_addPolicy = "set-addPolicy"; -pub const NID_set_addPolicy = @as(c_int, 625); -pub const OBJ_set_addPolicy = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 1); -}; -pub const SN_setAttr_Token_EMV = "setAttr-Token-EMV"; -pub const NID_setAttr_Token_EMV = @as(c_int, 626); -pub const OBJ_setAttr_Token_EMV = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_setAttr_Token_B0Prime = "setAttr-Token-B0Prime"; -pub const NID_setAttr_Token_B0Prime = @as(c_int, 627); -pub const OBJ_setAttr_Token_B0Prime = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_setAttr_IssCap_CVM = "setAttr-IssCap-CVM"; -pub const NID_setAttr_IssCap_CVM = @as(c_int, 628); -pub const OBJ_setAttr_IssCap_CVM = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_setAttr_IssCap_T2 = "setAttr-IssCap-T2"; -pub const NID_setAttr_IssCap_T2 = @as(c_int, 629); -pub const OBJ_setAttr_IssCap_T2 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const SN_setAttr_IssCap_Sig = "setAttr-IssCap-Sig"; -pub const NID_setAttr_IssCap_Sig = @as(c_int, 630); -pub const OBJ_setAttr_IssCap_Sig = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - break :blk @as(c_long, 5); -}; -pub const SN_setAttr_GenCryptgrm = "setAttr-GenCryptgrm"; -pub const LN_setAttr_GenCryptgrm = "generate cryptogram"; -pub const NID_setAttr_GenCryptgrm = @as(c_int, 631); -pub const OBJ_setAttr_GenCryptgrm = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_setAttr_T2Enc = "setAttr-T2Enc"; -pub const LN_setAttr_T2Enc = "encrypted track 2"; -pub const NID_setAttr_T2Enc = @as(c_int, 632); -pub const OBJ_setAttr_T2Enc = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_setAttr_T2cleartxt = "setAttr-T2cleartxt"; -pub const LN_setAttr_T2cleartxt = "cleartext track 2"; -pub const NID_setAttr_T2cleartxt = @as(c_int, 633); -pub const OBJ_setAttr_T2cleartxt = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - break :blk @as(c_long, 2); -}; -pub const SN_setAttr_TokICCsig = "setAttr-TokICCsig"; -pub const LN_setAttr_TokICCsig = "ICC or token signature"; -pub const NID_setAttr_TokICCsig = @as(c_int, 634); -pub const OBJ_setAttr_TokICCsig = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 5); - break :blk @as(c_long, 1); -}; -pub const SN_setAttr_SecDevSig = "setAttr-SecDevSig"; -pub const LN_setAttr_SecDevSig = "secure device signature"; -pub const NID_setAttr_SecDevSig = @as(c_int, 635); -pub const OBJ_setAttr_SecDevSig = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 5); - break :blk @as(c_long, 2); -}; -pub const SN_set_brand_IATA_ATA = "set-brand-IATA-ATA"; -pub const NID_set_brand_IATA_ATA = @as(c_int, 636); -pub const OBJ_set_brand_IATA_ATA = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 8); - break :blk @as(c_long, 1); -}; -pub const SN_set_brand_Diners = "set-brand-Diners"; -pub const NID_set_brand_Diners = @as(c_int, 637); -pub const OBJ_set_brand_Diners = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 8); - break :blk @as(c_long, 30); -}; -pub const SN_set_brand_AmericanExpress = "set-brand-AmericanExpress"; -pub const NID_set_brand_AmericanExpress = @as(c_int, 638); -pub const OBJ_set_brand_AmericanExpress = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 8); - break :blk @as(c_long, 34); -}; -pub const SN_set_brand_JCB = "set-brand-JCB"; -pub const NID_set_brand_JCB = @as(c_int, 639); -pub const OBJ_set_brand_JCB = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 8); - break :blk @as(c_long, 35); -}; -pub const SN_set_brand_Visa = "set-brand-Visa"; -pub const NID_set_brand_Visa = @as(c_int, 640); -pub const OBJ_set_brand_Visa = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 8); - break :blk @as(c_long, 4); -}; -pub const SN_set_brand_MasterCard = "set-brand-MasterCard"; -pub const NID_set_brand_MasterCard = @as(c_int, 641); -pub const OBJ_set_brand_MasterCard = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 8); - break :blk @as(c_long, 5); -}; -pub const SN_set_brand_Novus = "set-brand-Novus"; -pub const NID_set_brand_Novus = @as(c_int, 642); -pub const OBJ_set_brand_Novus = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 42); - _ = @as(c_long, 8); - break :blk @as(c_long, 6011); -}; -pub const SN_des_cdmf = "DES-CDMF"; -pub const LN_des_cdmf = "des-cdmf"; -pub const NID_des_cdmf = @as(c_int, 643); -pub const OBJ_des_cdmf = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 3); - break :blk @as(c_long, 10); -}; -pub const SN_rsaOAEPEncryptionSET = "rsaOAEPEncryptionSET"; -pub const NID_rsaOAEPEncryptionSET = @as(c_int, 644); -pub const OBJ_rsaOAEPEncryptionSET = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_itu_t = "ITU-T"; -pub const LN_itu_t = "itu-t"; -pub const NID_itu_t = @as(c_int, 645); -pub const OBJ_itu_t = @as(c_long, 0); -pub const SN_joint_iso_itu_t = "JOINT-ISO-ITU-T"; -pub const LN_joint_iso_itu_t = "joint-iso-itu-t"; -pub const NID_joint_iso_itu_t = @as(c_int, 646); -pub const OBJ_joint_iso_itu_t = @as(c_long, 2); -pub const SN_international_organizations = "international-organizations"; -pub const LN_international_organizations = "International Organizations"; -pub const NID_international_organizations = @as(c_int, 647); -pub const OBJ_international_organizations = blk: { - _ = @as(c_long, 2); - break :blk @as(c_long, 23); -}; -pub const SN_ms_smartcard_login = "msSmartcardLogin"; -pub const LN_ms_smartcard_login = "Microsoft Smartcardlogin"; -pub const NID_ms_smartcard_login = @as(c_int, 648); -pub const OBJ_ms_smartcard_login = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 20); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_ms_upn = "msUPN"; -pub const LN_ms_upn = "Microsoft Universal Principal Name"; -pub const NID_ms_upn = @as(c_int, 649); -pub const OBJ_ms_upn = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 20); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const SN_aes_128_cfb1 = "AES-128-CFB1"; -pub const LN_aes_128_cfb1 = "aes-128-cfb1"; -pub const NID_aes_128_cfb1 = @as(c_int, 650); -pub const SN_aes_192_cfb1 = "AES-192-CFB1"; -pub const LN_aes_192_cfb1 = "aes-192-cfb1"; -pub const NID_aes_192_cfb1 = @as(c_int, 651); -pub const SN_aes_256_cfb1 = "AES-256-CFB1"; -pub const LN_aes_256_cfb1 = "aes-256-cfb1"; -pub const NID_aes_256_cfb1 = @as(c_int, 652); -pub const SN_aes_128_cfb8 = "AES-128-CFB8"; -pub const LN_aes_128_cfb8 = "aes-128-cfb8"; -pub const NID_aes_128_cfb8 = @as(c_int, 653); -pub const SN_aes_192_cfb8 = "AES-192-CFB8"; -pub const LN_aes_192_cfb8 = "aes-192-cfb8"; -pub const NID_aes_192_cfb8 = @as(c_int, 654); -pub const SN_aes_256_cfb8 = "AES-256-CFB8"; -pub const LN_aes_256_cfb8 = "aes-256-cfb8"; -pub const NID_aes_256_cfb8 = @as(c_int, 655); -pub const SN_des_cfb1 = "DES-CFB1"; -pub const LN_des_cfb1 = "des-cfb1"; -pub const NID_des_cfb1 = @as(c_int, 656); -pub const SN_des_cfb8 = "DES-CFB8"; -pub const LN_des_cfb8 = "des-cfb8"; -pub const NID_des_cfb8 = @as(c_int, 657); -pub const SN_des_ede3_cfb1 = "DES-EDE3-CFB1"; -pub const LN_des_ede3_cfb1 = "des-ede3-cfb1"; -pub const NID_des_ede3_cfb1 = @as(c_int, 658); -pub const SN_des_ede3_cfb8 = "DES-EDE3-CFB8"; -pub const LN_des_ede3_cfb8 = "des-ede3-cfb8"; -pub const NID_des_ede3_cfb8 = @as(c_int, 659); -pub const SN_streetAddress = "street"; -pub const LN_streetAddress = "streetAddress"; -pub const NID_streetAddress = @as(c_int, 660); -pub const OBJ_streetAddress = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 9); -}; -pub const LN_postalCode = "postalCode"; -pub const NID_postalCode = @as(c_int, 661); -pub const OBJ_postalCode = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 17); -}; -pub const SN_id_ppl = "id-ppl"; -pub const NID_id_ppl = @as(c_int, 662); -pub const OBJ_id_ppl = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - break :blk @as(c_long, 21); -}; -pub const SN_proxyCertInfo = "proxyCertInfo"; -pub const LN_proxyCertInfo = "Proxy Certificate Information"; -pub const NID_proxyCertInfo = @as(c_int, 663); -pub const OBJ_proxyCertInfo = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 1); - break :blk @as(c_long, 14); -}; -pub const SN_id_ppl_anyLanguage = "id-ppl-anyLanguage"; -pub const LN_id_ppl_anyLanguage = "Any language"; -pub const NID_id_ppl_anyLanguage = @as(c_int, 664); -pub const OBJ_id_ppl_anyLanguage = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 21); - break :blk @as(c_long, 0); -}; -pub const SN_id_ppl_inheritAll = "id-ppl-inheritAll"; -pub const LN_id_ppl_inheritAll = "Inherit all"; -pub const NID_id_ppl_inheritAll = @as(c_int, 665); -pub const OBJ_id_ppl_inheritAll = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 21); - break :blk @as(c_long, 1); -}; -pub const SN_name_constraints = "nameConstraints"; -pub const LN_name_constraints = "X509v3 Name Constraints"; -pub const NID_name_constraints = @as(c_int, 666); -pub const OBJ_name_constraints = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 30); -}; -pub const SN_Independent = "id-ppl-independent"; -pub const LN_Independent = "Independent"; -pub const NID_Independent = @as(c_int, 667); -pub const OBJ_Independent = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 21); - break :blk @as(c_long, 2); -}; -pub const SN_sha256WithRSAEncryption = "RSA-SHA256"; -pub const LN_sha256WithRSAEncryption = "sha256WithRSAEncryption"; -pub const NID_sha256WithRSAEncryption = @as(c_int, 668); -pub const OBJ_sha256WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 11); -}; -pub const SN_sha384WithRSAEncryption = "RSA-SHA384"; -pub const LN_sha384WithRSAEncryption = "sha384WithRSAEncryption"; -pub const NID_sha384WithRSAEncryption = @as(c_int, 669); -pub const OBJ_sha384WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 12); -}; -pub const SN_sha512WithRSAEncryption = "RSA-SHA512"; -pub const LN_sha512WithRSAEncryption = "sha512WithRSAEncryption"; -pub const NID_sha512WithRSAEncryption = @as(c_int, 670); -pub const OBJ_sha512WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 13); -}; -pub const SN_sha224WithRSAEncryption = "RSA-SHA224"; -pub const LN_sha224WithRSAEncryption = "sha224WithRSAEncryption"; -pub const NID_sha224WithRSAEncryption = @as(c_int, 671); -pub const OBJ_sha224WithRSAEncryption = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 14); -}; -pub const SN_sha256 = "SHA256"; -pub const LN_sha256 = "sha256"; -pub const NID_sha256 = @as(c_int, 672); -pub const OBJ_sha256 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_sha384 = "SHA384"; -pub const LN_sha384 = "sha384"; -pub const NID_sha384 = @as(c_int, 673); -pub const OBJ_sha384 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_sha512 = "SHA512"; -pub const LN_sha512 = "sha512"; -pub const NID_sha512 = @as(c_int, 674); -pub const OBJ_sha512 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const SN_sha224 = "SHA224"; -pub const LN_sha224 = "sha224"; -pub const NID_sha224 = @as(c_int, 675); -pub const OBJ_sha224 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 2); - break :blk @as(c_long, 4); -}; -pub const SN_identified_organization = "identified-organization"; -pub const NID_identified_organization = @as(c_int, 676); -pub const OBJ_identified_organization = blk: { - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_certicom_arc = "certicom-arc"; -pub const NID_certicom_arc = @as(c_int, 677); -pub const OBJ_certicom_arc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 132); -}; -pub const SN_wap = "wap"; -pub const NID_wap = @as(c_int, 678); -pub const OBJ_wap = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - break :blk @as(c_long, 43); -}; -pub const SN_wap_wsg = "wap-wsg"; -pub const NID_wap_wsg = @as(c_int, 679); -pub const OBJ_wap_wsg = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - break :blk @as(c_long, 1); -}; -pub const SN_X9_62_id_characteristic_two_basis = "id-characteristic-two-basis"; -pub const NID_X9_62_id_characteristic_two_basis = @as(c_int, 680); -pub const OBJ_X9_62_id_characteristic_two_basis = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 1); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const SN_X9_62_onBasis = "onBasis"; -pub const NID_X9_62_onBasis = @as(c_int, 681); -pub const OBJ_X9_62_onBasis = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_X9_62_tpBasis = "tpBasis"; -pub const NID_X9_62_tpBasis = @as(c_int, 682); -pub const OBJ_X9_62_tpBasis = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_X9_62_ppBasis = "ppBasis"; -pub const NID_X9_62_ppBasis = @as(c_int, 683); -pub const OBJ_X9_62_ppBasis = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_X9_62_c2pnb163v1 = "c2pnb163v1"; -pub const NID_X9_62_c2pnb163v1 = @as(c_int, 684); -pub const OBJ_X9_62_c2pnb163v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 1); -}; -pub const SN_X9_62_c2pnb163v2 = "c2pnb163v2"; -pub const NID_X9_62_c2pnb163v2 = @as(c_int, 685); -pub const OBJ_X9_62_c2pnb163v2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 2); -}; -pub const SN_X9_62_c2pnb163v3 = "c2pnb163v3"; -pub const NID_X9_62_c2pnb163v3 = @as(c_int, 686); -pub const OBJ_X9_62_c2pnb163v3 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 3); -}; -pub const SN_X9_62_c2pnb176v1 = "c2pnb176v1"; -pub const NID_X9_62_c2pnb176v1 = @as(c_int, 687); -pub const OBJ_X9_62_c2pnb176v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 4); -}; -pub const SN_X9_62_c2tnb191v1 = "c2tnb191v1"; -pub const NID_X9_62_c2tnb191v1 = @as(c_int, 688); -pub const OBJ_X9_62_c2tnb191v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 5); -}; -pub const SN_X9_62_c2tnb191v2 = "c2tnb191v2"; -pub const NID_X9_62_c2tnb191v2 = @as(c_int, 689); -pub const OBJ_X9_62_c2tnb191v2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 6); -}; -pub const SN_X9_62_c2tnb191v3 = "c2tnb191v3"; -pub const NID_X9_62_c2tnb191v3 = @as(c_int, 690); -pub const OBJ_X9_62_c2tnb191v3 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 7); -}; -pub const SN_X9_62_c2onb191v4 = "c2onb191v4"; -pub const NID_X9_62_c2onb191v4 = @as(c_int, 691); -pub const OBJ_X9_62_c2onb191v4 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 8); -}; -pub const SN_X9_62_c2onb191v5 = "c2onb191v5"; -pub const NID_X9_62_c2onb191v5 = @as(c_int, 692); -pub const OBJ_X9_62_c2onb191v5 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 9); -}; -pub const SN_X9_62_c2pnb208w1 = "c2pnb208w1"; -pub const NID_X9_62_c2pnb208w1 = @as(c_int, 693); -pub const OBJ_X9_62_c2pnb208w1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 10); -}; -pub const SN_X9_62_c2tnb239v1 = "c2tnb239v1"; -pub const NID_X9_62_c2tnb239v1 = @as(c_int, 694); -pub const OBJ_X9_62_c2tnb239v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 11); -}; -pub const SN_X9_62_c2tnb239v2 = "c2tnb239v2"; -pub const NID_X9_62_c2tnb239v2 = @as(c_int, 695); -pub const OBJ_X9_62_c2tnb239v2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 12); -}; -pub const SN_X9_62_c2tnb239v3 = "c2tnb239v3"; -pub const NID_X9_62_c2tnb239v3 = @as(c_int, 696); -pub const OBJ_X9_62_c2tnb239v3 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 13); -}; -pub const SN_X9_62_c2onb239v4 = "c2onb239v4"; -pub const NID_X9_62_c2onb239v4 = @as(c_int, 697); -pub const OBJ_X9_62_c2onb239v4 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 14); -}; -pub const SN_X9_62_c2onb239v5 = "c2onb239v5"; -pub const NID_X9_62_c2onb239v5 = @as(c_int, 698); -pub const OBJ_X9_62_c2onb239v5 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 15); -}; -pub const SN_X9_62_c2pnb272w1 = "c2pnb272w1"; -pub const NID_X9_62_c2pnb272w1 = @as(c_int, 699); -pub const OBJ_X9_62_c2pnb272w1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 16); -}; -pub const SN_X9_62_c2pnb304w1 = "c2pnb304w1"; -pub const NID_X9_62_c2pnb304w1 = @as(c_int, 700); -pub const OBJ_X9_62_c2pnb304w1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 17); -}; -pub const SN_X9_62_c2tnb359v1 = "c2tnb359v1"; -pub const NID_X9_62_c2tnb359v1 = @as(c_int, 701); -pub const OBJ_X9_62_c2tnb359v1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 18); -}; -pub const SN_X9_62_c2pnb368w1 = "c2pnb368w1"; -pub const NID_X9_62_c2pnb368w1 = @as(c_int, 702); -pub const OBJ_X9_62_c2pnb368w1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 19); -}; -pub const SN_X9_62_c2tnb431r1 = "c2tnb431r1"; -pub const NID_X9_62_c2tnb431r1 = @as(c_int, 703); -pub const OBJ_X9_62_c2tnb431r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 20); -}; -pub const SN_secp112r1 = "secp112r1"; -pub const NID_secp112r1 = @as(c_int, 704); -pub const OBJ_secp112r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 6); -}; -pub const SN_secp112r2 = "secp112r2"; -pub const NID_secp112r2 = @as(c_int, 705); -pub const OBJ_secp112r2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 7); -}; -pub const SN_secp128r1 = "secp128r1"; -pub const NID_secp128r1 = @as(c_int, 706); -pub const OBJ_secp128r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 28); -}; -pub const SN_secp128r2 = "secp128r2"; -pub const NID_secp128r2 = @as(c_int, 707); -pub const OBJ_secp128r2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 29); -}; -pub const SN_secp160k1 = "secp160k1"; -pub const NID_secp160k1 = @as(c_int, 708); -pub const OBJ_secp160k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 9); -}; -pub const SN_secp160r1 = "secp160r1"; -pub const NID_secp160r1 = @as(c_int, 709); -pub const OBJ_secp160r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 8); -}; -pub const SN_secp160r2 = "secp160r2"; -pub const NID_secp160r2 = @as(c_int, 710); -pub const OBJ_secp160r2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 30); -}; -pub const SN_secp192k1 = "secp192k1"; -pub const NID_secp192k1 = @as(c_int, 711); -pub const OBJ_secp192k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 31); -}; -pub const SN_secp224k1 = "secp224k1"; -pub const NID_secp224k1 = @as(c_int, 712); -pub const OBJ_secp224k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 32); -}; -pub const SN_secp224r1 = "secp224r1"; -pub const NID_secp224r1 = @as(c_int, 713); -pub const OBJ_secp224r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 33); -}; -pub const SN_secp256k1 = "secp256k1"; -pub const NID_secp256k1 = @as(c_int, 714); -pub const OBJ_secp256k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 10); -}; -pub const SN_secp384r1 = "secp384r1"; -pub const NID_secp384r1 = @as(c_int, 715); -pub const OBJ_secp384r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 34); -}; -pub const SN_secp521r1 = "secp521r1"; -pub const NID_secp521r1 = @as(c_int, 716); -pub const OBJ_secp521r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 35); -}; -pub const SN_sect113r1 = "sect113r1"; -pub const NID_sect113r1 = @as(c_int, 717); -pub const OBJ_sect113r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 4); -}; -pub const SN_sect113r2 = "sect113r2"; -pub const NID_sect113r2 = @as(c_int, 718); -pub const OBJ_sect113r2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 5); -}; -pub const SN_sect131r1 = "sect131r1"; -pub const NID_sect131r1 = @as(c_int, 719); -pub const OBJ_sect131r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 22); -}; -pub const SN_sect131r2 = "sect131r2"; -pub const NID_sect131r2 = @as(c_int, 720); -pub const OBJ_sect131r2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 23); -}; -pub const SN_sect163k1 = "sect163k1"; -pub const NID_sect163k1 = @as(c_int, 721); -pub const OBJ_sect163k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 1); -}; -pub const SN_sect163r1 = "sect163r1"; -pub const NID_sect163r1 = @as(c_int, 722); -pub const OBJ_sect163r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 2); -}; -pub const SN_sect163r2 = "sect163r2"; -pub const NID_sect163r2 = @as(c_int, 723); -pub const OBJ_sect163r2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 15); -}; -pub const SN_sect193r1 = "sect193r1"; -pub const NID_sect193r1 = @as(c_int, 724); -pub const OBJ_sect193r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 24); -}; -pub const SN_sect193r2 = "sect193r2"; -pub const NID_sect193r2 = @as(c_int, 725); -pub const OBJ_sect193r2 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 25); -}; -pub const SN_sect233k1 = "sect233k1"; -pub const NID_sect233k1 = @as(c_int, 726); -pub const OBJ_sect233k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 26); -}; -pub const SN_sect233r1 = "sect233r1"; -pub const NID_sect233r1 = @as(c_int, 727); -pub const OBJ_sect233r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 27); -}; -pub const SN_sect239k1 = "sect239k1"; -pub const NID_sect239k1 = @as(c_int, 728); -pub const OBJ_sect239k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 3); -}; -pub const SN_sect283k1 = "sect283k1"; -pub const NID_sect283k1 = @as(c_int, 729); -pub const OBJ_sect283k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 16); -}; -pub const SN_sect283r1 = "sect283r1"; -pub const NID_sect283r1 = @as(c_int, 730); -pub const OBJ_sect283r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 17); -}; -pub const SN_sect409k1 = "sect409k1"; -pub const NID_sect409k1 = @as(c_int, 731); -pub const OBJ_sect409k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 36); -}; -pub const SN_sect409r1 = "sect409r1"; -pub const NID_sect409r1 = @as(c_int, 732); -pub const OBJ_sect409r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 37); -}; -pub const SN_sect571k1 = "sect571k1"; -pub const NID_sect571k1 = @as(c_int, 733); -pub const OBJ_sect571k1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 38); -}; -pub const SN_sect571r1 = "sect571r1"; -pub const NID_sect571r1 = @as(c_int, 734); -pub const OBJ_sect571r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 0); - break :blk @as(c_long, 39); -}; -pub const SN_wap_wsg_idm_ecid_wtls1 = "wap-wsg-idm-ecid-wtls1"; -pub const NID_wap_wsg_idm_ecid_wtls1 = @as(c_int, 735); -pub const OBJ_wap_wsg_idm_ecid_wtls1 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 1); -}; -pub const SN_wap_wsg_idm_ecid_wtls3 = "wap-wsg-idm-ecid-wtls3"; -pub const NID_wap_wsg_idm_ecid_wtls3 = @as(c_int, 736); -pub const OBJ_wap_wsg_idm_ecid_wtls3 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 3); -}; -pub const SN_wap_wsg_idm_ecid_wtls4 = "wap-wsg-idm-ecid-wtls4"; -pub const NID_wap_wsg_idm_ecid_wtls4 = @as(c_int, 737); -pub const OBJ_wap_wsg_idm_ecid_wtls4 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 4); -}; -pub const SN_wap_wsg_idm_ecid_wtls5 = "wap-wsg-idm-ecid-wtls5"; -pub const NID_wap_wsg_idm_ecid_wtls5 = @as(c_int, 738); -pub const OBJ_wap_wsg_idm_ecid_wtls5 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 5); -}; -pub const SN_wap_wsg_idm_ecid_wtls6 = "wap-wsg-idm-ecid-wtls6"; -pub const NID_wap_wsg_idm_ecid_wtls6 = @as(c_int, 739); -pub const OBJ_wap_wsg_idm_ecid_wtls6 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 6); -}; -pub const SN_wap_wsg_idm_ecid_wtls7 = "wap-wsg-idm-ecid-wtls7"; -pub const NID_wap_wsg_idm_ecid_wtls7 = @as(c_int, 740); -pub const OBJ_wap_wsg_idm_ecid_wtls7 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 7); -}; -pub const SN_wap_wsg_idm_ecid_wtls8 = "wap-wsg-idm-ecid-wtls8"; -pub const NID_wap_wsg_idm_ecid_wtls8 = @as(c_int, 741); -pub const OBJ_wap_wsg_idm_ecid_wtls8 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 8); -}; -pub const SN_wap_wsg_idm_ecid_wtls9 = "wap-wsg-idm-ecid-wtls9"; -pub const NID_wap_wsg_idm_ecid_wtls9 = @as(c_int, 742); -pub const OBJ_wap_wsg_idm_ecid_wtls9 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 9); -}; -pub const SN_wap_wsg_idm_ecid_wtls10 = "wap-wsg-idm-ecid-wtls10"; -pub const NID_wap_wsg_idm_ecid_wtls10 = @as(c_int, 743); -pub const OBJ_wap_wsg_idm_ecid_wtls10 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 10); -}; -pub const SN_wap_wsg_idm_ecid_wtls11 = "wap-wsg-idm-ecid-wtls11"; -pub const NID_wap_wsg_idm_ecid_wtls11 = @as(c_int, 744); -pub const OBJ_wap_wsg_idm_ecid_wtls11 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 11); -}; -pub const SN_wap_wsg_idm_ecid_wtls12 = "wap-wsg-idm-ecid-wtls12"; -pub const NID_wap_wsg_idm_ecid_wtls12 = @as(c_int, 745); -pub const OBJ_wap_wsg_idm_ecid_wtls12 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 23); - _ = @as(c_long, 43); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - break :blk @as(c_long, 12); -}; -pub const SN_any_policy = "anyPolicy"; -pub const LN_any_policy = "X509v3 Any Policy"; -pub const NID_any_policy = @as(c_int, 746); -pub const OBJ_any_policy = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - _ = @as(c_long, 32); - break :blk @as(c_long, 0); -}; -pub const SN_policy_mappings = "policyMappings"; -pub const LN_policy_mappings = "X509v3 Policy Mappings"; -pub const NID_policy_mappings = @as(c_int, 747); -pub const OBJ_policy_mappings = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 33); -}; -pub const SN_inhibit_any_policy = "inhibitAnyPolicy"; -pub const LN_inhibit_any_policy = "X509v3 Inhibit Any Policy"; -pub const NID_inhibit_any_policy = @as(c_int, 748); -pub const OBJ_inhibit_any_policy = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 54); -}; -pub const SN_ipsec3 = "Oakley-EC2N-3"; -pub const LN_ipsec3 = "ipsec3"; -pub const NID_ipsec3 = @as(c_int, 749); -pub const SN_ipsec4 = "Oakley-EC2N-4"; -pub const LN_ipsec4 = "ipsec4"; -pub const NID_ipsec4 = @as(c_int, 750); -pub const SN_camellia_128_cbc = "CAMELLIA-128-CBC"; -pub const LN_camellia_128_cbc = "camellia-128-cbc"; -pub const NID_camellia_128_cbc = @as(c_int, 751); -pub const OBJ_camellia_128_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 392); - _ = @as(c_long, 200011); - _ = @as(c_long, 61); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_camellia_192_cbc = "CAMELLIA-192-CBC"; -pub const LN_camellia_192_cbc = "camellia-192-cbc"; -pub const NID_camellia_192_cbc = @as(c_int, 752); -pub const OBJ_camellia_192_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 392); - _ = @as(c_long, 200011); - _ = @as(c_long, 61); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_camellia_256_cbc = "CAMELLIA-256-CBC"; -pub const LN_camellia_256_cbc = "camellia-256-cbc"; -pub const NID_camellia_256_cbc = @as(c_int, 753); -pub const OBJ_camellia_256_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 392); - _ = @as(c_long, 200011); - _ = @as(c_long, 61); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_camellia_128_ecb = "CAMELLIA-128-ECB"; -pub const LN_camellia_128_ecb = "camellia-128-ecb"; -pub const NID_camellia_128_ecb = @as(c_int, 754); -pub const OBJ_camellia_128_ecb = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 1); -}; -pub const SN_camellia_192_ecb = "CAMELLIA-192-ECB"; -pub const LN_camellia_192_ecb = "camellia-192-ecb"; -pub const NID_camellia_192_ecb = @as(c_int, 755); -pub const OBJ_camellia_192_ecb = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 21); -}; -pub const SN_camellia_256_ecb = "CAMELLIA-256-ECB"; -pub const LN_camellia_256_ecb = "camellia-256-ecb"; -pub const NID_camellia_256_ecb = @as(c_int, 756); -pub const OBJ_camellia_256_ecb = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 41); -}; -pub const SN_camellia_128_cfb128 = "CAMELLIA-128-CFB"; -pub const LN_camellia_128_cfb128 = "camellia-128-cfb"; -pub const NID_camellia_128_cfb128 = @as(c_int, 757); -pub const OBJ_camellia_128_cfb128 = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 4); -}; -pub const SN_camellia_192_cfb128 = "CAMELLIA-192-CFB"; -pub const LN_camellia_192_cfb128 = "camellia-192-cfb"; -pub const NID_camellia_192_cfb128 = @as(c_int, 758); -pub const OBJ_camellia_192_cfb128 = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 24); -}; -pub const SN_camellia_256_cfb128 = "CAMELLIA-256-CFB"; -pub const LN_camellia_256_cfb128 = "camellia-256-cfb"; -pub const NID_camellia_256_cfb128 = @as(c_int, 759); -pub const OBJ_camellia_256_cfb128 = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 44); -}; -pub const SN_camellia_128_cfb1 = "CAMELLIA-128-CFB1"; -pub const LN_camellia_128_cfb1 = "camellia-128-cfb1"; -pub const NID_camellia_128_cfb1 = @as(c_int, 760); -pub const SN_camellia_192_cfb1 = "CAMELLIA-192-CFB1"; -pub const LN_camellia_192_cfb1 = "camellia-192-cfb1"; -pub const NID_camellia_192_cfb1 = @as(c_int, 761); -pub const SN_camellia_256_cfb1 = "CAMELLIA-256-CFB1"; -pub const LN_camellia_256_cfb1 = "camellia-256-cfb1"; -pub const NID_camellia_256_cfb1 = @as(c_int, 762); -pub const SN_camellia_128_cfb8 = "CAMELLIA-128-CFB8"; -pub const LN_camellia_128_cfb8 = "camellia-128-cfb8"; -pub const NID_camellia_128_cfb8 = @as(c_int, 763); -pub const SN_camellia_192_cfb8 = "CAMELLIA-192-CFB8"; -pub const LN_camellia_192_cfb8 = "camellia-192-cfb8"; -pub const NID_camellia_192_cfb8 = @as(c_int, 764); -pub const SN_camellia_256_cfb8 = "CAMELLIA-256-CFB8"; -pub const LN_camellia_256_cfb8 = "camellia-256-cfb8"; -pub const NID_camellia_256_cfb8 = @as(c_int, 765); -pub const SN_camellia_128_ofb128 = "CAMELLIA-128-OFB"; -pub const LN_camellia_128_ofb128 = "camellia-128-ofb"; -pub const NID_camellia_128_ofb128 = @as(c_int, 766); -pub const OBJ_camellia_128_ofb128 = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 3); -}; -pub const SN_camellia_192_ofb128 = "CAMELLIA-192-OFB"; -pub const LN_camellia_192_ofb128 = "camellia-192-ofb"; -pub const NID_camellia_192_ofb128 = @as(c_int, 767); -pub const OBJ_camellia_192_ofb128 = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 23); -}; -pub const SN_camellia_256_ofb128 = "CAMELLIA-256-OFB"; -pub const LN_camellia_256_ofb128 = "camellia-256-ofb"; -pub const NID_camellia_256_ofb128 = @as(c_int, 768); -pub const OBJ_camellia_256_ofb128 = blk: { - _ = @as(c_long, 0); - _ = @as(c_long, 3); - _ = @as(c_long, 4401); - _ = @as(c_long, 5); - _ = @as(c_long, 3); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - break :blk @as(c_long, 43); -}; -pub const SN_subject_directory_attributes = "subjectDirectoryAttributes"; -pub const LN_subject_directory_attributes = "X509v3 Subject Directory Attributes"; -pub const NID_subject_directory_attributes = @as(c_int, 769); -pub const OBJ_subject_directory_attributes = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 9); -}; -pub const SN_issuing_distribution_point = "issuingDistributionPoint"; -pub const LN_issuing_distribution_point = "X509v3 Issuing Distribution Point"; -pub const NID_issuing_distribution_point = @as(c_int, 770); -pub const OBJ_issuing_distribution_point = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 28); -}; -pub const SN_certificate_issuer = "certificateIssuer"; -pub const LN_certificate_issuer = "X509v3 Certificate Issuer"; -pub const NID_certificate_issuer = @as(c_int, 771); -pub const OBJ_certificate_issuer = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 29); -}; -pub const SN_kisa = "KISA"; -pub const LN_kisa = "kisa"; -pub const NID_kisa = @as(c_int, 773); -pub const OBJ_kisa = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 410); - break :blk @as(c_long, 200004); -}; -pub const SN_seed_ecb = "SEED-ECB"; -pub const LN_seed_ecb = "seed-ecb"; -pub const NID_seed_ecb = @as(c_int, 776); -pub const OBJ_seed_ecb = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 410); - _ = @as(c_long, 200004); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_seed_cbc = "SEED-CBC"; -pub const LN_seed_cbc = "seed-cbc"; -pub const NID_seed_cbc = @as(c_int, 777); -pub const OBJ_seed_cbc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 410); - _ = @as(c_long, 200004); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_seed_ofb128 = "SEED-OFB"; -pub const LN_seed_ofb128 = "seed-ofb"; -pub const NID_seed_ofb128 = @as(c_int, 778); -pub const OBJ_seed_ofb128 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 410); - _ = @as(c_long, 200004); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_seed_cfb128 = "SEED-CFB"; -pub const LN_seed_cfb128 = "seed-cfb"; -pub const NID_seed_cfb128 = @as(c_int, 779); -pub const OBJ_seed_cfb128 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 410); - _ = @as(c_long, 200004); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_hmac_md5 = "HMAC-MD5"; -pub const LN_hmac_md5 = "hmac-md5"; -pub const NID_hmac_md5 = @as(c_int, 780); -pub const OBJ_hmac_md5 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_hmac_sha1 = "HMAC-SHA1"; -pub const LN_hmac_sha1 = "hmac-sha1"; -pub const NID_hmac_sha1 = @as(c_int, 781); -pub const OBJ_hmac_sha1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_id_PasswordBasedMAC = "id-PasswordBasedMAC"; -pub const LN_id_PasswordBasedMAC = "password based MAC"; -pub const NID_id_PasswordBasedMAC = @as(c_int, 782); -pub const OBJ_id_PasswordBasedMAC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113533); - _ = @as(c_long, 7); - _ = @as(c_long, 66); - break :blk @as(c_long, 13); -}; -pub const SN_id_DHBasedMac = "id-DHBasedMac"; -pub const LN_id_DHBasedMac = "Diffie-Hellman based MAC"; -pub const NID_id_DHBasedMac = @as(c_int, 783); -pub const OBJ_id_DHBasedMac = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113533); - _ = @as(c_long, 7); - _ = @as(c_long, 66); - break :blk @as(c_long, 30); -}; -pub const SN_id_it_suppLangTags = "id-it-suppLangTags"; -pub const NID_id_it_suppLangTags = @as(c_int, 784); -pub const OBJ_id_it_suppLangTags = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 4); - break :blk @as(c_long, 16); -}; -pub const SN_caRepository = "caRepository"; -pub const LN_caRepository = "CA Repository"; -pub const NID_caRepository = @as(c_int, 785); -pub const OBJ_caRepository = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 48); - break :blk @as(c_long, 5); -}; -pub const SN_id_smime_ct_compressedData = "id-smime-ct-compressedData"; -pub const NID_id_smime_ct_compressedData = @as(c_int, 786); -pub const OBJ_id_smime_ct_compressedData = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 9); -}; -pub const SN_id_ct_asciiTextWithCRLF = "id-ct-asciiTextWithCRLF"; -pub const NID_id_ct_asciiTextWithCRLF = @as(c_int, 787); -pub const OBJ_id_ct_asciiTextWithCRLF = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 1); - break :blk @as(c_long, 27); -}; -pub const SN_id_aes128_wrap = "id-aes128-wrap"; -pub const NID_id_aes128_wrap = @as(c_int, 788); -pub const OBJ_id_aes128_wrap = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_id_aes192_wrap = "id-aes192-wrap"; -pub const NID_id_aes192_wrap = @as(c_int, 789); -pub const OBJ_id_aes192_wrap = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 25); -}; -pub const SN_id_aes256_wrap = "id-aes256-wrap"; -pub const NID_id_aes256_wrap = @as(c_int, 790); -pub const OBJ_id_aes256_wrap = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 45); -}; -pub const SN_ecdsa_with_Recommended = "ecdsa-with-Recommended"; -pub const NID_ecdsa_with_Recommended = @as(c_int, 791); -pub const OBJ_ecdsa_with_Recommended = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 4); - break :blk @as(c_long, 2); -}; -pub const SN_ecdsa_with_Specified = "ecdsa-with-Specified"; -pub const NID_ecdsa_with_Specified = @as(c_int, 792); -pub const OBJ_ecdsa_with_Specified = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 4); - break :blk @as(c_long, 3); -}; -pub const SN_ecdsa_with_SHA224 = "ecdsa-with-SHA224"; -pub const NID_ecdsa_with_SHA224 = @as(c_int, 793); -pub const OBJ_ecdsa_with_SHA224 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 4); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_ecdsa_with_SHA256 = "ecdsa-with-SHA256"; -pub const NID_ecdsa_with_SHA256 = @as(c_int, 794); -pub const OBJ_ecdsa_with_SHA256 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 4); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_ecdsa_with_SHA384 = "ecdsa-with-SHA384"; -pub const NID_ecdsa_with_SHA384 = @as(c_int, 795); -pub const OBJ_ecdsa_with_SHA384 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 4); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_ecdsa_with_SHA512 = "ecdsa-with-SHA512"; -pub const NID_ecdsa_with_SHA512 = @as(c_int, 796); -pub const OBJ_ecdsa_with_SHA512 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10045); - _ = @as(c_long, 4); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const LN_hmacWithMD5 = "hmacWithMD5"; -pub const NID_hmacWithMD5 = @as(c_int, 797); -pub const OBJ_hmacWithMD5 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 6); -}; -pub const LN_hmacWithSHA224 = "hmacWithSHA224"; -pub const NID_hmacWithSHA224 = @as(c_int, 798); -pub const OBJ_hmacWithSHA224 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 8); -}; -pub const LN_hmacWithSHA256 = "hmacWithSHA256"; -pub const NID_hmacWithSHA256 = @as(c_int, 799); -pub const OBJ_hmacWithSHA256 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 9); -}; -pub const LN_hmacWithSHA384 = "hmacWithSHA384"; -pub const NID_hmacWithSHA384 = @as(c_int, 800); -pub const OBJ_hmacWithSHA384 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 10); -}; -pub const LN_hmacWithSHA512 = "hmacWithSHA512"; -pub const NID_hmacWithSHA512 = @as(c_int, 801); -pub const OBJ_hmacWithSHA512 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 2); - break :blk @as(c_long, 11); -}; -pub const SN_dsa_with_SHA224 = "dsa_with_SHA224"; -pub const NID_dsa_with_SHA224 = @as(c_int, 802); -pub const OBJ_dsa_with_SHA224 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 3); - break :blk @as(c_long, 1); -}; -pub const SN_dsa_with_SHA256 = "dsa_with_SHA256"; -pub const NID_dsa_with_SHA256 = @as(c_int, 803); -pub const OBJ_dsa_with_SHA256 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_whirlpool = "whirlpool"; -pub const NID_whirlpool = @as(c_int, 804); -pub const OBJ_whirlpool = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 0); - _ = @as(c_long, 10118); - _ = @as(c_long, 3); - _ = @as(c_long, 0); - break :blk @as(c_long, 55); -}; -pub const SN_cryptopro = "cryptopro"; -pub const NID_cryptopro = @as(c_int, 805); -pub const OBJ_cryptopro = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - break :blk @as(c_long, 2); -}; -pub const SN_cryptocom = "cryptocom"; -pub const NID_cryptocom = @as(c_int, 806); -pub const OBJ_cryptocom = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - break :blk @as(c_long, 9); -}; -pub const SN_id_GostR3411_94_with_GostR3410_2001 = "id-GostR3411-94-with-GostR3410-2001"; -pub const LN_id_GostR3411_94_with_GostR3410_2001 = "GOST R 34.11-94 with GOST R 34.10-2001"; -pub const NID_id_GostR3411_94_with_GostR3410_2001 = @as(c_int, 807); -pub const OBJ_id_GostR3411_94_with_GostR3410_2001 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 3); -}; -pub const SN_id_GostR3411_94_with_GostR3410_94 = "id-GostR3411-94-with-GostR3410-94"; -pub const LN_id_GostR3411_94_with_GostR3410_94 = "GOST R 34.11-94 with GOST R 34.10-94"; -pub const NID_id_GostR3411_94_with_GostR3410_94 = @as(c_int, 808); -pub const OBJ_id_GostR3411_94_with_GostR3410_94 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 4); -}; -pub const SN_id_GostR3411_94 = "md_gost94"; -pub const LN_id_GostR3411_94 = "GOST R 34.11-94"; -pub const NID_id_GostR3411_94 = @as(c_int, 809); -pub const OBJ_id_GostR3411_94 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 9); -}; -pub const SN_id_HMACGostR3411_94 = "id-HMACGostR3411-94"; -pub const LN_id_HMACGostR3411_94 = "HMAC GOST 34.11-94"; -pub const NID_id_HMACGostR3411_94 = @as(c_int, 810); -pub const OBJ_id_HMACGostR3411_94 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 10); -}; -pub const SN_id_GostR3410_2001 = "gost2001"; -pub const LN_id_GostR3410_2001 = "GOST R 34.10-2001"; -pub const NID_id_GostR3410_2001 = @as(c_int, 811); - -pub const OBJ_id_GostR3410_2001 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 19); -}; - -pub const NID_id_GostR3410_2012_256 = @as(c_int, 979); -pub const NID_id_GostR3410_2012_512 = @as(c_int, 980); -pub const SN_id_GostR3410_94 = "gost94"; -pub const LN_id_GostR3410_94 = "GOST R 34.10-94"; -pub const NID_id_GostR3410_94 = @as(c_int, 812); -pub const OBJ_id_GostR3410_94 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 20); -}; -pub const SN_id_Gost28147_89 = "gost89"; -pub const LN_id_Gost28147_89 = "GOST 28147-89"; -pub const NID_id_Gost28147_89 = @as(c_int, 813); -pub const OBJ_id_Gost28147_89 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 21); -}; -pub const SN_gost89_cnt = "gost89-cnt"; -pub const NID_gost89_cnt = @as(c_int, 814); -pub const SN_id_Gost28147_89_MAC = "gost-mac"; -pub const LN_id_Gost28147_89_MAC = "GOST 28147-89 MAC"; -pub const NID_id_Gost28147_89_MAC = @as(c_int, 815); -pub const OBJ_id_Gost28147_89_MAC = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 22); -}; -pub const SN_id_GostR3411_94_prf = "prf-gostr3411-94"; -pub const LN_id_GostR3411_94_prf = "GOST R 34.11-94 PRF"; -pub const NID_id_GostR3411_94_prf = @as(c_int, 816); -pub const OBJ_id_GostR3411_94_prf = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 23); -}; -pub const SN_id_GostR3410_2001DH = "id-GostR3410-2001DH"; -pub const LN_id_GostR3410_2001DH = "GOST R 34.10-2001 DH"; -pub const NID_id_GostR3410_2001DH = @as(c_int, 817); -pub const OBJ_id_GostR3410_2001DH = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 98); -}; -pub const SN_id_GostR3410_94DH = "id-GostR3410-94DH"; -pub const LN_id_GostR3410_94DH = "GOST R 34.10-94 DH"; -pub const NID_id_GostR3410_94DH = @as(c_int, 818); -pub const OBJ_id_GostR3410_94DH = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - break :blk @as(c_long, 99); -}; -pub const SN_id_Gost28147_89_CryptoPro_KeyMeshing = "id-Gost28147-89-CryptoPro-KeyMeshing"; -pub const NID_id_Gost28147_89_CryptoPro_KeyMeshing = @as(c_int, 819); -pub const OBJ_id_Gost28147_89_CryptoPro_KeyMeshing = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 14); - break :blk @as(c_long, 1); -}; -pub const SN_id_Gost28147_89_None_KeyMeshing = "id-Gost28147-89-None-KeyMeshing"; -pub const NID_id_Gost28147_89_None_KeyMeshing = @as(c_int, 820); -pub const OBJ_id_Gost28147_89_None_KeyMeshing = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 14); - break :blk @as(c_long, 0); -}; -pub const SN_id_GostR3411_94_TestParamSet = "id-GostR3411-94-TestParamSet"; -pub const NID_id_GostR3411_94_TestParamSet = @as(c_int, 821); -pub const OBJ_id_GostR3411_94_TestParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 30); - break :blk @as(c_long, 0); -}; -pub const SN_id_GostR3411_94_CryptoProParamSet = "id-GostR3411-94-CryptoProParamSet"; -pub const NID_id_GostR3411_94_CryptoProParamSet = @as(c_int, 822); -pub const OBJ_id_GostR3411_94_CryptoProParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 30); - break :blk @as(c_long, 1); -}; -pub const SN_id_Gost28147_89_TestParamSet = "id-Gost28147-89-TestParamSet"; -pub const NID_id_Gost28147_89_TestParamSet = @as(c_int, 823); -pub const OBJ_id_Gost28147_89_TestParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 0); -}; -pub const SN_id_Gost28147_89_CryptoPro_A_ParamSet = "id-Gost28147-89-CryptoPro-A-ParamSet"; -pub const NID_id_Gost28147_89_CryptoPro_A_ParamSet = @as(c_int, 824); -pub const OBJ_id_Gost28147_89_CryptoPro_A_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 1); -}; -pub const SN_id_Gost28147_89_CryptoPro_B_ParamSet = "id-Gost28147-89-CryptoPro-B-ParamSet"; -pub const NID_id_Gost28147_89_CryptoPro_B_ParamSet = @as(c_int, 825); -pub const OBJ_id_Gost28147_89_CryptoPro_B_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 2); -}; -pub const SN_id_Gost28147_89_CryptoPro_C_ParamSet = "id-Gost28147-89-CryptoPro-C-ParamSet"; -pub const NID_id_Gost28147_89_CryptoPro_C_ParamSet = @as(c_int, 826); -pub const OBJ_id_Gost28147_89_CryptoPro_C_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 3); -}; -pub const SN_id_Gost28147_89_CryptoPro_D_ParamSet = "id-Gost28147-89-CryptoPro-D-ParamSet"; -pub const NID_id_Gost28147_89_CryptoPro_D_ParamSet = @as(c_int, 827); -pub const OBJ_id_Gost28147_89_CryptoPro_D_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 4); -}; -pub const SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet = "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet"; -pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet = @as(c_int, 828); -pub const OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 5); -}; -pub const SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet = "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet"; -pub const NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet = @as(c_int, 829); -pub const OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 6); -}; -pub const SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet = "id-Gost28147-89-CryptoPro-RIC-1-ParamSet"; -pub const NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet = @as(c_int, 830); -pub const OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 31); - break :blk @as(c_long, 7); -}; -pub const SN_id_GostR3410_94_TestParamSet = "id-GostR3410-94-TestParamSet"; -pub const NID_id_GostR3410_94_TestParamSet = @as(c_int, 831); -pub const OBJ_id_GostR3410_94_TestParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 32); - break :blk @as(c_long, 0); -}; -pub const SN_id_GostR3410_94_CryptoPro_A_ParamSet = "id-GostR3410-94-CryptoPro-A-ParamSet"; -pub const NID_id_GostR3410_94_CryptoPro_A_ParamSet = @as(c_int, 832); -pub const OBJ_id_GostR3410_94_CryptoPro_A_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 32); - break :blk @as(c_long, 2); -}; -pub const SN_id_GostR3410_94_CryptoPro_B_ParamSet = "id-GostR3410-94-CryptoPro-B-ParamSet"; -pub const NID_id_GostR3410_94_CryptoPro_B_ParamSet = @as(c_int, 833); -pub const OBJ_id_GostR3410_94_CryptoPro_B_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 32); - break :blk @as(c_long, 3); -}; -pub const SN_id_GostR3410_94_CryptoPro_C_ParamSet = "id-GostR3410-94-CryptoPro-C-ParamSet"; -pub const NID_id_GostR3410_94_CryptoPro_C_ParamSet = @as(c_int, 834); -pub const OBJ_id_GostR3410_94_CryptoPro_C_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 32); - break :blk @as(c_long, 4); -}; -pub const SN_id_GostR3410_94_CryptoPro_D_ParamSet = "id-GostR3410-94-CryptoPro-D-ParamSet"; -pub const NID_id_GostR3410_94_CryptoPro_D_ParamSet = @as(c_int, 835); -pub const OBJ_id_GostR3410_94_CryptoPro_D_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 32); - break :blk @as(c_long, 5); -}; -pub const SN_id_GostR3410_94_CryptoPro_XchA_ParamSet = "id-GostR3410-94-CryptoPro-XchA-ParamSet"; -pub const NID_id_GostR3410_94_CryptoPro_XchA_ParamSet = @as(c_int, 836); -pub const OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 33); - break :blk @as(c_long, 1); -}; -pub const SN_id_GostR3410_94_CryptoPro_XchB_ParamSet = "id-GostR3410-94-CryptoPro-XchB-ParamSet"; -pub const NID_id_GostR3410_94_CryptoPro_XchB_ParamSet = @as(c_int, 837); -pub const OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 33); - break :blk @as(c_long, 2); -}; -pub const SN_id_GostR3410_94_CryptoPro_XchC_ParamSet = "id-GostR3410-94-CryptoPro-XchC-ParamSet"; -pub const NID_id_GostR3410_94_CryptoPro_XchC_ParamSet = @as(c_int, 838); -pub const OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 33); - break :blk @as(c_long, 3); -}; -pub const SN_id_GostR3410_2001_TestParamSet = "id-GostR3410-2001-TestParamSet"; -pub const NID_id_GostR3410_2001_TestParamSet = @as(c_int, 839); -pub const OBJ_id_GostR3410_2001_TestParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 35); - break :blk @as(c_long, 0); -}; -pub const SN_id_GostR3410_2001_CryptoPro_A_ParamSet = "id-GostR3410-2001-CryptoPro-A-ParamSet"; -pub const NID_id_GostR3410_2001_CryptoPro_A_ParamSet = @as(c_int, 840); -pub const OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 35); - break :blk @as(c_long, 1); -}; -pub const SN_id_GostR3410_2001_CryptoPro_B_ParamSet = "id-GostR3410-2001-CryptoPro-B-ParamSet"; -pub const NID_id_GostR3410_2001_CryptoPro_B_ParamSet = @as(c_int, 841); -pub const OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 35); - break :blk @as(c_long, 2); -}; -pub const SN_id_GostR3410_2001_CryptoPro_C_ParamSet = "id-GostR3410-2001-CryptoPro-C-ParamSet"; -pub const NID_id_GostR3410_2001_CryptoPro_C_ParamSet = @as(c_int, 842); -pub const OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 35); - break :blk @as(c_long, 3); -}; -pub const SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet = "id-GostR3410-2001-CryptoPro-XchA-ParamSet"; -pub const NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet = @as(c_int, 843); -pub const OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 36); - break :blk @as(c_long, 0); -}; -pub const SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet = "id-GostR3410-2001-CryptoPro-XchB-ParamSet"; -pub const NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet = @as(c_int, 844); -pub const OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 36); - break :blk @as(c_long, 1); -}; -pub const SN_id_GostR3410_94_a = "id-GostR3410-94-a"; -pub const NID_id_GostR3410_94_a = @as(c_int, 845); -pub const OBJ_id_GostR3410_94_a = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 20); - break :blk @as(c_long, 1); -}; -pub const SN_id_GostR3410_94_aBis = "id-GostR3410-94-aBis"; -pub const NID_id_GostR3410_94_aBis = @as(c_int, 846); -pub const OBJ_id_GostR3410_94_aBis = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 20); - break :blk @as(c_long, 2); -}; -pub const SN_id_GostR3410_94_b = "id-GostR3410-94-b"; -pub const NID_id_GostR3410_94_b = @as(c_int, 847); -pub const OBJ_id_GostR3410_94_b = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 20); - break :blk @as(c_long, 3); -}; -pub const SN_id_GostR3410_94_bBis = "id-GostR3410-94-bBis"; -pub const NID_id_GostR3410_94_bBis = @as(c_int, 848); -pub const OBJ_id_GostR3410_94_bBis = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 2); - _ = @as(c_long, 20); - break :blk @as(c_long, 4); -}; -pub const SN_id_Gost28147_89_cc = "id-Gost28147-89-cc"; -pub const LN_id_Gost28147_89_cc = "GOST 28147-89 Cryptocom ParamSet"; -pub const NID_id_Gost28147_89_cc = @as(c_int, 849); -pub const OBJ_id_Gost28147_89_cc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 9); - _ = @as(c_long, 1); - _ = @as(c_long, 6); - break :blk @as(c_long, 1); -}; -pub const SN_id_GostR3410_94_cc = "gost94cc"; -pub const LN_id_GostR3410_94_cc = "GOST 34.10-94 Cryptocom"; -pub const NID_id_GostR3410_94_cc = @as(c_int, 850); -pub const OBJ_id_GostR3410_94_cc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 9); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 3); -}; -pub const SN_id_GostR3410_2001_cc = "gost2001cc"; -pub const LN_id_GostR3410_2001_cc = "GOST 34.10-2001 Cryptocom"; -pub const NID_id_GostR3410_2001_cc = @as(c_int, 851); -pub const OBJ_id_GostR3410_2001_cc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 9); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - break :blk @as(c_long, 4); -}; -pub const SN_id_GostR3411_94_with_GostR3410_94_cc = "id-GostR3411-94-with-GostR3410-94-cc"; -pub const LN_id_GostR3411_94_with_GostR3410_94_cc = "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom"; -pub const NID_id_GostR3411_94_with_GostR3410_94_cc = @as(c_int, 852); -pub const OBJ_id_GostR3411_94_with_GostR3410_94_cc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 9); - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_id_GostR3411_94_with_GostR3410_2001_cc = "id-GostR3411-94-with-GostR3410-2001-cc"; -pub const LN_id_GostR3411_94_with_GostR3410_2001_cc = "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom"; -pub const NID_id_GostR3411_94_with_GostR3410_2001_cc = @as(c_int, 853); -pub const OBJ_id_GostR3411_94_with_GostR3410_2001_cc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 9); - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const SN_id_GostR3410_2001_ParamSet_cc = "id-GostR3410-2001-ParamSet-cc"; -pub const LN_id_GostR3410_2001_ParamSet_cc = "GOST R 3410-2001 Parameter Set Cryptocom"; -pub const NID_id_GostR3410_2001_ParamSet_cc = @as(c_int, 854); -pub const OBJ_id_GostR3410_2001_ParamSet_cc = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 643); - _ = @as(c_long, 2); - _ = @as(c_long, 9); - _ = @as(c_long, 1); - _ = @as(c_long, 8); - break :blk @as(c_long, 1); -}; -pub const SN_hmac = "HMAC"; -pub const LN_hmac = "hmac"; -pub const NID_hmac = @as(c_int, 855); -pub const SN_LocalKeySet = "LocalKeySet"; -pub const LN_LocalKeySet = "Microsoft Local Key set"; -pub const NID_LocalKeySet = @as(c_int, 856); -pub const OBJ_LocalKeySet = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - _ = @as(c_long, 311); - _ = @as(c_long, 17); - break :blk @as(c_long, 2); -}; -pub const SN_freshest_crl = "freshestCRL"; -pub const LN_freshest_crl = "X509v3 Freshest CRL"; -pub const NID_freshest_crl = @as(c_int, 857); -pub const OBJ_freshest_crl = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - break :blk @as(c_long, 46); -}; -pub const SN_id_on_permanentIdentifier = "id-on-permanentIdentifier"; -pub const LN_id_on_permanentIdentifier = "Permanent Identifier"; -pub const NID_id_on_permanentIdentifier = @as(c_int, 858); -pub const OBJ_id_on_permanentIdentifier = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 6); - _ = @as(c_long, 1); - _ = @as(c_long, 5); - _ = @as(c_long, 5); - _ = @as(c_long, 7); - _ = @as(c_long, 8); - break :blk @as(c_long, 3); -}; -pub const LN_searchGuide = "searchGuide"; -pub const NID_searchGuide = @as(c_int, 859); -pub const OBJ_searchGuide = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 14); -}; -pub const LN_businessCategory = "businessCategory"; -pub const NID_businessCategory = @as(c_int, 860); -pub const OBJ_businessCategory = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 15); -}; -pub const LN_postalAddress = "postalAddress"; -pub const NID_postalAddress = @as(c_int, 861); -pub const OBJ_postalAddress = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 16); -}; -pub const LN_postOfficeBox = "postOfficeBox"; -pub const NID_postOfficeBox = @as(c_int, 862); -pub const OBJ_postOfficeBox = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 18); -}; -pub const LN_physicalDeliveryOfficeName = "physicalDeliveryOfficeName"; -pub const NID_physicalDeliveryOfficeName = @as(c_int, 863); -pub const OBJ_physicalDeliveryOfficeName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 19); -}; -pub const LN_telephoneNumber = "telephoneNumber"; -pub const NID_telephoneNumber = @as(c_int, 864); -pub const OBJ_telephoneNumber = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 20); -}; -pub const LN_telexNumber = "telexNumber"; -pub const NID_telexNumber = @as(c_int, 865); -pub const OBJ_telexNumber = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 21); -}; -pub const LN_teletexTerminalIdentifier = "teletexTerminalIdentifier"; -pub const NID_teletexTerminalIdentifier = @as(c_int, 866); -pub const OBJ_teletexTerminalIdentifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 22); -}; -pub const LN_facsimileTelephoneNumber = "facsimileTelephoneNumber"; -pub const NID_facsimileTelephoneNumber = @as(c_int, 867); -pub const OBJ_facsimileTelephoneNumber = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 23); -}; -pub const LN_x121Address = "x121Address"; -pub const NID_x121Address = @as(c_int, 868); -pub const OBJ_x121Address = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 24); -}; -pub const LN_internationaliSDNNumber = "internationaliSDNNumber"; -pub const NID_internationaliSDNNumber = @as(c_int, 869); -pub const OBJ_internationaliSDNNumber = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 25); -}; -pub const LN_registeredAddress = "registeredAddress"; -pub const NID_registeredAddress = @as(c_int, 870); -pub const OBJ_registeredAddress = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 26); -}; -pub const LN_destinationIndicator = "destinationIndicator"; -pub const NID_destinationIndicator = @as(c_int, 871); -pub const OBJ_destinationIndicator = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 27); -}; -pub const LN_preferredDeliveryMethod = "preferredDeliveryMethod"; -pub const NID_preferredDeliveryMethod = @as(c_int, 872); -pub const OBJ_preferredDeliveryMethod = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 28); -}; -pub const LN_presentationAddress = "presentationAddress"; -pub const NID_presentationAddress = @as(c_int, 873); -pub const OBJ_presentationAddress = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 29); -}; -pub const LN_supportedApplicationContext = "supportedApplicationContext"; -pub const NID_supportedApplicationContext = @as(c_int, 874); -pub const OBJ_supportedApplicationContext = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 30); -}; -pub const SN_member = "member"; -pub const NID_member = @as(c_int, 875); -pub const OBJ_member = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 31); -}; -pub const SN_owner = "owner"; -pub const NID_owner = @as(c_int, 876); -pub const OBJ_owner = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 32); -}; -pub const LN_roleOccupant = "roleOccupant"; -pub const NID_roleOccupant = @as(c_int, 877); -pub const OBJ_roleOccupant = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 33); -}; -pub const SN_seeAlso = "seeAlso"; -pub const NID_seeAlso = @as(c_int, 878); -pub const OBJ_seeAlso = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 34); -}; -pub const LN_userPassword = "userPassword"; -pub const NID_userPassword = @as(c_int, 879); -pub const OBJ_userPassword = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 35); -}; -pub const LN_userCertificate = "userCertificate"; -pub const NID_userCertificate = @as(c_int, 880); -pub const OBJ_userCertificate = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 36); -}; -pub const LN_cACertificate = "cACertificate"; -pub const NID_cACertificate = @as(c_int, 881); -pub const OBJ_cACertificate = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 37); -}; -pub const LN_authorityRevocationList = "authorityRevocationList"; -pub const NID_authorityRevocationList = @as(c_int, 882); -pub const OBJ_authorityRevocationList = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 38); -}; -pub const LN_certificateRevocationList = "certificateRevocationList"; -pub const NID_certificateRevocationList = @as(c_int, 883); -pub const OBJ_certificateRevocationList = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 39); -}; -pub const LN_crossCertificatePair = "crossCertificatePair"; -pub const NID_crossCertificatePair = @as(c_int, 884); -pub const OBJ_crossCertificatePair = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 40); -}; -pub const LN_enhancedSearchGuide = "enhancedSearchGuide"; -pub const NID_enhancedSearchGuide = @as(c_int, 885); -pub const OBJ_enhancedSearchGuide = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 47); -}; -pub const LN_protocolInformation = "protocolInformation"; -pub const NID_protocolInformation = @as(c_int, 886); -pub const OBJ_protocolInformation = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 48); -}; -pub const LN_distinguishedName = "distinguishedName"; -pub const NID_distinguishedName = @as(c_int, 887); -pub const OBJ_distinguishedName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 49); -}; -pub const LN_uniqueMember = "uniqueMember"; -pub const NID_uniqueMember = @as(c_int, 888); -pub const OBJ_uniqueMember = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 50); -}; -pub const LN_houseIdentifier = "houseIdentifier"; -pub const NID_houseIdentifier = @as(c_int, 889); -pub const OBJ_houseIdentifier = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 51); -}; -pub const LN_supportedAlgorithms = "supportedAlgorithms"; -pub const NID_supportedAlgorithms = @as(c_int, 890); -pub const OBJ_supportedAlgorithms = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 52); -}; -pub const LN_deltaRevocationList = "deltaRevocationList"; -pub const NID_deltaRevocationList = @as(c_int, 891); -pub const OBJ_deltaRevocationList = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 53); -}; -pub const SN_dmdName = "dmdName"; -pub const NID_dmdName = @as(c_int, 892); -pub const OBJ_dmdName = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 4); - break :blk @as(c_long, 54); -}; -pub const SN_id_alg_PWRI_KEK = "id-alg-PWRI-KEK"; -pub const NID_id_alg_PWRI_KEK = @as(c_int, 893); -pub const OBJ_id_alg_PWRI_KEK = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 9); - _ = @as(c_long, 16); - _ = @as(c_long, 3); - break :blk @as(c_long, 9); -}; -pub const SN_cmac = "CMAC"; -pub const LN_cmac = "cmac"; -pub const NID_cmac = @as(c_int, 894); -pub const SN_aes_128_gcm = "id-aes128-GCM"; -pub const LN_aes_128_gcm = "aes-128-gcm"; -pub const NID_aes_128_gcm = @as(c_int, 895); -pub const OBJ_aes_128_gcm = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_aes_128_ccm = "id-aes128-CCM"; -pub const LN_aes_128_ccm = "aes-128-ccm"; -pub const NID_aes_128_ccm = @as(c_int, 896); -pub const OBJ_aes_128_ccm = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_id_aes128_wrap_pad = "id-aes128-wrap-pad"; -pub const NID_id_aes128_wrap_pad = @as(c_int, 897); -pub const OBJ_id_aes128_wrap_pad = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_aes_192_gcm = "id-aes192-GCM"; -pub const LN_aes_192_gcm = "aes-192-gcm"; -pub const NID_aes_192_gcm = @as(c_int, 898); -pub const OBJ_aes_192_gcm = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 26); -}; -pub const SN_aes_192_ccm = "id-aes192-CCM"; -pub const LN_aes_192_ccm = "aes-192-ccm"; -pub const NID_aes_192_ccm = @as(c_int, 899); -pub const OBJ_aes_192_ccm = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 27); -}; -pub const SN_id_aes192_wrap_pad = "id-aes192-wrap-pad"; -pub const NID_id_aes192_wrap_pad = @as(c_int, 900); -pub const OBJ_id_aes192_wrap_pad = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 28); -}; -pub const SN_aes_256_gcm = "id-aes256-GCM"; -pub const LN_aes_256_gcm = "aes-256-gcm"; -pub const NID_aes_256_gcm = @as(c_int, 901); -pub const OBJ_aes_256_gcm = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 46); -}; -pub const SN_aes_256_ccm = "id-aes256-CCM"; -pub const LN_aes_256_ccm = "aes-256-ccm"; -pub const NID_aes_256_ccm = @as(c_int, 902); -pub const OBJ_aes_256_ccm = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 47); -}; -pub const SN_id_aes256_wrap_pad = "id-aes256-wrap-pad"; -pub const NID_id_aes256_wrap_pad = @as(c_int, 903); -pub const OBJ_id_aes256_wrap_pad = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 1); - break :blk @as(c_long, 48); -}; -pub const SN_aes_128_ctr = "AES-128-CTR"; -pub const LN_aes_128_ctr = "aes-128-ctr"; -pub const NID_aes_128_ctr = @as(c_int, 904); -pub const SN_aes_192_ctr = "AES-192-CTR"; -pub const LN_aes_192_ctr = "aes-192-ctr"; -pub const NID_aes_192_ctr = @as(c_int, 905); -pub const SN_aes_256_ctr = "AES-256-CTR"; -pub const LN_aes_256_ctr = "aes-256-ctr"; -pub const NID_aes_256_ctr = @as(c_int, 906); -pub const SN_id_camellia128_wrap = "id-camellia128-wrap"; -pub const NID_id_camellia128_wrap = @as(c_int, 907); -pub const OBJ_id_camellia128_wrap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 392); - _ = @as(c_long, 200011); - _ = @as(c_long, 61); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 2); -}; -pub const SN_id_camellia192_wrap = "id-camellia192-wrap"; -pub const NID_id_camellia192_wrap = @as(c_int, 908); -pub const OBJ_id_camellia192_wrap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 392); - _ = @as(c_long, 200011); - _ = @as(c_long, 61); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 3); -}; -pub const SN_id_camellia256_wrap = "id-camellia256-wrap"; -pub const NID_id_camellia256_wrap = @as(c_int, 909); -pub const OBJ_id_camellia256_wrap = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 392); - _ = @as(c_long, 200011); - _ = @as(c_long, 61); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - _ = @as(c_long, 3); - break :blk @as(c_long, 4); -}; -pub const SN_anyExtendedKeyUsage = "anyExtendedKeyUsage"; -pub const LN_anyExtendedKeyUsage = "Any Extended Key Usage"; -pub const NID_anyExtendedKeyUsage = @as(c_int, 910); -pub const OBJ_anyExtendedKeyUsage = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 5); - _ = @as(c_long, 29); - _ = @as(c_long, 37); - break :blk @as(c_long, 0); -}; -pub const SN_mgf1 = "MGF1"; -pub const LN_mgf1 = "mgf1"; -pub const NID_mgf1 = @as(c_int, 911); -pub const OBJ_mgf1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_rsassaPss = "RSASSA-PSS"; -pub const LN_rsassaPss = "rsassaPss"; -pub const NID_rsassaPss = @as(c_int, 912); -pub const OBJ_rsassaPss = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 10); -}; -pub const SN_aes_128_xts = "AES-128-XTS"; -pub const LN_aes_128_xts = "aes-128-xts"; -pub const NID_aes_128_xts = @as(c_int, 913); -pub const SN_aes_256_xts = "AES-256-XTS"; -pub const LN_aes_256_xts = "aes-256-xts"; -pub const NID_aes_256_xts = @as(c_int, 914); -pub const SN_rc4_hmac_md5 = "RC4-HMAC-MD5"; -pub const LN_rc4_hmac_md5 = "rc4-hmac-md5"; -pub const NID_rc4_hmac_md5 = @as(c_int, 915); -pub const SN_aes_128_cbc_hmac_sha1 = "AES-128-CBC-HMAC-SHA1"; -pub const LN_aes_128_cbc_hmac_sha1 = "aes-128-cbc-hmac-sha1"; -pub const NID_aes_128_cbc_hmac_sha1 = @as(c_int, 916); -pub const SN_aes_192_cbc_hmac_sha1 = "AES-192-CBC-HMAC-SHA1"; -pub const LN_aes_192_cbc_hmac_sha1 = "aes-192-cbc-hmac-sha1"; -pub const NID_aes_192_cbc_hmac_sha1 = @as(c_int, 917); -pub const SN_aes_256_cbc_hmac_sha1 = "AES-256-CBC-HMAC-SHA1"; -pub const LN_aes_256_cbc_hmac_sha1 = "aes-256-cbc-hmac-sha1"; -pub const NID_aes_256_cbc_hmac_sha1 = @as(c_int, 918); -pub const SN_rsaesOaep = "RSAES-OAEP"; -pub const LN_rsaesOaep = "rsaesOaep"; -pub const NID_rsaesOaep = @as(c_int, 919); -pub const OBJ_rsaesOaep = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_dhpublicnumber = "dhpublicnumber"; -pub const LN_dhpublicnumber = "X9.42 DH"; -pub const NID_dhpublicnumber = @as(c_int, 920); -pub const OBJ_dhpublicnumber = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 10046); - _ = @as(c_long, 2); - break :blk @as(c_long, 1); -}; -pub const SN_brainpoolP160r1 = "brainpoolP160r1"; -pub const NID_brainpoolP160r1 = @as(c_int, 921); -pub const OBJ_brainpoolP160r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 1); -}; -pub const SN_brainpoolP160t1 = "brainpoolP160t1"; -pub const NID_brainpoolP160t1 = @as(c_int, 922); -pub const OBJ_brainpoolP160t1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 2); -}; -pub const SN_brainpoolP192r1 = "brainpoolP192r1"; -pub const NID_brainpoolP192r1 = @as(c_int, 923); -pub const OBJ_brainpoolP192r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 3); -}; -pub const SN_brainpoolP192t1 = "brainpoolP192t1"; -pub const NID_brainpoolP192t1 = @as(c_int, 924); -pub const OBJ_brainpoolP192t1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 4); -}; -pub const SN_brainpoolP224r1 = "brainpoolP224r1"; -pub const NID_brainpoolP224r1 = @as(c_int, 925); -pub const OBJ_brainpoolP224r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 5); -}; -pub const SN_brainpoolP224t1 = "brainpoolP224t1"; -pub const NID_brainpoolP224t1 = @as(c_int, 926); -pub const OBJ_brainpoolP224t1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 6); -}; -pub const SN_brainpoolP256r1 = "brainpoolP256r1"; -pub const NID_brainpoolP256r1 = @as(c_int, 927); -pub const OBJ_brainpoolP256r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 7); -}; -pub const SN_brainpoolP256t1 = "brainpoolP256t1"; -pub const NID_brainpoolP256t1 = @as(c_int, 928); -pub const OBJ_brainpoolP256t1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 8); -}; -pub const SN_brainpoolP320r1 = "brainpoolP320r1"; -pub const NID_brainpoolP320r1 = @as(c_int, 929); -pub const OBJ_brainpoolP320r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 9); -}; -pub const SN_brainpoolP320t1 = "brainpoolP320t1"; -pub const NID_brainpoolP320t1 = @as(c_int, 930); -pub const OBJ_brainpoolP320t1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 10); -}; -pub const SN_brainpoolP384r1 = "brainpoolP384r1"; -pub const NID_brainpoolP384r1 = @as(c_int, 931); -pub const OBJ_brainpoolP384r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 11); -}; -pub const SN_brainpoolP384t1 = "brainpoolP384t1"; -pub const NID_brainpoolP384t1 = @as(c_int, 932); -pub const OBJ_brainpoolP384t1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 12); -}; -pub const SN_brainpoolP512r1 = "brainpoolP512r1"; -pub const NID_brainpoolP512r1 = @as(c_int, 933); -pub const OBJ_brainpoolP512r1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 13); -}; -pub const SN_brainpoolP512t1 = "brainpoolP512t1"; -pub const NID_brainpoolP512t1 = @as(c_int, 934); -pub const OBJ_brainpoolP512t1 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 36); - _ = @as(c_long, 3); - _ = @as(c_long, 3); - _ = @as(c_long, 2); - _ = @as(c_long, 8); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 14); -}; -pub const SN_pSpecified = "PSPECIFIED"; -pub const LN_pSpecified = "pSpecified"; -pub const NID_pSpecified = @as(c_int, 935); -pub const OBJ_pSpecified = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 2); - _ = @as(c_long, 840); - _ = @as(c_long, 113549); - _ = @as(c_long, 1); - _ = @as(c_long, 1); - break :blk @as(c_long, 9); -}; -pub const SN_dhSinglePass_stdDH_sha1kdf_scheme = "dhSinglePass-stdDH-sha1kdf-scheme"; -pub const NID_dhSinglePass_stdDH_sha1kdf_scheme = @as(c_int, 936); -pub const OBJ_dhSinglePass_stdDH_sha1kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 133); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 63); - _ = @as(c_long, 0); - break :blk @as(c_long, 2); -}; -pub const SN_dhSinglePass_stdDH_sha224kdf_scheme = "dhSinglePass-stdDH-sha224kdf-scheme"; -pub const NID_dhSinglePass_stdDH_sha224kdf_scheme = @as(c_int, 937); -pub const OBJ_dhSinglePass_stdDH_sha224kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 11); - break :blk @as(c_long, 0); -}; -pub const SN_dhSinglePass_stdDH_sha256kdf_scheme = "dhSinglePass-stdDH-sha256kdf-scheme"; -pub const NID_dhSinglePass_stdDH_sha256kdf_scheme = @as(c_int, 938); -pub const OBJ_dhSinglePass_stdDH_sha256kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 11); - break :blk @as(c_long, 1); -}; -pub const SN_dhSinglePass_stdDH_sha384kdf_scheme = "dhSinglePass-stdDH-sha384kdf-scheme"; -pub const NID_dhSinglePass_stdDH_sha384kdf_scheme = @as(c_int, 939); -pub const OBJ_dhSinglePass_stdDH_sha384kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 11); - break :blk @as(c_long, 2); -}; -pub const SN_dhSinglePass_stdDH_sha512kdf_scheme = "dhSinglePass-stdDH-sha512kdf-scheme"; -pub const NID_dhSinglePass_stdDH_sha512kdf_scheme = @as(c_int, 940); -pub const OBJ_dhSinglePass_stdDH_sha512kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 11); - break :blk @as(c_long, 3); -}; -pub const SN_dhSinglePass_cofactorDH_sha1kdf_scheme = "dhSinglePass-cofactorDH-sha1kdf-scheme"; -pub const NID_dhSinglePass_cofactorDH_sha1kdf_scheme = @as(c_int, 941); -pub const OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 133); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 63); - _ = @as(c_long, 0); - break :blk @as(c_long, 3); -}; -pub const SN_dhSinglePass_cofactorDH_sha224kdf_scheme = "dhSinglePass-cofactorDH-sha224kdf-scheme"; -pub const NID_dhSinglePass_cofactorDH_sha224kdf_scheme = @as(c_int, 942); -pub const OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 14); - break :blk @as(c_long, 0); -}; -pub const SN_dhSinglePass_cofactorDH_sha256kdf_scheme = "dhSinglePass-cofactorDH-sha256kdf-scheme"; -pub const NID_dhSinglePass_cofactorDH_sha256kdf_scheme = @as(c_int, 943); -pub const OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 14); - break :blk @as(c_long, 1); -}; -pub const SN_dhSinglePass_cofactorDH_sha384kdf_scheme = "dhSinglePass-cofactorDH-sha384kdf-scheme"; -pub const NID_dhSinglePass_cofactorDH_sha384kdf_scheme = @as(c_int, 944); -pub const OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 14); - break :blk @as(c_long, 2); -}; -pub const SN_dhSinglePass_cofactorDH_sha512kdf_scheme = "dhSinglePass-cofactorDH-sha512kdf-scheme"; -pub const NID_dhSinglePass_cofactorDH_sha512kdf_scheme = @as(c_int, 945); -pub const OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 132); - _ = @as(c_long, 1); - _ = @as(c_long, 14); - break :blk @as(c_long, 3); -}; -pub const SN_dh_std_kdf = "dh-std-kdf"; -pub const NID_dh_std_kdf = @as(c_int, 946); -pub const SN_dh_cofactor_kdf = "dh-cofactor-kdf"; -pub const NID_dh_cofactor_kdf = @as(c_int, 947); -pub const SN_X25519 = "X25519"; -pub const NID_X25519 = @as(c_int, 948); -pub const OBJ_X25519 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 101); - break :blk @as(c_long, 110); -}; -pub const SN_ED25519 = "ED25519"; -pub const NID_ED25519 = @as(c_int, 949); -pub const OBJ_ED25519 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 101); - break :blk @as(c_long, 112); -}; -pub const SN_chacha20_poly1305 = "ChaCha20-Poly1305"; -pub const LN_chacha20_poly1305 = "chacha20-poly1305"; -pub const NID_chacha20_poly1305 = @as(c_int, 950); -pub const SN_kx_rsa = "KxRSA"; -pub const LN_kx_rsa = "kx-rsa"; -pub const NID_kx_rsa = @as(c_int, 951); -pub const SN_kx_ecdhe = "KxECDHE"; -pub const LN_kx_ecdhe = "kx-ecdhe"; -pub const NID_kx_ecdhe = @as(c_int, 952); -pub const SN_kx_psk = "KxPSK"; -pub const LN_kx_psk = "kx-psk"; -pub const NID_kx_psk = @as(c_int, 953); -pub const SN_auth_rsa = "AuthRSA"; -pub const LN_auth_rsa = "auth-rsa"; -pub const NID_auth_rsa = @as(c_int, 954); -pub const SN_auth_ecdsa = "AuthECDSA"; -pub const LN_auth_ecdsa = "auth-ecdsa"; -pub const NID_auth_ecdsa = @as(c_int, 955); -pub const SN_auth_psk = "AuthPSK"; -pub const LN_auth_psk = "auth-psk"; -pub const NID_auth_psk = @as(c_int, 956); -pub const SN_kx_any = "KxANY"; -pub const LN_kx_any = "kx-any"; -pub const NID_kx_any = @as(c_int, 957); -pub const SN_auth_any = "AuthANY"; -pub const LN_auth_any = "auth-any"; -pub const NID_auth_any = @as(c_int, 958); -pub const SN_CECPQ2 = "CECPQ2"; -pub const NID_CECPQ2 = @as(c_int, 959); -pub const SN_ED448 = "ED448"; -pub const NID_ED448 = @as(c_int, 960); -pub const OBJ_ED448 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 101); - break :blk @as(c_long, 113); -}; -pub const SN_X448 = "X448"; -pub const NID_X448 = @as(c_int, 961); -pub const OBJ_X448 = blk: { - _ = @as(c_long, 1); - _ = @as(c_long, 3); - _ = @as(c_long, 101); - break :blk @as(c_long, 111); -}; -pub const SN_sha512_256 = "SHA512-256"; -pub const LN_sha512_256 = "sha512-256"; -pub const NID_sha512_256 = @as(c_int, 962); -pub const OBJ_sha512_256 = blk: { - _ = @as(c_long, 2); - _ = @as(c_long, 16); - _ = @as(c_long, 840); - _ = @as(c_long, 1); - _ = @as(c_long, 101); - _ = @as(c_long, 3); - _ = @as(c_long, 4); - _ = @as(c_long, 2); - break :blk @as(c_long, 6); -}; -pub const SN_hkdf = "HKDF"; -pub const LN_hkdf = "hkdf"; -pub const NID_hkdf = @as(c_int, 963); -pub const EVP_PKEY_NONE = NID_undef; -pub const EVP_PKEY_RSA = NID_rsaEncryption; -pub const EVP_PKEY_RSA_PSS = NID_rsassaPss; -pub const EVP_PKEY_DSA = NID_dsa; -pub const EVP_PKEY_EC = NID_X9_62_id_ecPublicKey; -pub const EVP_PKEY_ED25519 = NID_ED25519; -pub const EVP_PKEY_X25519 = NID_X25519; -pub const EVP_PKEY_HKDF = NID_hkdf; -pub const EVP_PKEY_DH = NID_dhKeyAgreement; -pub const EVP_PKEY_RSA2 = NID_rsa; -pub const EVP_PKEY_X448 = NID_X448; -pub const EVP_PKEY_ED448 = NID_ED448; -pub const OPENSSL_HEADER_PKCS7_H = ""; -pub const PKCS7_DETACHED = @as(c_int, 0x40); -pub const PKCS7_TEXT = @as(c_int, 0x1); -pub const PKCS7_NOCERTS = @as(c_int, 0x2); -pub const PKCS7_NOSIGS = @as(c_int, 0x4); -pub const PKCS7_NOCHAIN = @as(c_int, 0x8); -pub const PKCS7_NOINTERN = @as(c_int, 0x10); -pub const PKCS7_NOVERIFY = @as(c_int, 0x20); -pub const PKCS7_BINARY = @as(c_int, 0x80); -pub const PKCS7_NOATTR = @as(c_int, 0x100); -pub const PKCS7_NOSMIMECAP = @as(c_int, 0x200); -pub const PKCS7_STREAM = @as(c_int, 0x1000); -pub const PKCS7_PARTIAL = @as(c_int, 0x4000); -pub const PKCS7_R_BAD_PKCS7_VERSION = @as(c_int, 100); -pub const PKCS7_R_NOT_PKCS7_SIGNED_DATA = @as(c_int, 101); -pub const PKCS7_R_NO_CERTIFICATES_INCLUDED = @as(c_int, 102); -pub const PKCS7_R_NO_CRLS_INCLUDED = @as(c_int, 103); -pub const HEADER_X509_H = ""; -pub const HEADER_ASN1_H = ""; -pub const OPENSSL_HEADER_BN_H = ""; -pub const __CLANG_INTTYPES_H = ""; -pub const _INTTYPES_H_ = ""; -pub const __PRI_8_LENGTH_MODIFIER__ = "hh"; -pub const __PRI_64_LENGTH_MODIFIER__ = "ll"; -pub const __SCN_64_LENGTH_MODIFIER__ = "ll"; -pub const __PRI_MAX_LENGTH_MODIFIER__ = "j"; -pub const __SCN_MAX_LENGTH_MODIFIER__ = "j"; -pub const PRId8 = __PRI_8_LENGTH_MODIFIER__ ++ "d"; -pub const PRIi8 = __PRI_8_LENGTH_MODIFIER__ ++ "i"; -pub const PRIo8 = __PRI_8_LENGTH_MODIFIER__ ++ "o"; -pub const PRIu8 = __PRI_8_LENGTH_MODIFIER__ ++ "u"; -pub const PRIx8 = __PRI_8_LENGTH_MODIFIER__ ++ "x"; -pub const PRIX8 = __PRI_8_LENGTH_MODIFIER__ ++ "X"; -pub const PRId16 = "hd"; -pub const PRIi16 = "hi"; -pub const PRIo16 = "ho"; -pub const PRIu16 = "hu"; -pub const PRIx16 = "hx"; -pub const PRIX16 = "hX"; -pub const PRId32 = "d"; -pub const PRIi32 = "i"; -pub const PRIo32 = "o"; -pub const PRIu32 = "u"; -pub const PRIx32 = "x"; -pub const PRIX32 = "X"; -pub const PRId64 = __PRI_64_LENGTH_MODIFIER__ ++ "d"; -pub const PRIi64 = __PRI_64_LENGTH_MODIFIER__ ++ "i"; -pub const PRIo64 = __PRI_64_LENGTH_MODIFIER__ ++ "o"; -pub const PRIu64 = __PRI_64_LENGTH_MODIFIER__ ++ "u"; -pub const PRIx64 = __PRI_64_LENGTH_MODIFIER__ ++ "x"; -pub const PRIX64 = __PRI_64_LENGTH_MODIFIER__ ++ "X"; -pub const PRIdLEAST8 = PRId8; -pub const PRIiLEAST8 = PRIi8; -pub const PRIoLEAST8 = PRIo8; -pub const PRIuLEAST8 = PRIu8; -pub const PRIxLEAST8 = PRIx8; -pub const PRIXLEAST8 = PRIX8; -pub const PRIdLEAST16 = PRId16; -pub const PRIiLEAST16 = PRIi16; -pub const PRIoLEAST16 = PRIo16; -pub const PRIuLEAST16 = PRIu16; -pub const PRIxLEAST16 = PRIx16; -pub const PRIXLEAST16 = PRIX16; -pub const PRIdLEAST32 = PRId32; -pub const PRIiLEAST32 = PRIi32; -pub const PRIoLEAST32 = PRIo32; -pub const PRIuLEAST32 = PRIu32; -pub const PRIxLEAST32 = PRIx32; -pub const PRIXLEAST32 = PRIX32; -pub const PRIdLEAST64 = PRId64; -pub const PRIiLEAST64 = PRIi64; -pub const PRIoLEAST64 = PRIo64; -pub const PRIuLEAST64 = PRIu64; -pub const PRIxLEAST64 = PRIx64; -pub const PRIXLEAST64 = PRIX64; -pub const PRIdFAST8 = PRId8; -pub const PRIiFAST8 = PRIi8; -pub const PRIoFAST8 = PRIo8; -pub const PRIuFAST8 = PRIu8; -pub const PRIxFAST8 = PRIx8; -pub const PRIXFAST8 = PRIX8; -pub const PRIdFAST16 = PRId16; -pub const PRIiFAST16 = PRIi16; -pub const PRIoFAST16 = PRIo16; -pub const PRIuFAST16 = PRIu16; -pub const PRIxFAST16 = PRIx16; -pub const PRIXFAST16 = PRIX16; -pub const PRIdFAST32 = PRId32; -pub const PRIiFAST32 = PRIi32; -pub const PRIoFAST32 = PRIo32; -pub const PRIuFAST32 = PRIu32; -pub const PRIxFAST32 = PRIx32; -pub const PRIXFAST32 = PRIX32; -pub const PRIdFAST64 = PRId64; -pub const PRIiFAST64 = PRIi64; -pub const PRIoFAST64 = PRIo64; -pub const PRIuFAST64 = PRIu64; -pub const PRIxFAST64 = PRIx64; -pub const PRIXFAST64 = PRIX64; -pub const PRIdPTR = "ld"; -pub const PRIiPTR = "li"; -pub const PRIoPTR = "lo"; -pub const PRIuPTR = "lu"; -pub const PRIxPTR = "lx"; -pub const PRIXPTR = "lX"; -pub const PRIdMAX = __PRI_MAX_LENGTH_MODIFIER__ ++ "d"; -pub const PRIiMAX = __PRI_MAX_LENGTH_MODIFIER__ ++ "i"; -pub const PRIoMAX = __PRI_MAX_LENGTH_MODIFIER__ ++ "o"; -pub const PRIuMAX = __PRI_MAX_LENGTH_MODIFIER__ ++ "u"; -pub const PRIxMAX = __PRI_MAX_LENGTH_MODIFIER__ ++ "x"; -pub const PRIXMAX = __PRI_MAX_LENGTH_MODIFIER__ ++ "X"; -pub const SCNd8 = __PRI_8_LENGTH_MODIFIER__ ++ "d"; -pub const SCNi8 = __PRI_8_LENGTH_MODIFIER__ ++ "i"; -pub const SCNo8 = __PRI_8_LENGTH_MODIFIER__ ++ "o"; -pub const SCNu8 = __PRI_8_LENGTH_MODIFIER__ ++ "u"; -pub const SCNx8 = __PRI_8_LENGTH_MODIFIER__ ++ "x"; -pub const SCNd16 = "hd"; -pub const SCNi16 = "hi"; -pub const SCNo16 = "ho"; -pub const SCNu16 = "hu"; -pub const SCNx16 = "hx"; -pub const SCNd32 = "d"; -pub const SCNi32 = "i"; -pub const SCNo32 = "o"; -pub const SCNu32 = "u"; -pub const SCNx32 = "x"; -pub const SCNd64 = __SCN_64_LENGTH_MODIFIER__ ++ "d"; -pub const SCNi64 = __SCN_64_LENGTH_MODIFIER__ ++ "i"; -pub const SCNo64 = __SCN_64_LENGTH_MODIFIER__ ++ "o"; -pub const SCNu64 = __SCN_64_LENGTH_MODIFIER__ ++ "u"; -pub const SCNx64 = __SCN_64_LENGTH_MODIFIER__ ++ "x"; -pub const SCNdLEAST8 = SCNd8; -pub const SCNiLEAST8 = SCNi8; -pub const SCNoLEAST8 = SCNo8; -pub const SCNuLEAST8 = SCNu8; -pub const SCNxLEAST8 = SCNx8; -pub const SCNdLEAST16 = SCNd16; -pub const SCNiLEAST16 = SCNi16; -pub const SCNoLEAST16 = SCNo16; -pub const SCNuLEAST16 = SCNu16; -pub const SCNxLEAST16 = SCNx16; -pub const SCNdLEAST32 = SCNd32; -pub const SCNiLEAST32 = SCNi32; -pub const SCNoLEAST32 = SCNo32; -pub const SCNuLEAST32 = SCNu32; -pub const SCNxLEAST32 = SCNx32; -pub const SCNdLEAST64 = SCNd64; -pub const SCNiLEAST64 = SCNi64; -pub const SCNoLEAST64 = SCNo64; -pub const SCNuLEAST64 = SCNu64; -pub const SCNxLEAST64 = SCNx64; -pub const SCNdFAST8 = SCNd8; -pub const SCNiFAST8 = SCNi8; -pub const SCNoFAST8 = SCNo8; -pub const SCNuFAST8 = SCNu8; -pub const SCNxFAST8 = SCNx8; -pub const SCNdFAST16 = SCNd16; -pub const SCNiFAST16 = SCNi16; -pub const SCNoFAST16 = SCNo16; -pub const SCNuFAST16 = SCNu16; -pub const SCNxFAST16 = SCNx16; -pub const SCNdFAST32 = SCNd32; -pub const SCNiFAST32 = SCNi32; -pub const SCNoFAST32 = SCNo32; -pub const SCNuFAST32 = SCNu32; -pub const SCNxFAST32 = SCNx32; -pub const SCNdFAST64 = SCNd64; -pub const SCNiFAST64 = SCNi64; -pub const SCNoFAST64 = SCNo64; -pub const SCNuFAST64 = SCNu64; -pub const SCNxFAST64 = SCNx64; -pub const SCNdPTR = "ld"; -pub const SCNiPTR = "li"; -pub const SCNoPTR = "lo"; -pub const SCNuPTR = "lu"; -pub const SCNxPTR = "lx"; -pub const SCNdMAX = __SCN_MAX_LENGTH_MODIFIER__ ++ "d"; -pub const SCNiMAX = __SCN_MAX_LENGTH_MODIFIER__ ++ "i"; -pub const SCNoMAX = __SCN_MAX_LENGTH_MODIFIER__ ++ "o"; -pub const SCNuMAX = __SCN_MAX_LENGTH_MODIFIER__ ++ "u"; -pub const SCNxMAX = __SCN_MAX_LENGTH_MODIFIER__ ++ "x"; -pub const BN_BITS2 = @as(c_int, 64); -pub const BN_DEC_FMT1 = "%" ++ PRIu64; -pub const BN_DEC_FMT2 = "%019" ++ PRIu64; -pub const BN_HEX_FMT1 = "%" ++ PRIx64; -pub const BN_HEX_FMT2 = "%016" ++ PRIx64; -pub inline fn BN_mod(rem: anytype, numerator: anytype, divisor: anytype, ctx: anytype) @TypeOf(BN_div(NULL, rem, numerator, divisor, ctx)) { - return BN_div(NULL, rem, numerator, divisor, ctx); -} -pub const BN_RAND_TOP_ANY = -@as(c_int, 1); -pub const BN_RAND_TOP_ONE = @as(c_int, 0); -pub const BN_RAND_TOP_TWO = @as(c_int, 1); -pub const BN_RAND_BOTTOM_ANY = @as(c_int, 0); -pub const BN_RAND_BOTTOM_ODD = @as(c_int, 1); -pub const BN_GENCB_GENERATED = @as(c_int, 0); -pub const BN_GENCB_PRIME_TEST = @as(c_int, 1); -pub const BN_prime_checks_for_validation = @as(c_int, 64); -pub const BN_prime_checks_for_generation = @as(c_int, 0); -pub const BN_prime_checks = BN_prime_checks_for_validation; -pub const BN_FLG_MALLOCED = @as(c_int, 0x01); -pub const BN_FLG_STATIC_DATA = @as(c_int, 0x02); -pub const BN_R_ARG2_LT_ARG3 = @as(c_int, 100); -pub const BN_R_BAD_RECIPROCAL = @as(c_int, 101); -pub const BN_R_BIGNUM_TOO_LONG = @as(c_int, 102); -pub const BN_R_BITS_TOO_SMALL = @as(c_int, 103); -pub const BN_R_CALLED_WITH_EVEN_MODULUS = @as(c_int, 104); -pub const BN_R_DIV_BY_ZERO = @as(c_int, 105); -pub const BN_R_EXPAND_ON_STATIC_BIGNUM_DATA = @as(c_int, 106); -pub const BN_R_INPUT_NOT_REDUCED = @as(c_int, 107); -pub const BN_R_INVALID_RANGE = @as(c_int, 108); -pub const BN_R_NEGATIVE_NUMBER = @as(c_int, 109); -pub const BN_R_NOT_A_SQUARE = @as(c_int, 110); -pub const BN_R_NOT_INITIALIZED = @as(c_int, 111); -pub const BN_R_NO_INVERSE = @as(c_int, 112); -pub const BN_R_PRIVATE_KEY_TOO_LARGE = @as(c_int, 113); -pub const BN_R_P_IS_NOT_PRIME = @as(c_int, 114); -pub const BN_R_TOO_MANY_ITERATIONS = @as(c_int, 115); -pub const BN_R_TOO_MANY_TEMPORARY_VARIABLES = @as(c_int, 116); -pub const BN_R_BAD_ENCODING = @as(c_int, 117); -pub const BN_R_ENCODE_ERROR = @as(c_int, 118); -pub const BN_R_INVALID_INPUT = @as(c_int, 119); -pub const V_ASN1_UNIVERSAL = @as(c_int, 0x00); -pub const V_ASN1_APPLICATION = @as(c_int, 0x40); -pub const V_ASN1_CONTEXT_SPECIFIC = @as(c_int, 0x80); -pub const V_ASN1_PRIVATE = @as(c_int, 0xc0); -pub const V_ASN1_CONSTRUCTED = @as(c_int, 0x20); -pub const V_ASN1_PRIMITIVE_TAG = @as(c_int, 0x1f); -pub const V_ASN1_MAX_UNIVERSAL = @as(c_int, 0xff); -pub const V_ASN1_UNDEF = -@as(c_int, 1); -pub const V_ASN1_OTHER = -@as(c_int, 3); -pub const V_ASN1_ANY = -@as(c_int, 4); -pub const V_ASN1_EOC = @as(c_int, 0); -pub const V_ASN1_BOOLEAN = @as(c_int, 1); -pub const V_ASN1_INTEGER = @as(c_int, 2); -pub const V_ASN1_BIT_STRING = @as(c_int, 3); -pub const V_ASN1_OCTET_STRING = @as(c_int, 4); -pub const V_ASN1_NULL = @as(c_int, 5); -pub const V_ASN1_OBJECT = @as(c_int, 6); -pub const V_ASN1_OBJECT_DESCRIPTOR = @as(c_int, 7); -pub const V_ASN1_EXTERNAL = @as(c_int, 8); -pub const V_ASN1_REAL = @as(c_int, 9); -pub const V_ASN1_ENUMERATED = @as(c_int, 10); -pub const V_ASN1_UTF8STRING = @as(c_int, 12); -pub const V_ASN1_SEQUENCE = @as(c_int, 16); -pub const V_ASN1_SET = @as(c_int, 17); -pub const V_ASN1_NUMERICSTRING = @as(c_int, 18); -pub const V_ASN1_PRINTABLESTRING = @as(c_int, 19); -pub const V_ASN1_T61STRING = @as(c_int, 20); -pub const V_ASN1_TELETEXSTRING = @as(c_int, 20); -pub const V_ASN1_VIDEOTEXSTRING = @as(c_int, 21); -pub const V_ASN1_IA5STRING = @as(c_int, 22); -pub const V_ASN1_UTCTIME = @as(c_int, 23); -pub const V_ASN1_GENERALIZEDTIME = @as(c_int, 24); -pub const V_ASN1_GRAPHICSTRING = @as(c_int, 25); -pub const V_ASN1_ISO64STRING = @as(c_int, 26); -pub const V_ASN1_VISIBLESTRING = @as(c_int, 26); -pub const V_ASN1_GENERALSTRING = @as(c_int, 27); -pub const V_ASN1_UNIVERSALSTRING = @as(c_int, 28); -pub const V_ASN1_BMPSTRING = @as(c_int, 30); -pub const V_ASN1_NEG = @as(c_int, 0x100); -pub const V_ASN1_NEG_INTEGER = V_ASN1_INTEGER | V_ASN1_NEG; -pub const V_ASN1_NEG_ENUMERATED = V_ASN1_ENUMERATED | V_ASN1_NEG; -pub const B_ASN1_NUMERICSTRING = @as(c_int, 0x0001); -pub const B_ASN1_PRINTABLESTRING = @as(c_int, 0x0002); -pub const B_ASN1_T61STRING = @as(c_int, 0x0004); -pub const B_ASN1_TELETEXSTRING = @as(c_int, 0x0004); -pub const B_ASN1_VIDEOTEXSTRING = @as(c_int, 0x0008); -pub const B_ASN1_IA5STRING = @as(c_int, 0x0010); -pub const B_ASN1_GRAPHICSTRING = @as(c_int, 0x0020); -pub const B_ASN1_ISO64STRING = @as(c_int, 0x0040); -pub const B_ASN1_VISIBLESTRING = @as(c_int, 0x0040); -pub const B_ASN1_GENERALSTRING = @as(c_int, 0x0080); -pub const B_ASN1_UNIVERSALSTRING = @as(c_int, 0x0100); -pub const B_ASN1_OCTET_STRING = @as(c_int, 0x0200); -pub const B_ASN1_BIT_STRING = @as(c_int, 0x0400); -pub const B_ASN1_BMPSTRING = @as(c_int, 0x0800); -pub const B_ASN1_UNKNOWN = @as(c_int, 0x1000); -pub const B_ASN1_UTF8STRING = @as(c_int, 0x2000); -pub const B_ASN1_UTCTIME = @as(c_int, 0x4000); -pub const B_ASN1_GENERALIZEDTIME = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex); -pub const B_ASN1_SEQUENCE = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x10000, .hex); -pub inline fn ASN1_ITEM_ptr(iptr: anytype) @TypeOf(iptr) { - return iptr; -} -pub const ASN1_STRING_FLAG_BITS_LEFT = @as(c_int, 0x08); -pub const MBSTRING_FLAG = @as(c_int, 0x1000); -pub const MBSTRING_UTF8 = MBSTRING_FLAG; -pub const MBSTRING_ASC = MBSTRING_FLAG | @as(c_int, 1); -pub const MBSTRING_BMP = MBSTRING_FLAG | @as(c_int, 2); -pub const MBSTRING_UNIV = MBSTRING_FLAG | @as(c_int, 4); -pub const DIRSTRING_TYPE = ((B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING) | B_ASN1_BMPSTRING) | B_ASN1_UTF8STRING; -pub const PKCS9STRING_TYPE = DIRSTRING_TYPE | B_ASN1_IA5STRING; -pub const STABLE_NO_MASK = @as(c_int, 0x02); -pub const B_ASN1_DIRECTORYSTRING = (((B_ASN1_PRINTABLESTRING | B_ASN1_TELETEXSTRING) | B_ASN1_BMPSTRING) | B_ASN1_UNIVERSALSTRING) | B_ASN1_UTF8STRING; -pub const B_ASN1_DISPLAYTEXT = ((B_ASN1_IA5STRING | B_ASN1_VISIBLESTRING) | B_ASN1_BMPSTRING) | B_ASN1_UTF8STRING; -pub const B_ASN1_TIME = B_ASN1_UTCTIME | B_ASN1_GENERALIZEDTIME; -pub const ASN1_STRFLGS_ESC_2253 = @as(c_int, 1); -pub const ASN1_STRFLGS_ESC_CTRL = @as(c_int, 2); -pub const ASN1_STRFLGS_ESC_MSB = @as(c_int, 4); -pub const ASN1_STRFLGS_ESC_QUOTE = @as(c_int, 8); -pub const ASN1_STRFLGS_UTF8_CONVERT = @as(c_int, 0x10); -pub const ASN1_STRFLGS_IGNORE_TYPE = @as(c_int, 0x20); -pub const ASN1_STRFLGS_SHOW_TYPE = @as(c_int, 0x40); -pub const ASN1_STRFLGS_DUMP_ALL = @as(c_int, 0x80); -pub const ASN1_STRFLGS_DUMP_UNKNOWN = @as(c_int, 0x100); -pub const ASN1_STRFLGS_DUMP_DER = @as(c_int, 0x200); -pub const ASN1_STRFLGS_RFC2253 = ((((ASN1_STRFLGS_ESC_2253 | ASN1_STRFLGS_ESC_CTRL) | ASN1_STRFLGS_ESC_MSB) | ASN1_STRFLGS_UTF8_CONVERT) | ASN1_STRFLGS_DUMP_UNKNOWN) | ASN1_STRFLGS_DUMP_DER; -pub inline fn DECLARE_ASN1_FUNCTIONS(@"type": anytype) @TypeOf(DECLARE_ASN1_FUNCTIONS_name(@"type", @"type")) { - return DECLARE_ASN1_FUNCTIONS_name(@"type", @"type"); -} -pub inline fn DECLARE_ASN1_ALLOC_FUNCTIONS(@"type": anytype) @TypeOf(DECLARE_ASN1_ALLOC_FUNCTIONS_name(@"type", @"type")) { - return DECLARE_ASN1_ALLOC_FUNCTIONS_name(@"type", @"type"); -} -pub inline fn M_ASN1_STRING_length(x: anytype) @TypeOf(ASN1_STRING_length(x)) { - return ASN1_STRING_length(x); -} -pub inline fn M_ASN1_STRING_type(x: anytype) @TypeOf(ASN1_STRING_type(x)) { - return ASN1_STRING_type(x); -} -pub inline fn M_ASN1_STRING_data(x: anytype) @TypeOf(ASN1_STRING_data(x)) { - return ASN1_STRING_data(x); -} -pub inline fn M_ASN1_BIT_STRING_new() @TypeOf(ASN1_BIT_STRING_new()) { - return ASN1_BIT_STRING_new(); -} -pub inline fn M_ASN1_BIT_STRING_free(a: anytype) @TypeOf(ASN1_BIT_STRING_free(a)) { - return ASN1_BIT_STRING_free(a); -} -pub inline fn M_ASN1_BIT_STRING_dup(a: anytype) @TypeOf(ASN1_STRING_dup(a)) { - return ASN1_STRING_dup(a); -} -pub inline fn M_ASN1_BIT_STRING_cmp(a: anytype, b: anytype) @TypeOf(ASN1_STRING_cmp(a, b)) { - return ASN1_STRING_cmp(a, b); -} -// pub inline fn M_ASN1_BIT_STRING_set(a: anytype, b: anytype, c: anytype) @TypeOf(ASN1_BIT_STRING_set(a, b, c)) { -// return ASN1_BIT_STRING_set(a, b, c); -// } -pub inline fn M_ASN1_INTEGER_new() @TypeOf(ASN1_INTEGER_new()) { - return ASN1_INTEGER_new(); -} -pub inline fn M_ASN1_INTEGER_free(a: anytype) @TypeOf(ASN1_INTEGER_free(a)) { - return ASN1_INTEGER_free(a); -} -pub inline fn M_ASN1_INTEGER_dup(a: anytype) @TypeOf(ASN1_INTEGER_dup(a)) { - return ASN1_INTEGER_dup(a); -} -pub inline fn M_ASN1_INTEGER_cmp(a: anytype, b: anytype) @TypeOf(ASN1_INTEGER_cmp(a, b)) { - return ASN1_INTEGER_cmp(a, b); -} -pub inline fn M_ASN1_ENUMERATED_new() @TypeOf(ASN1_ENUMERATED_new()) { - return ASN1_ENUMERATED_new(); -} -pub inline fn M_ASN1_ENUMERATED_free(a: anytype) @TypeOf(ASN1_ENUMERATED_free(a)) { - return ASN1_ENUMERATED_free(a); -} -pub inline fn M_ASN1_ENUMERATED_dup(a: anytype) @TypeOf(ASN1_STRING_dup(a)) { - return ASN1_STRING_dup(a); -} -pub inline fn M_ASN1_ENUMERATED_cmp(a: anytype, b: anytype) @TypeOf(ASN1_STRING_cmp(a, b)) { - return ASN1_STRING_cmp(a, b); -} -pub inline fn M_ASN1_OCTET_STRING_new() @TypeOf(ASN1_OCTET_STRING_new()) { - return ASN1_OCTET_STRING_new(); -} -pub inline fn M_ASN1_OCTET_STRING_free(a: anytype) @TypeOf(ASN1_OCTET_STRING_free()) { - _ = @TypeOf(a); - return ASN1_OCTET_STRING_free(); -} -pub inline fn M_ASN1_OCTET_STRING_dup(a: anytype) @TypeOf(ASN1_OCTET_STRING_dup(a)) { - return ASN1_OCTET_STRING_dup(a); -} -pub inline fn M_ASN1_OCTET_STRING_cmp(a: anytype, b: anytype) @TypeOf(ASN1_OCTET_STRING_cmp(a, b)) { - return ASN1_OCTET_STRING_cmp(a, b); -} -pub inline fn M_ASN1_OCTET_STRING_set(a: anytype, b: anytype, c: anytype) @TypeOf(ASN1_OCTET_STRING_set(a, b, c)) { - return ASN1_OCTET_STRING_set(a, b, c); -} -pub inline fn M_ASN1_OCTET_STRING_print(a: anytype, b: anytype) @TypeOf(ASN1_STRING_print(a, b)) { - return ASN1_STRING_print(a, b); -} -pub inline fn M_ASN1_PRINTABLESTRING_new() @TypeOf(ASN1_PRINTABLESTRING_new()) { - return ASN1_PRINTABLESTRING_new(); -} -pub inline fn M_ASN1_PRINTABLESTRING_free(a: anytype) @TypeOf(ASN1_PRINTABLESTRING_free(a)) { - return ASN1_PRINTABLESTRING_free(a); -} -pub inline fn M_ASN1_IA5STRING_new() @TypeOf(ASN1_IA5STRING_new()) { - return ASN1_IA5STRING_new(); -} -pub inline fn M_ASN1_IA5STRING_free(a: anytype) @TypeOf(ASN1_IA5STRING_free(a)) { - return ASN1_IA5STRING_free(a); -} -pub inline fn M_ASN1_IA5STRING_dup(a: anytype) @TypeOf(ASN1_STRING_dup(a)) { - return ASN1_STRING_dup(a); -} -pub inline fn M_ASN1_UTCTIME_new() @TypeOf(ASN1_UTCTIME_new()) { - return ASN1_UTCTIME_new(); -} -pub inline fn M_ASN1_UTCTIME_free(a: anytype) @TypeOf(ASN1_UTCTIME_free(a)) { - return ASN1_UTCTIME_free(a); -} -pub inline fn M_ASN1_UTCTIME_dup(a: anytype) @TypeOf(ASN1_STRING_dup(a)) { - return ASN1_STRING_dup(a); -} -pub inline fn M_ASN1_T61STRING_new() @TypeOf(ASN1_T61STRING_new()) { - return ASN1_T61STRING_new(); -} -pub inline fn M_ASN1_T61STRING_free(a: anytype) @TypeOf(ASN1_T61STRING_free(a)) { - return ASN1_T61STRING_free(a); -} -pub inline fn M_ASN1_GENERALIZEDTIME_new() @TypeOf(ASN1_GENERALIZEDTIME_new()) { - return ASN1_GENERALIZEDTIME_new(); -} -pub inline fn M_ASN1_GENERALIZEDTIME_free(a: anytype) @TypeOf(ASN1_GENERALIZEDTIME_free(a)) { - return ASN1_GENERALIZEDTIME_free(a); -} -pub inline fn M_ASN1_GENERALIZEDTIME_dup(a: anytype) @TypeOf(ASN1_STRING_dup(a)) { - return ASN1_STRING_dup(a); -} -pub inline fn M_ASN1_GENERALSTRING_new() @TypeOf(ASN1_GENERALSTRING_new()) { - return ASN1_GENERALSTRING_new(); -} -pub inline fn M_ASN1_GENERALSTRING_free(a: anytype) @TypeOf(ASN1_GENERALSTRING_free(a)) { - return ASN1_GENERALSTRING_free(a); -} -pub inline fn M_ASN1_UNIVERSALSTRING_new() @TypeOf(ASN1_UNIVERSALSTRING_new()) { - return ASN1_UNIVERSALSTRING_new(); -} -pub inline fn M_ASN1_UNIVERSALSTRING_free(a: anytype) @TypeOf(ASN1_UNIVERSALSTRING_free(a)) { - return ASN1_UNIVERSALSTRING_free(a); -} -pub inline fn M_ASN1_BMPSTRING_new() @TypeOf(ASN1_BMPSTRING_new()) { - return ASN1_BMPSTRING_new(); -} -pub inline fn M_ASN1_BMPSTRING_free(a: anytype) @TypeOf(ASN1_BMPSTRING_free(a)) { - return ASN1_BMPSTRING_free(a); -} -pub inline fn M_ASN1_VISIBLESTRING_new() @TypeOf(ASN1_VISIBLESTRING_new()) { - return ASN1_VISIBLESTRING_new(); -} -pub inline fn M_ASN1_VISIBLESTRING_free(a: anytype) @TypeOf(ASN1_VISIBLESTRING_free(a)) { - return ASN1_VISIBLESTRING_free(a); -} -pub inline fn M_ASN1_UTF8STRING_new() @TypeOf(ASN1_UTF8STRING_new()) { - return ASN1_UTF8STRING_new(); -} -pub inline fn M_ASN1_UTF8STRING_free(a: anytype) @TypeOf(ASN1_UTF8STRING_free(a)) { - return ASN1_UTF8STRING_free(a); -} -pub const B_ASN1_PRINTABLE = ((((((((B_ASN1_NUMERICSTRING | B_ASN1_PRINTABLESTRING) | B_ASN1_T61STRING) | B_ASN1_IA5STRING) | B_ASN1_BIT_STRING) | B_ASN1_UNIVERSALSTRING) | B_ASN1_BMPSTRING) | B_ASN1_UTF8STRING) | B_ASN1_SEQUENCE) | B_ASN1_UNKNOWN; -pub const ASN1_R_ASN1_LENGTH_MISMATCH = @as(c_int, 100); -pub const ASN1_R_AUX_ERROR = @as(c_int, 101); -pub const ASN1_R_BAD_GET_ASN1_OBJECT_CALL = @as(c_int, 102); -pub const ASN1_R_BAD_OBJECT_HEADER = @as(c_int, 103); -pub const ASN1_R_BMPSTRING_IS_WRONG_LENGTH = @as(c_int, 104); -pub const ASN1_R_BN_LIB = @as(c_int, 105); -pub const ASN1_R_BOOLEAN_IS_WRONG_LENGTH = @as(c_int, 106); -pub const ASN1_R_BUFFER_TOO_SMALL = @as(c_int, 107); -pub const ASN1_R_CONTEXT_NOT_INITIALISED = @as(c_int, 108); -pub const ASN1_R_DECODE_ERROR = @as(c_int, 109); -pub const ASN1_R_DEPTH_EXCEEDED = @as(c_int, 110); -pub const ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED = @as(c_int, 111); -pub const ASN1_R_ENCODE_ERROR = @as(c_int, 112); -pub const ASN1_R_ERROR_GETTING_TIME = @as(c_int, 113); -pub const ASN1_R_EXPECTING_AN_ASN1_SEQUENCE = @as(c_int, 114); -pub const ASN1_R_EXPECTING_AN_INTEGER = @as(c_int, 115); -pub const ASN1_R_EXPECTING_AN_OBJECT = @as(c_int, 116); -pub const ASN1_R_EXPECTING_A_BOOLEAN = @as(c_int, 117); -pub const ASN1_R_EXPECTING_A_TIME = @as(c_int, 118); -pub const ASN1_R_EXPLICIT_LENGTH_MISMATCH = @as(c_int, 119); -pub const ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED = @as(c_int, 120); -pub const ASN1_R_FIELD_MISSING = @as(c_int, 121); -pub const ASN1_R_FIRST_NUM_TOO_LARGE = @as(c_int, 122); -pub const ASN1_R_HEADER_TOO_LONG = @as(c_int, 123); -pub const ASN1_R_ILLEGAL_BITSTRING_FORMAT = @as(c_int, 124); -pub const ASN1_R_ILLEGAL_BOOLEAN = @as(c_int, 125); -pub const ASN1_R_ILLEGAL_CHARACTERS = @as(c_int, 126); -pub const ASN1_R_ILLEGAL_FORMAT = @as(c_int, 127); -pub const ASN1_R_ILLEGAL_HEX = @as(c_int, 128); -pub const ASN1_R_ILLEGAL_IMPLICIT_TAG = @as(c_int, 129); -pub const ASN1_R_ILLEGAL_INTEGER = @as(c_int, 130); -pub const ASN1_R_ILLEGAL_NESTED_TAGGING = @as(c_int, 131); -pub const ASN1_R_ILLEGAL_NULL = @as(c_int, 132); -pub const ASN1_R_ILLEGAL_NULL_VALUE = @as(c_int, 133); -pub const ASN1_R_ILLEGAL_OBJECT = @as(c_int, 134); -pub const ASN1_R_ILLEGAL_OPTIONAL_ANY = @as(c_int, 135); -pub const ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE = @as(c_int, 136); -pub const ASN1_R_ILLEGAL_TAGGED_ANY = @as(c_int, 137); -pub const ASN1_R_ILLEGAL_TIME_VALUE = @as(c_int, 138); -pub const ASN1_R_INTEGER_NOT_ASCII_FORMAT = @as(c_int, 139); -pub const ASN1_R_INTEGER_TOO_LARGE_FOR_LONG = @as(c_int, 140); -pub const ASN1_R_INVALID_BIT_STRING_BITS_LEFT = @as(c_int, 141); -pub const ASN1_R_INVALID_BMPSTRING = @as(c_int, 142); -pub const ASN1_R_INVALID_DIGIT = @as(c_int, 143); -pub const ASN1_R_INVALID_MODIFIER = @as(c_int, 144); -pub const ASN1_R_INVALID_NUMBER = @as(c_int, 145); -pub const ASN1_R_INVALID_OBJECT_ENCODING = @as(c_int, 146); -pub const ASN1_R_INVALID_SEPARATOR = @as(c_int, 147); -pub const ASN1_R_INVALID_TIME_FORMAT = @as(c_int, 148); -pub const ASN1_R_INVALID_UNIVERSALSTRING = @as(c_int, 149); -pub const ASN1_R_INVALID_UTF8STRING = @as(c_int, 150); -pub const ASN1_R_LIST_ERROR = @as(c_int, 151); -pub const ASN1_R_MISSING_ASN1_EOS = @as(c_int, 152); -pub const ASN1_R_MISSING_EOC = @as(c_int, 153); -pub const ASN1_R_MISSING_SECOND_NUMBER = @as(c_int, 154); -pub const ASN1_R_MISSING_VALUE = @as(c_int, 155); -pub const ASN1_R_MSTRING_NOT_UNIVERSAL = @as(c_int, 156); -pub const ASN1_R_MSTRING_WRONG_TAG = @as(c_int, 157); -pub const ASN1_R_NESTED_ASN1_ERROR = @as(c_int, 158); -pub const ASN1_R_NESTED_ASN1_STRING = @as(c_int, 159); -pub const ASN1_R_NON_HEX_CHARACTERS = @as(c_int, 160); -pub const ASN1_R_NOT_ASCII_FORMAT = @as(c_int, 161); -pub const ASN1_R_NOT_ENOUGH_DATA = @as(c_int, 162); -pub const ASN1_R_NO_MATCHING_CHOICE_TYPE = @as(c_int, 163); -pub const ASN1_R_NULL_IS_WRONG_LENGTH = @as(c_int, 164); -pub const ASN1_R_OBJECT_NOT_ASCII_FORMAT = @as(c_int, 165); -pub const ASN1_R_ODD_NUMBER_OF_CHARS = @as(c_int, 166); -pub const ASN1_R_SECOND_NUMBER_TOO_LARGE = @as(c_int, 167); -pub const ASN1_R_SEQUENCE_LENGTH_MISMATCH = @as(c_int, 168); -pub const ASN1_R_SEQUENCE_NOT_CONSTRUCTED = @as(c_int, 169); -pub const ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG = @as(c_int, 170); -pub const ASN1_R_SHORT_LINE = @as(c_int, 171); -pub const ASN1_R_STREAMING_NOT_SUPPORTED = @as(c_int, 172); -pub const ASN1_R_STRING_TOO_LONG = @as(c_int, 173); -pub const ASN1_R_STRING_TOO_SHORT = @as(c_int, 174); -pub const ASN1_R_TAG_VALUE_TOO_HIGH = @as(c_int, 175); -pub const ASN1_R_TIME_NOT_ASCII_FORMAT = @as(c_int, 176); -pub const ASN1_R_TOO_LONG = @as(c_int, 177); -pub const ASN1_R_TYPE_NOT_CONSTRUCTED = @as(c_int, 178); -pub const ASN1_R_TYPE_NOT_PRIMITIVE = @as(c_int, 179); -pub const ASN1_R_UNEXPECTED_EOC = @as(c_int, 180); -pub const ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH = @as(c_int, 181); -pub const ASN1_R_UNKNOWN_FORMAT = @as(c_int, 182); -pub const ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM = @as(c_int, 183); -pub const ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM = @as(c_int, 184); -pub const ASN1_R_UNKNOWN_TAG = @as(c_int, 185); -pub const ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE = @as(c_int, 186); -pub const ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE = @as(c_int, 187); -pub const ASN1_R_UNSUPPORTED_TYPE = @as(c_int, 188); -pub const ASN1_R_WRONG_PUBLIC_KEY_TYPE = @as(c_int, 189); -pub const ASN1_R_WRONG_TAG = @as(c_int, 190); -pub const ASN1_R_WRONG_TYPE = @as(c_int, 191); -pub const ASN1_R_NESTED_TOO_DEEP = @as(c_int, 192); -pub const ASN1_R_BAD_TEMPLATE = @as(c_int, 193); -pub const ASN1_R_INVALID_BIT_STRING_PADDING = @as(c_int, 194); -pub const ASN1_R_WRONG_INTEGER_TYPE = @as(c_int, 195); -pub const ASN1_R_INVALID_INTEGER = @as(c_int, 196); -pub const OPENSSL_HEADER_DH_H = ""; -pub const DH_GENERATOR_2 = @as(c_int, 2); -pub const DH_GENERATOR_5 = @as(c_int, 5); -pub const DH_CHECK_P_NOT_PRIME = @as(c_int, 0x01); -pub const DH_CHECK_P_NOT_SAFE_PRIME = @as(c_int, 0x02); -pub const DH_CHECK_UNABLE_TO_CHECK_GENERATOR = @as(c_int, 0x04); -pub const DH_CHECK_NOT_SUITABLE_GENERATOR = @as(c_int, 0x08); -pub const DH_CHECK_Q_NOT_PRIME = @as(c_int, 0x10); -pub const DH_CHECK_INVALID_Q_VALUE = @as(c_int, 0x20); -pub const DH_NOT_SUITABLE_GENERATOR = DH_CHECK_NOT_SUITABLE_GENERATOR; -pub const DH_UNABLE_TO_CHECK_GENERATOR = DH_CHECK_UNABLE_TO_CHECK_GENERATOR; -pub const DH_CHECK_PUBKEY_TOO_SMALL = @as(c_int, 0x1); -pub const DH_CHECK_PUBKEY_TOO_LARGE = @as(c_int, 0x2); -pub const DH_CHECK_PUBKEY_INVALID = @as(c_int, 0x4); -pub const DH_R_BAD_GENERATOR = @as(c_int, 100); -pub const DH_R_INVALID_PUBKEY = @as(c_int, 101); -pub const DH_R_MODULUS_TOO_LARGE = @as(c_int, 102); -pub const DH_R_NO_PRIVATE_VALUE = @as(c_int, 103); -pub const DH_R_DECODE_ERROR = @as(c_int, 104); -pub const DH_R_ENCODE_ERROR = @as(c_int, 105); -pub const OPENSSL_HEADER_DSA_H = ""; -pub const OPENSSL_HEADER_ENGINE_H = ""; -pub const ENGINE_R_OPERATION_NOT_SUPPORTED = @as(c_int, 100); -pub const DSA_R_BAD_Q_VALUE = @as(c_int, 100); -pub const DSA_R_MISSING_PARAMETERS = @as(c_int, 101); -pub const DSA_R_MODULUS_TOO_LARGE = @as(c_int, 102); -pub const DSA_R_NEED_NEW_SETUP_VALUES = @as(c_int, 103); -pub const DSA_R_BAD_VERSION = @as(c_int, 104); -pub const DSA_R_DECODE_ERROR = @as(c_int, 105); -pub const DSA_R_ENCODE_ERROR = @as(c_int, 106); -pub const DSA_R_INVALID_PARAMETERS = @as(c_int, 107); -pub const OPENSSL_HEADER_EC_H = ""; -pub const OPENSSL_EC_EXPLICIT_CURVE = @as(c_int, 0); -pub const OPENSSL_EC_NAMED_CURVE = @as(c_int, 1); -pub const OPENSSL_HEADER_EC_KEY_H = ""; -pub const EC_PKEY_NO_PARAMETERS = @as(c_int, 0x001); -pub const EC_PKEY_NO_PUBKEY = @as(c_int, 0x002); -pub const ECDSA_FLAG_OPAQUE = @as(c_int, 1); -pub const EC_R_BUFFER_TOO_SMALL = @as(c_int, 100); -pub const EC_R_COORDINATES_OUT_OF_RANGE = @as(c_int, 101); -pub const EC_R_D2I_ECPKPARAMETERS_FAILURE = @as(c_int, 102); -pub const EC_R_EC_GROUP_NEW_BY_NAME_FAILURE = @as(c_int, 103); -pub const EC_R_GROUP2PKPARAMETERS_FAILURE = @as(c_int, 104); -pub const EC_R_I2D_ECPKPARAMETERS_FAILURE = @as(c_int, 105); -pub const EC_R_INCOMPATIBLE_OBJECTS = @as(c_int, 106); -pub const EC_R_INVALID_COMPRESSED_POINT = @as(c_int, 107); -pub const EC_R_INVALID_COMPRESSION_BIT = @as(c_int, 108); -pub const EC_R_INVALID_ENCODING = @as(c_int, 109); -pub const EC_R_INVALID_FIELD = @as(c_int, 110); -pub const EC_R_INVALID_FORM = @as(c_int, 111); -pub const EC_R_INVALID_GROUP_ORDER = @as(c_int, 112); -pub const EC_R_INVALID_PRIVATE_KEY = @as(c_int, 113); -pub const EC_R_MISSING_PARAMETERS = @as(c_int, 114); -pub const EC_R_MISSING_PRIVATE_KEY = @as(c_int, 115); -pub const EC_R_NON_NAMED_CURVE = @as(c_int, 116); -pub const EC_R_NOT_INITIALIZED = @as(c_int, 117); -pub const EC_R_PKPARAMETERS2GROUP_FAILURE = @as(c_int, 118); -pub const EC_R_POINT_AT_INFINITY = @as(c_int, 119); -pub const EC_R_POINT_IS_NOT_ON_CURVE = @as(c_int, 120); -pub const EC_R_SLOT_FULL = @as(c_int, 121); -pub const EC_R_UNDEFINED_GENERATOR = @as(c_int, 122); -pub const EC_R_UNKNOWN_GROUP = @as(c_int, 123); -pub const EC_R_UNKNOWN_ORDER = @as(c_int, 124); -pub const EC_R_WRONG_ORDER = @as(c_int, 125); -pub const EC_R_BIGNUM_OUT_OF_RANGE = @as(c_int, 126); -pub const EC_R_WRONG_CURVE_PARAMETERS = @as(c_int, 127); -pub const EC_R_DECODE_ERROR = @as(c_int, 128); -pub const EC_R_ENCODE_ERROR = @as(c_int, 129); -pub const EC_R_GROUP_MISMATCH = @as(c_int, 130); -pub const EC_R_INVALID_COFACTOR = @as(c_int, 131); -pub const EC_R_PUBLIC_KEY_VALIDATION_FAILED = @as(c_int, 132); -pub const EC_R_INVALID_SCALAR = @as(c_int, 133); -pub const OPENSSL_HEADER_ECDH_H = ""; -pub const ECDH_R_KDF_FAILED = @as(c_int, 100); -pub const ECDH_R_NO_PRIVATE_VALUE = @as(c_int, 101); -pub const ECDH_R_POINT_ARITHMETIC_FAILURE = @as(c_int, 102); -pub const ECDH_R_UNKNOWN_DIGEST_LENGTH = @as(c_int, 103); -pub const OPENSSL_HEADER_ECDSA_H = ""; -pub const ECDSA_R_BAD_SIGNATURE = @as(c_int, 100); -pub const ECDSA_R_MISSING_PARAMETERS = @as(c_int, 101); -pub const ECDSA_R_NEED_NEW_SETUP_VALUES = @as(c_int, 102); -pub const ECDSA_R_NOT_IMPLEMENTED = @as(c_int, 103); -pub const ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED = @as(c_int, 104); -pub const ECDSA_R_ENCODE_ERROR = @as(c_int, 105); -pub const OPENSSL_HEADER_OBJ_H = ""; -pub const OPENSSL_HEADER_BYTESTRING_H = ""; -pub const OPENSSL_HEADER_SSL_SPAN_H = ""; -pub const CBS_ASN1_TAG_SHIFT = @as(c_int, 24); -pub const CBS_ASN1_CONSTRUCTED = @as(c_uint, 0x20) << CBS_ASN1_TAG_SHIFT; -pub const CBS_ASN1_UNIVERSAL = @as(c_uint, 0) << CBS_ASN1_TAG_SHIFT; -pub const CBS_ASN1_APPLICATION = @as(c_uint, 0x40) << CBS_ASN1_TAG_SHIFT; -pub const CBS_ASN1_CONTEXT_SPECIFIC = @as(c_uint, 0x80) << CBS_ASN1_TAG_SHIFT; -pub const CBS_ASN1_PRIVATE = @as(c_uint, 0xc0) << CBS_ASN1_TAG_SHIFT; -pub const CBS_ASN1_CLASS_MASK = @as(c_uint, 0xc0) << CBS_ASN1_TAG_SHIFT; -pub const CBS_ASN1_TAG_NUMBER_MASK = (@as(c_uint, 1) << (@as(c_int, 5) + CBS_ASN1_TAG_SHIFT)) - @as(c_int, 1); -pub const CBS_ASN1_BOOLEAN = @as(c_uint, 0x1); -pub const CBS_ASN1_INTEGER = @as(c_uint, 0x2); -pub const CBS_ASN1_BITSTRING = @as(c_uint, 0x3); -pub const CBS_ASN1_OCTETSTRING = @as(c_uint, 0x4); -pub const CBS_ASN1_NULL = @as(c_uint, 0x5); -pub const CBS_ASN1_OBJECT = @as(c_uint, 0x6); -pub const CBS_ASN1_ENUMERATED = @as(c_uint, 0xa); -pub const CBS_ASN1_UTF8STRING = @as(c_uint, 0xc); -pub const CBS_ASN1_SEQUENCE = @as(c_uint, 0x10) | CBS_ASN1_CONSTRUCTED; -pub const CBS_ASN1_SET = @as(c_uint, 0x11) | CBS_ASN1_CONSTRUCTED; -pub const CBS_ASN1_NUMERICSTRING = @as(c_uint, 0x12); -pub const CBS_ASN1_PRINTABLESTRING = @as(c_uint, 0x13); -pub const CBS_ASN1_T61STRING = @as(c_uint, 0x14); -pub const CBS_ASN1_VIDEOTEXSTRING = @as(c_uint, 0x15); -pub const CBS_ASN1_IA5STRING = @as(c_uint, 0x16); -pub const CBS_ASN1_UTCTIME = @as(c_uint, 0x17); -pub const CBS_ASN1_GENERALIZEDTIME = @as(c_uint, 0x18); -pub const CBS_ASN1_GRAPHICSTRING = @as(c_uint, 0x19); -pub const CBS_ASN1_VISIBLESTRING = @as(c_uint, 0x1a); -pub const CBS_ASN1_GENERALSTRING = @as(c_uint, 0x1b); -pub const CBS_ASN1_UNIVERSALSTRING = @as(c_uint, 0x1c); -pub const CBS_ASN1_BMPSTRING = @as(c_uint, 0x1e); -pub const OBJ_NAME_TYPE_MD_METH = @as(c_int, 1); -pub const OBJ_NAME_TYPE_CIPHER_METH = @as(c_int, 2); -pub const OBJ_R_UNKNOWN_NID = @as(c_int, 100); -pub const OBJ_R_INVALID_OID_STRING = @as(c_int, 101); -pub const OPENSSL_HEADER_POOL_H = ""; -pub const OPENSSL_HEADER_RSA_H = ""; -pub const RSA_PKCS1_PADDING = @as(c_int, 1); -pub const RSA_NO_PADDING = @as(c_int, 3); -pub const RSA_PKCS1_OAEP_PADDING = @as(c_int, 4); -pub const RSA_PKCS1_PSS_PADDING = @as(c_int, 6); -pub const RSA_FLAG_OPAQUE = @as(c_int, 1); -pub const RSA_FLAG_NO_BLINDING = @as(c_int, 8); -pub const RSA_FLAG_EXT_PKEY = @as(c_int, 0x20); -pub const RSA_3 = @as(c_int, 0x3); -pub const RSA_F4 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x10001, .hex); -pub const RSA_METHOD_FLAG_NO_CHECK = RSA_FLAG_OPAQUE; -pub const RSA_R_BAD_ENCODING = @as(c_int, 100); -pub const RSA_R_BAD_E_VALUE = @as(c_int, 101); -pub const RSA_R_BAD_FIXED_HEADER_DECRYPT = @as(c_int, 102); -pub const RSA_R_BAD_PAD_BYTE_COUNT = @as(c_int, 103); -pub const RSA_R_BAD_RSA_PARAMETERS = @as(c_int, 104); -pub const RSA_R_BAD_SIGNATURE = @as(c_int, 105); -pub const RSA_R_BAD_VERSION = @as(c_int, 106); -pub const RSA_R_BLOCK_TYPE_IS_NOT_01 = @as(c_int, 107); -pub const RSA_R_BN_NOT_INITIALIZED = @as(c_int, 108); -pub const RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY = @as(c_int, 109); -pub const RSA_R_CRT_PARAMS_ALREADY_GIVEN = @as(c_int, 110); -pub const RSA_R_CRT_VALUES_INCORRECT = @as(c_int, 111); -pub const RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN = @as(c_int, 112); -pub const RSA_R_DATA_TOO_LARGE = @as(c_int, 113); -pub const RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE = @as(c_int, 114); -pub const RSA_R_DATA_TOO_LARGE_FOR_MODULUS = @as(c_int, 115); -pub const RSA_R_DATA_TOO_SMALL = @as(c_int, 116); -pub const RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE = @as(c_int, 117); -pub const RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY = @as(c_int, 118); -pub const RSA_R_D_E_NOT_CONGRUENT_TO_1 = @as(c_int, 119); -pub const RSA_R_EMPTY_PUBLIC_KEY = @as(c_int, 120); -pub const RSA_R_ENCODE_ERROR = @as(c_int, 121); -pub const RSA_R_FIRST_OCTET_INVALID = @as(c_int, 122); -pub const RSA_R_INCONSISTENT_SET_OF_CRT_VALUES = @as(c_int, 123); -pub const RSA_R_INTERNAL_ERROR = @as(c_int, 124); -pub const RSA_R_INVALID_MESSAGE_LENGTH = @as(c_int, 125); -pub const RSA_R_KEY_SIZE_TOO_SMALL = @as(c_int, 126); -pub const RSA_R_LAST_OCTET_INVALID = @as(c_int, 127); -pub const RSA_R_MODULUS_TOO_LARGE = @as(c_int, 128); -pub const RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES = @as(c_int, 129); -pub const RSA_R_NO_PUBLIC_EXPONENT = @as(c_int, 130); -pub const RSA_R_NULL_BEFORE_BLOCK_MISSING = @as(c_int, 131); -pub const RSA_R_N_NOT_EQUAL_P_Q = @as(c_int, 132); -pub const RSA_R_OAEP_DECODING_ERROR = @as(c_int, 133); -pub const RSA_R_ONLY_ONE_OF_P_Q_GIVEN = @as(c_int, 134); -pub const RSA_R_OUTPUT_BUFFER_TOO_SMALL = @as(c_int, 135); -pub const RSA_R_PADDING_CHECK_FAILED = @as(c_int, 136); -pub const RSA_R_PKCS_DECODING_ERROR = @as(c_int, 137); -pub const RSA_R_SLEN_CHECK_FAILED = @as(c_int, 138); -pub const RSA_R_SLEN_RECOVERY_FAILED = @as(c_int, 139); -pub const RSA_R_TOO_LONG = @as(c_int, 140); -pub const RSA_R_TOO_MANY_ITERATIONS = @as(c_int, 141); -pub const RSA_R_UNKNOWN_ALGORITHM_TYPE = @as(c_int, 142); -pub const RSA_R_UNKNOWN_PADDING_TYPE = @as(c_int, 143); -pub const RSA_R_VALUE_MISSING = @as(c_int, 144); -pub const RSA_R_WRONG_SIGNATURE_LENGTH = @as(c_int, 145); -pub const RSA_R_PUBLIC_KEY_VALIDATION_FAILED = @as(c_int, 146); -pub const RSA_R_D_OUT_OF_RANGE = @as(c_int, 147); -pub const RSA_R_BLOCK_TYPE_IS_NOT_02 = @as(c_int, 148); -pub const OPENSSL_HEADER_SHA_H = ""; -pub const SHA_CBLOCK = @as(c_int, 64); -pub const SHA_DIGEST_LENGTH = @as(c_int, 20); -pub const SHA224_CBLOCK = @as(c_int, 64); -pub const SHA224_DIGEST_LENGTH = @as(c_int, 28); -pub const SHA256_CBLOCK = @as(c_int, 64); -pub const SHA256_DIGEST_LENGTH = @as(c_int, 32); -pub const SHA384_CBLOCK = @as(c_int, 128); -pub const SHA384_DIGEST_LENGTH = @as(c_int, 48); -pub const SHA512_CBLOCK = @as(c_int, 128); -pub const SHA512_DIGEST_LENGTH = @as(c_int, 64); -pub const SHA512_256_DIGEST_LENGTH = @as(c_int, 32); -pub const X509_VERSION_1 = @as(c_int, 0); -pub const X509_VERSION_2 = @as(c_int, 1); -pub const X509_VERSION_3 = @as(c_int, 2); -pub const X509_CRL_VERSION_1 = @as(c_int, 0); -pub const X509_CRL_VERSION_2 = @as(c_int, 1); -pub const X509_REQ_VERSION_1 = @as(c_int, 0); -pub inline fn X509_extract_key(x: anytype) @TypeOf(X509_get_pubkey(x)) { - return X509_get_pubkey(x); -} -pub inline fn X509_REQ_extract_key(a: anytype) @TypeOf(X509_REQ_get_pubkey(a)) { - return X509_REQ_get_pubkey(a); -} -pub inline fn X509_name_cmp(a: anytype, b: anytype) @TypeOf(X509_NAME_cmp(a, b)) { - return X509_NAME_cmp(a, b); -} -pub const X509_CRL_set_lastUpdate = X509_CRL_set1_lastUpdate; -pub const X509_CRL_set_nextUpdate = X509_CRL_set1_nextUpdate; -pub const X509_FILETYPE_PEM = @as(c_int, 1); -pub const X509_FILETYPE_ASN1 = @as(c_int, 2); -pub const X509_FILETYPE_DEFAULT = @as(c_int, 3); -pub const X509v3_KU_DIGITAL_SIGNATURE = @as(c_int, 0x0080); -pub const X509v3_KU_NON_REPUDIATION = @as(c_int, 0x0040); -pub const X509v3_KU_KEY_ENCIPHERMENT = @as(c_int, 0x0020); -pub const X509v3_KU_DATA_ENCIPHERMENT = @as(c_int, 0x0010); -pub const X509v3_KU_KEY_AGREEMENT = @as(c_int, 0x0008); -pub const X509v3_KU_KEY_CERT_SIGN = @as(c_int, 0x0004); -pub const X509v3_KU_CRL_SIGN = @as(c_int, 0x0002); -pub const X509v3_KU_ENCIPHER_ONLY = @as(c_int, 0x0001); -pub const X509v3_KU_DECIPHER_ONLY = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex); -pub const X509v3_KU_UNDEF = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xffff, .hex); -pub const X509_TRUST_DEFAULT = -@as(c_int, 1); -pub const X509_TRUST_COMPAT = @as(c_int, 1); -pub const X509_TRUST_SSL_CLIENT = @as(c_int, 2); -pub const X509_TRUST_SSL_SERVER = @as(c_int, 3); -pub const X509_TRUST_EMAIL = @as(c_int, 4); -pub const X509_TRUST_OBJECT_SIGN = @as(c_int, 5); -pub const X509_TRUST_OCSP_SIGN = @as(c_int, 6); -pub const X509_TRUST_OCSP_REQUEST = @as(c_int, 7); -pub const X509_TRUST_TSA = @as(c_int, 8); -pub const X509_TRUST_MIN = @as(c_int, 1); -pub const X509_TRUST_MAX = @as(c_int, 8); -pub const X509_TRUST_DYNAMIC = @as(c_int, 1); -pub const X509_TRUST_DYNAMIC_NAME = @as(c_int, 2); -pub const X509_TRUST_TRUSTED = @as(c_int, 1); -pub const X509_TRUST_REJECTED = @as(c_int, 2); -pub const X509_TRUST_UNTRUSTED = @as(c_int, 3); -pub const X509_FLAG_COMPAT = @as(c_int, 0); -pub const X509_FLAG_NO_HEADER = @as(c_long, 1); -pub const X509_FLAG_NO_VERSION = @as(c_long, 1) << @as(c_int, 1); -pub const X509_FLAG_NO_SERIAL = @as(c_long, 1) << @as(c_int, 2); -pub const X509_FLAG_NO_SIGNAME = @as(c_long, 1) << @as(c_int, 3); -pub const X509_FLAG_NO_ISSUER = @as(c_long, 1) << @as(c_int, 4); -pub const X509_FLAG_NO_VALIDITY = @as(c_long, 1) << @as(c_int, 5); -pub const X509_FLAG_NO_SUBJECT = @as(c_long, 1) << @as(c_int, 6); -pub const X509_FLAG_NO_PUBKEY = @as(c_long, 1) << @as(c_int, 7); -pub const X509_FLAG_NO_EXTENSIONS = @as(c_long, 1) << @as(c_int, 8); -pub const X509_FLAG_NO_SIGDUMP = @as(c_long, 1) << @as(c_int, 9); -pub const X509_FLAG_NO_AUX = @as(c_long, 1) << @as(c_int, 10); -pub const X509_FLAG_NO_ATTRIBUTES = @as(c_long, 1) << @as(c_int, 11); -pub const X509_FLAG_NO_IDS = @as(c_long, 1) << @as(c_int, 12); -pub const XN_FLAG_SEP_MASK = @as(c_int, 0xf) << @as(c_int, 16); -pub const XN_FLAG_COMPAT = @as(c_int, 0); -pub const XN_FLAG_SEP_COMMA_PLUS = @as(c_int, 1) << @as(c_int, 16); -pub const XN_FLAG_SEP_CPLUS_SPC = @as(c_int, 2) << @as(c_int, 16); -pub const XN_FLAG_SEP_SPLUS_SPC = @as(c_int, 3) << @as(c_int, 16); -pub const XN_FLAG_SEP_MULTILINE = @as(c_int, 4) << @as(c_int, 16); -pub const XN_FLAG_DN_REV = @as(c_int, 1) << @as(c_int, 20); -pub const XN_FLAG_FN_MASK = @as(c_int, 0x3) << @as(c_int, 21); -pub const XN_FLAG_FN_SN = @as(c_int, 0); -pub const XN_FLAG_FN_LN = @as(c_int, 1) << @as(c_int, 21); -pub const XN_FLAG_FN_OID = @as(c_int, 2) << @as(c_int, 21); -pub const XN_FLAG_FN_NONE = @as(c_int, 3) << @as(c_int, 21); -pub const XN_FLAG_SPC_EQ = @as(c_int, 1) << @as(c_int, 23); -pub const XN_FLAG_DUMP_UNKNOWN_FIELDS = @as(c_int, 1) << @as(c_int, 24); -pub const XN_FLAG_FN_ALIGN = @as(c_int, 1) << @as(c_int, 25); -pub const XN_FLAG_RFC2253 = (((ASN1_STRFLGS_RFC2253 | XN_FLAG_SEP_COMMA_PLUS) | XN_FLAG_DN_REV) | XN_FLAG_FN_SN) | XN_FLAG_DUMP_UNKNOWN_FIELDS; -pub const XN_FLAG_ONELINE = (((ASN1_STRFLGS_RFC2253 | ASN1_STRFLGS_ESC_QUOTE) | XN_FLAG_SEP_CPLUS_SPC) | XN_FLAG_SPC_EQ) | XN_FLAG_FN_SN; -pub const XN_FLAG_MULTILINE = ((((ASN1_STRFLGS_ESC_CTRL | ASN1_STRFLGS_ESC_MSB) | XN_FLAG_SEP_MULTILINE) | XN_FLAG_SPC_EQ) | XN_FLAG_FN_LN) | XN_FLAG_FN_ALIGN; -pub const X509_LU_X509 = @as(c_int, 1); -pub const X509_LU_CRL = @as(c_int, 2); -pub const X509_LU_PKEY = @as(c_int, 3); -pub const X509_L_FILE_LOAD = @as(c_int, 1); -pub const X509_L_ADD_DIR = @as(c_int, 2); -pub inline fn X509_LOOKUP_load_file(x: anytype, name: anytype, @"type": anytype) @TypeOf(X509_LOOKUP_ctrl(x, X509_L_FILE_LOAD, name, @import("std").zig.c_translation.cast(c_long, @"type"), NULL)) { - return X509_LOOKUP_ctrl(x, X509_L_FILE_LOAD, name, @import("std").zig.c_translation.cast(c_long, @"type"), NULL); -} -pub inline fn X509_LOOKUP_add_dir(x: anytype, name: anytype, @"type": anytype) @TypeOf(X509_LOOKUP_ctrl(x, X509_L_ADD_DIR, name, @import("std").zig.c_translation.cast(c_long, @"type"), NULL)) { - return X509_LOOKUP_ctrl(x, X509_L_ADD_DIR, name, @import("std").zig.c_translation.cast(c_long, @"type"), NULL); -} -pub const X509_V_OK = @as(c_int, 0); -pub const X509_V_ERR_UNSPECIFIED = @as(c_int, 1); -pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = @as(c_int, 2); -pub const X509_V_ERR_UNABLE_TO_GET_CRL = @as(c_int, 3); -pub const X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = @as(c_int, 4); -pub const X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = @as(c_int, 5); -pub const X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = @as(c_int, 6); -pub const X509_V_ERR_CERT_SIGNATURE_FAILURE = @as(c_int, 7); -pub const X509_V_ERR_CRL_SIGNATURE_FAILURE = @as(c_int, 8); -pub const X509_V_ERR_CERT_NOT_YET_VALID = @as(c_int, 9); -pub const X509_V_ERR_CERT_HAS_EXPIRED = @as(c_int, 10); -pub const X509_V_ERR_CRL_NOT_YET_VALID = @as(c_int, 11); -pub const X509_V_ERR_CRL_HAS_EXPIRED = @as(c_int, 12); -pub const X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = @as(c_int, 13); -pub const X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = @as(c_int, 14); -pub const X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = @as(c_int, 15); -pub const X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = @as(c_int, 16); -pub const X509_V_ERR_OUT_OF_MEM = @as(c_int, 17); -pub const X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = @as(c_int, 18); -pub const X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = @as(c_int, 19); -pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = @as(c_int, 20); -pub const X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = @as(c_int, 21); -pub const X509_V_ERR_CERT_CHAIN_TOO_LONG = @as(c_int, 22); -pub const X509_V_ERR_CERT_REVOKED = @as(c_int, 23); -pub const X509_V_ERR_INVALID_CA = @as(c_int, 24); -pub const X509_V_ERR_PATH_LENGTH_EXCEEDED = @as(c_int, 25); -pub const X509_V_ERR_INVALID_PURPOSE = @as(c_int, 26); -pub const X509_V_ERR_CERT_UNTRUSTED = @as(c_int, 27); -pub const X509_V_ERR_CERT_REJECTED = @as(c_int, 28); -pub const X509_V_ERR_SUBJECT_ISSUER_MISMATCH = @as(c_int, 29); -pub const X509_V_ERR_AKID_SKID_MISMATCH = @as(c_int, 30); -pub const X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH = @as(c_int, 31); -pub const X509_V_ERR_KEYUSAGE_NO_CERTSIGN = @as(c_int, 32); -pub const X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER = @as(c_int, 33); -pub const X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION = @as(c_int, 34); -pub const X509_V_ERR_KEYUSAGE_NO_CRL_SIGN = @as(c_int, 35); -pub const X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION = @as(c_int, 36); -pub const X509_V_ERR_INVALID_NON_CA = @as(c_int, 37); -pub const X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED = @as(c_int, 38); -pub const X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE = @as(c_int, 39); -pub const X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED = @as(c_int, 40); -pub const X509_V_ERR_INVALID_EXTENSION = @as(c_int, 41); -pub const X509_V_ERR_INVALID_POLICY_EXTENSION = @as(c_int, 42); -pub const X509_V_ERR_NO_EXPLICIT_POLICY = @as(c_int, 43); -pub const X509_V_ERR_DIFFERENT_CRL_SCOPE = @as(c_int, 44); -pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE = @as(c_int, 45); -pub const X509_V_ERR_UNNESTED_RESOURCE = @as(c_int, 46); -pub const X509_V_ERR_PERMITTED_VIOLATION = @as(c_int, 47); -pub const X509_V_ERR_EXCLUDED_VIOLATION = @as(c_int, 48); -pub const X509_V_ERR_SUBTREE_MINMAX = @as(c_int, 49); -pub const X509_V_ERR_APPLICATION_VERIFICATION = @as(c_int, 50); -pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE = @as(c_int, 51); -pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = @as(c_int, 52); -pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = @as(c_int, 53); -pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR = @as(c_int, 54); - -pub const X509_V_ERR_SUITE_B_INVALID_VERSION = @as(c_int, 56); -pub const X509_V_ERR_SUITE_B_INVALID_ALGORITHM = @as(c_int, 57); -pub const X509_V_ERR_SUITE_B_INVALID_CURVE = @as(c_int, 58); -pub const X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = @as(c_int, 59); -pub const X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = @as(c_int, 60); -pub const X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = @as(c_int, 61); - -pub const X509_V_ERR_HOSTNAME_MISMATCH = @as(c_int, 62); -pub const X509_V_ERR_EMAIL_MISMATCH = @as(c_int, 63); -pub const X509_V_ERR_IP_ADDRESS_MISMATCH = @as(c_int, 64); -pub const X509_V_ERR_INVALID_CALL = @as(c_int, 65); -pub const X509_V_ERR_STORE_LOOKUP = @as(c_int, 66); -pub const X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS = @as(c_int, 67); -pub const X509_V_FLAG_CB_ISSUER_CHECK = @as(c_int, 0x1); -pub const X509_V_FLAG_USE_CHECK_TIME = @as(c_int, 0x2); -pub const X509_V_FLAG_CRL_CHECK = @as(c_int, 0x4); -pub const X509_V_FLAG_CRL_CHECK_ALL = @as(c_int, 0x8); -pub const X509_V_FLAG_IGNORE_CRITICAL = @as(c_int, 0x10); -pub const X509_V_FLAG_X509_STRICT = @as(c_int, 0x00); -pub const X509_V_FLAG_ALLOW_PROXY_CERTS = @as(c_int, 0x40); -pub const X509_V_FLAG_POLICY_CHECK = @as(c_int, 0x80); -pub const X509_V_FLAG_EXPLICIT_POLICY = @as(c_int, 0x100); -pub const X509_V_FLAG_INHIBIT_ANY = @as(c_int, 0x200); -pub const X509_V_FLAG_INHIBIT_MAP = @as(c_int, 0x400); -pub const X509_V_FLAG_NOTIFY_POLICY = @as(c_int, 0x800); -pub const X509_V_FLAG_EXTENDED_CRL_SUPPORT = @as(c_int, 0x1000); -pub const X509_V_FLAG_USE_DELTAS = @as(c_int, 0x2000); -pub const X509_V_FLAG_CHECK_SS_SIGNATURE = @as(c_int, 0x4000); -pub const X509_V_FLAG_TRUSTED_FIRST = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x8000, .hex); -pub const X509_V_FLAG_PARTIAL_CHAIN = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x80000, .hex); -pub const X509_V_FLAG_NO_ALT_CHAINS = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x100000, .hex); -pub const X509_V_FLAG_NO_CHECK_TIME = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x200000, .hex); -pub const X509_VP_FLAG_DEFAULT = @as(c_int, 0x1); -pub const X509_VP_FLAG_OVERWRITE = @as(c_int, 0x2); -pub const X509_VP_FLAG_RESET_FLAGS = @as(c_int, 0x4); -pub const X509_VP_FLAG_LOCKED = @as(c_int, 0x8); -pub const X509_VP_FLAG_ONCE = @as(c_int, 0x10); -pub const X509_V_FLAG_POLICY_MASK = ((X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY) | X509_V_FLAG_INHIBIT_ANY) | X509_V_FLAG_INHIBIT_MAP; -pub inline fn X509_STORE_set_verify_func(ctx: anytype, func: anytype) @TypeOf(X509_STORE_set_verify(ctx, func)) { - return X509_STORE_set_verify(ctx, func); -} -pub inline fn X509_STORE_set_verify_cb_func(ctx: anytype, func: anytype) @TypeOf(X509_STORE_set_verify_cb(ctx, func)) { - return X509_STORE_set_verify_cb(ctx, func); -} -pub inline fn X509_STORE_set_lookup_crls_cb(ctx: anytype, func: anytype) @TypeOf(X509_STORE_set_lookup_crls(ctx, func)) { - return X509_STORE_set_lookup_crls(ctx, func); -} -pub const X509_R_AKID_MISMATCH = @as(c_int, 100); -pub const X509_R_BAD_PKCS7_VERSION = @as(c_int, 101); -pub const X509_R_BAD_X509_FILETYPE = @as(c_int, 102); -pub const X509_R_BASE64_DECODE_ERROR = @as(c_int, 103); -pub const X509_R_CANT_CHECK_DH_KEY = @as(c_int, 104); -pub const X509_R_CERT_ALREADY_IN_HASH_TABLE = @as(c_int, 105); -pub const X509_R_CRL_ALREADY_DELTA = @as(c_int, 106); -pub const X509_R_CRL_VERIFY_FAILURE = @as(c_int, 107); -pub const X509_R_IDP_MISMATCH = @as(c_int, 108); -pub const X509_R_INVALID_BIT_STRING_BITS_LEFT = @as(c_int, 109); -pub const X509_R_INVALID_DIRECTORY = @as(c_int, 110); -pub const X509_R_INVALID_FIELD_NAME = @as(c_int, 111); -pub const X509_R_INVALID_PSS_PARAMETERS = @as(c_int, 112); -pub const X509_R_INVALID_TRUST = @as(c_int, 113); -pub const X509_R_ISSUER_MISMATCH = @as(c_int, 114); -pub const X509_R_KEY_TYPE_MISMATCH = @as(c_int, 115); -pub const X509_R_KEY_VALUES_MISMATCH = @as(c_int, 116); -pub const X509_R_LOADING_CERT_DIR = @as(c_int, 117); -pub const X509_R_LOADING_DEFAULTS = @as(c_int, 118); -pub const X509_R_NEWER_CRL_NOT_NEWER = @as(c_int, 119); -pub const X509_R_NOT_PKCS7_SIGNED_DATA = @as(c_int, 120); -pub const X509_R_NO_CERTIFICATES_INCLUDED = @as(c_int, 121); -pub const X509_R_NO_CERT_SET_FOR_US_TO_VERIFY = @as(c_int, 122); -pub const X509_R_NO_CRLS_INCLUDED = @as(c_int, 123); -pub const X509_R_NO_CRL_NUMBER = @as(c_int, 124); -pub const X509_R_PUBLIC_KEY_DECODE_ERROR = @as(c_int, 125); -pub const X509_R_PUBLIC_KEY_ENCODE_ERROR = @as(c_int, 126); -pub const X509_R_SHOULD_RETRY = @as(c_int, 127); -pub const X509_R_UNKNOWN_KEY_TYPE = @as(c_int, 128); -pub const X509_R_UNKNOWN_NID = @as(c_int, 129); -pub const X509_R_UNKNOWN_PURPOSE_ID = @as(c_int, 130); -pub const X509_R_UNKNOWN_TRUST_ID = @as(c_int, 131); -pub const X509_R_UNSUPPORTED_ALGORITHM = @as(c_int, 132); -pub const X509_R_WRONG_LOOKUP_TYPE = @as(c_int, 133); -pub const X509_R_WRONG_TYPE = @as(c_int, 134); -pub const X509_R_NAME_TOO_LONG = @as(c_int, 135); -pub const X509_R_INVALID_PARAMETER = @as(c_int, 136); -pub const X509_R_SIGNATURE_ALGORITHM_MISMATCH = @as(c_int, 137); -pub const X509_R_DELTA_CRL_WITHOUT_CRL_NUMBER = @as(c_int, 138); -pub const X509_R_INVALID_FIELD_FOR_VERSION = @as(c_int, 139); -pub const X509_R_INVALID_VERSION = @as(c_int, 140); -pub const X509_R_NO_CERTIFICATE_FOUND = @as(c_int, 141); -pub const X509_R_NO_CERTIFICATE_OR_CRL_FOUND = @as(c_int, 142); -pub const X509_R_NO_CRL_FOUND = @as(c_int, 143); -pub const OPENSSL_HEADER_CRYPTO_H = ""; -pub const OPENSSL_HEADER_MEM_H = ""; -pub const OPENSSL_VERSION_TEXT = "OpenSSL 1.1.1 (compatible; BoringSSL)"; -pub const OPENSSL_VERSION = @as(c_int, 0); -pub const OPENSSL_CFLAGS = @as(c_int, 1); -pub const OPENSSL_BUILT_ON = @as(c_int, 2); -pub const OPENSSL_PLATFORM = @as(c_int, 3); -pub const OPENSSL_DIR = @as(c_int, 4); -pub const SSLEAY_VERSION = OPENSSL_VERSION; -pub const SSLEAY_CFLAGS = OPENSSL_CFLAGS; -pub const SSLEAY_BUILT_ON = OPENSSL_BUILT_ON; -pub const SSLEAY_PLATFORM = OPENSSL_PLATFORM; -pub const SSLEAY_DIR = OPENSSL_DIR; -pub const OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS = @as(c_int, 0); -pub const OPENSSL_INIT_LOAD_CRYPTO_STRINGS = @as(c_int, 0); -pub const OPENSSL_INIT_ADD_ALL_CIPHERS = @as(c_int, 0); -pub const OPENSSL_INIT_ADD_ALL_DIGESTS = @as(c_int, 0); -pub const OPENSSL_INIT_NO_ADD_ALL_CIPHERS = @as(c_int, 0); -pub const OPENSSL_INIT_NO_ADD_ALL_DIGESTS = @as(c_int, 0); -pub const OPENSSL_INIT_LOAD_CONFIG = @as(c_int, 0); -pub const OPENSSL_INIT_NO_LOAD_CONFIG = @as(c_int, 0); -pub const PEM_BUFSIZE = @as(c_int, 1024); -pub const PEM_STRING_X509_OLD = "X509 CERTIFICATE"; -pub const PEM_STRING_X509 = "CERTIFICATE"; -pub const PEM_STRING_X509_PAIR = "CERTIFICATE PAIR"; -pub const PEM_STRING_X509_TRUSTED = "TRUSTED CERTIFICATE"; -pub const PEM_STRING_X509_REQ_OLD = "NEW CERTIFICATE REQUEST"; -pub const PEM_STRING_X509_REQ = "CERTIFICATE REQUEST"; -pub const PEM_STRING_X509_CRL = "X509 CRL"; -pub const PEM_STRING_EVP_PKEY = "ANY PRIVATE KEY"; -pub const PEM_STRING_PUBLIC = "PUBLIC KEY"; -pub const PEM_STRING_RSA = "RSA PRIVATE KEY"; -pub const PEM_STRING_RSA_PUBLIC = "RSA PUBLIC KEY"; -pub const PEM_STRING_DSA = "DSA PRIVATE KEY"; -pub const PEM_STRING_DSA_PUBLIC = "DSA PUBLIC KEY"; -pub const PEM_STRING_EC = "EC PRIVATE KEY"; -pub const PEM_STRING_PKCS7 = "PKCS7"; -pub const PEM_STRING_PKCS7_SIGNED = "PKCS #7 SIGNED DATA"; -pub const PEM_STRING_PKCS8 = "ENCRYPTED PRIVATE KEY"; -pub const PEM_STRING_PKCS8INF = "PRIVATE KEY"; -pub const PEM_STRING_DHPARAMS = "DH PARAMETERS"; -pub const PEM_STRING_SSL_SESSION = "SSL SESSION PARAMETERS"; -pub const PEM_STRING_DSAPARAMS = "DSA PARAMETERS"; -pub const PEM_STRING_ECDSA_PUBLIC = "ECDSA PUBLIC KEY"; -pub const PEM_STRING_ECPRIVATEKEY = "EC PRIVATE KEY"; -pub const PEM_STRING_CMS = "CMS"; -pub const PEM_TYPE_ENCRYPTED = @as(c_int, 10); -pub const PEM_TYPE_MIC_ONLY = @as(c_int, 20); -pub const PEM_TYPE_MIC_CLEAR = @as(c_int, 30); -pub const PEM_TYPE_CLEAR = @as(c_int, 40); -pub const PEM_R_BAD_BASE64_DECODE = @as(c_int, 100); -pub const PEM_R_BAD_DECRYPT = @as(c_int, 101); -pub const PEM_R_BAD_END_LINE = @as(c_int, 102); -pub const PEM_R_BAD_IV_CHARS = @as(c_int, 103); -pub const PEM_R_BAD_PASSWORD_READ = @as(c_int, 104); -pub const PEM_R_CIPHER_IS_NULL = @as(c_int, 105); -pub const PEM_R_ERROR_CONVERTING_PRIVATE_KEY = @as(c_int, 106); -pub const PEM_R_NOT_DEK_INFO = @as(c_int, 107); -pub const PEM_R_NOT_ENCRYPTED = @as(c_int, 108); -pub const PEM_R_NOT_PROC_TYPE = @as(c_int, 109); -pub const PEM_R_NO_START_LINE = @as(c_int, 110); -pub const PEM_R_READ_KEY = @as(c_int, 111); -pub const PEM_R_SHORT_HEADER = @as(c_int, 112); -pub const PEM_R_UNSUPPORTED_CIPHER = @as(c_int, 113); -pub const PEM_R_UNSUPPORTED_ENCRYPTION = @as(c_int, 114); -pub const OPENSSL_HEADER_SSL3_H = ""; -pub const SSL2_MT_CLIENT_HELLO = @as(c_int, 1); -pub const SSL2_VERSION = @as(c_int, 0x0002); -pub const SSL3_CK_SCSV = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000FF, .hex); -pub const SSL3_CK_FALLBACK_SCSV = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03005600, .hex); -pub const SSL3_CK_RSA_NULL_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000001, .hex); -pub const SSL3_CK_RSA_NULL_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000002, .hex); -pub const SSL3_CK_RSA_RC4_40_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000003, .hex); -pub const SSL3_CK_RSA_RC4_128_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000004, .hex); -pub const SSL3_CK_RSA_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000005, .hex); -pub const SSL3_CK_RSA_RC2_40_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000006, .hex); -pub const SSL3_CK_RSA_IDEA_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000007, .hex); -pub const SSL3_CK_RSA_DES_40_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000008, .hex); -pub const SSL3_CK_RSA_DES_64_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000009, .hex); -pub const SSL3_CK_RSA_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300000A, .hex); -pub const SSL3_CK_DH_DSS_DES_40_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300000B, .hex); -pub const SSL3_CK_DH_DSS_DES_64_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300000C, .hex); -pub const SSL3_CK_DH_DSS_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300000D, .hex); -pub const SSL3_CK_DH_RSA_DES_40_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300000E, .hex); -pub const SSL3_CK_DH_RSA_DES_64_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300000F, .hex); -pub const SSL3_CK_DH_RSA_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000010, .hex); -pub const SSL3_CK_EDH_DSS_DES_40_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000011, .hex); -pub const SSL3_CK_EDH_DSS_DES_64_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000012, .hex); -pub const SSL3_CK_EDH_DSS_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000013, .hex); -pub const SSL3_CK_EDH_RSA_DES_40_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000014, .hex); -pub const SSL3_CK_EDH_RSA_DES_64_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000015, .hex); -pub const SSL3_CK_EDH_RSA_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000016, .hex); -pub const SSL3_CK_ADH_RC4_40_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000017, .hex); -pub const SSL3_CK_ADH_RC4_128_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000018, .hex); -pub const SSL3_CK_ADH_DES_40_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000019, .hex); -pub const SSL3_CK_ADH_DES_64_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300001A, .hex); -pub const SSL3_CK_ADH_DES_192_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300001B, .hex); -pub const SSL3_TXT_RSA_NULL_MD5 = "NULL-MD5"; -pub const SSL3_TXT_RSA_NULL_SHA = "NULL-SHA"; -pub const SSL3_TXT_RSA_RC4_40_MD5 = "EXP-RC4-MD5"; -pub const SSL3_TXT_RSA_RC4_128_MD5 = "RC4-MD5"; -pub const SSL3_TXT_RSA_RC4_128_SHA = "RC4-SHA"; -pub const SSL3_TXT_RSA_RC2_40_MD5 = "EXP-RC2-CBC-MD5"; -pub const SSL3_TXT_RSA_IDEA_128_SHA = "IDEA-CBC-SHA"; -pub const SSL3_TXT_RSA_DES_40_CBC_SHA = "EXP-DES-CBC-SHA"; -pub const SSL3_TXT_RSA_DES_64_CBC_SHA = "DES-CBC-SHA"; -pub const SSL3_TXT_RSA_DES_192_CBC3_SHA = "DES-CBC3-SHA"; -pub const SSL3_TXT_DH_DSS_DES_40_CBC_SHA = "EXP-DH-DSS-DES-CBC-SHA"; -pub const SSL3_TXT_DH_DSS_DES_64_CBC_SHA = "DH-DSS-DES-CBC-SHA"; -pub const SSL3_TXT_DH_DSS_DES_192_CBC3_SHA = "DH-DSS-DES-CBC3-SHA"; -pub const SSL3_TXT_DH_RSA_DES_40_CBC_SHA = "EXP-DH-RSA-DES-CBC-SHA"; -pub const SSL3_TXT_DH_RSA_DES_64_CBC_SHA = "DH-RSA-DES-CBC-SHA"; -pub const SSL3_TXT_DH_RSA_DES_192_CBC3_SHA = "DH-RSA-DES-CBC3-SHA"; -pub const SSL3_TXT_EDH_DSS_DES_40_CBC_SHA = "EXP-EDH-DSS-DES-CBC-SHA"; -pub const SSL3_TXT_EDH_DSS_DES_64_CBC_SHA = "EDH-DSS-DES-CBC-SHA"; -pub const SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA = "EDH-DSS-DES-CBC3-SHA"; -pub const SSL3_TXT_EDH_RSA_DES_40_CBC_SHA = "EXP-EDH-RSA-DES-CBC-SHA"; -pub const SSL3_TXT_EDH_RSA_DES_64_CBC_SHA = "EDH-RSA-DES-CBC-SHA"; -pub const SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA = "EDH-RSA-DES-CBC3-SHA"; -pub const SSL3_TXT_ADH_RC4_40_MD5 = "EXP-ADH-RC4-MD5"; -pub const SSL3_TXT_ADH_RC4_128_MD5 = "ADH-RC4-MD5"; -pub const SSL3_TXT_ADH_DES_40_CBC_SHA = "EXP-ADH-DES-CBC-SHA"; -pub const SSL3_TXT_ADH_DES_64_CBC_SHA = "ADH-DES-CBC-SHA"; -pub const SSL3_TXT_ADH_DES_192_CBC_SHA = "ADH-DES-CBC3-SHA"; -pub const SSL3_SSL_SESSION_ID_LENGTH = @as(c_int, 32); -pub const SSL3_MAX_SSL_SESSION_ID_LENGTH = @as(c_int, 32); -pub const SSL3_MASTER_SECRET_SIZE = @as(c_int, 48); -pub const SSL3_RANDOM_SIZE = @as(c_int, 32); -pub const SSL3_SESSION_ID_SIZE = @as(c_int, 32); -pub const SSL3_RT_HEADER_LENGTH = @as(c_int, 5); -pub const SSL3_HM_HEADER_LENGTH = @as(c_int, 4); -pub const SSL3_ALIGN_PAYLOAD = @as(c_int, 8); -pub const SSL3_RT_MAX_MD_SIZE = @as(c_int, 64); -pub const SSL_RT_MAX_CIPHER_BLOCK_SIZE = @as(c_int, 16); -pub const SSL3_RT_MAX_PLAIN_LENGTH = @as(c_int, 16384); -pub const SSL3_RT_MAX_COMPRESSED_OVERHEAD = @as(c_int, 1024); -pub const SSL3_RT_MAX_ENCRYPTED_OVERHEAD = @as(c_int, 256) + SSL3_RT_MAX_MD_SIZE; -pub const SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD = EVP_AEAD_MAX_OVERHEAD + EVP_AEAD_MAX_NONCE_LENGTH; -pub const SSL3_RT_MAX_COMPRESSED_LENGTH = SSL3_RT_MAX_PLAIN_LENGTH; -pub const SSL3_RT_MAX_ENCRYPTED_LENGTH = SSL3_RT_MAX_ENCRYPTED_OVERHEAD + SSL3_RT_MAX_COMPRESSED_LENGTH; -pub const SSL3_RT_MAX_PACKET_SIZE = SSL3_RT_MAX_ENCRYPTED_LENGTH + SSL3_RT_HEADER_LENGTH; -pub const SSL3_MD_CLIENT_FINISHED_CONST = "\x43\x4c\x4e\x54"; -pub const SSL3_MD_SERVER_FINISHED_CONST = "\x53\x52\x56\x52"; -pub const SSL3_RT_CHANGE_CIPHER_SPEC = @as(c_int, 20); -pub const SSL3_RT_ALERT = @as(c_int, 21); -pub const SSL3_RT_HANDSHAKE = @as(c_int, 22); -pub const SSL3_RT_APPLICATION_DATA = @as(c_int, 23); -pub const SSL3_RT_HEADER = @as(c_int, 0x100); -pub const SSL3_RT_CLIENT_HELLO_INNER = @as(c_int, 0x101); -pub const SSL3_AL_WARNING = @as(c_int, 1); -pub const SSL3_AL_FATAL = @as(c_int, 2); -pub const SSL3_AD_CLOSE_NOTIFY = @as(c_int, 0); -pub const SSL3_AD_UNEXPECTED_MESSAGE = @as(c_int, 10); -pub const SSL3_AD_BAD_RECORD_MAC = @as(c_int, 20); -pub const SSL3_AD_DECOMPRESSION_FAILURE = @as(c_int, 30); -pub const SSL3_AD_HANDSHAKE_FAILURE = @as(c_int, 40); -pub const SSL3_AD_NO_CERTIFICATE = @as(c_int, 41); -pub const SSL3_AD_BAD_CERTIFICATE = @as(c_int, 42); -pub const SSL3_AD_UNSUPPORTED_CERTIFICATE = @as(c_int, 43); -pub const SSL3_AD_CERTIFICATE_REVOKED = @as(c_int, 44); -pub const SSL3_AD_CERTIFICATE_EXPIRED = @as(c_int, 45); -pub const SSL3_AD_CERTIFICATE_UNKNOWN = @as(c_int, 46); -pub const SSL3_AD_ILLEGAL_PARAMETER = @as(c_int, 47); -pub const SSL3_AD_INAPPROPRIATE_FALLBACK = @as(c_int, 86); -pub const SSL3_CT_RSA_SIGN = @as(c_int, 1); -pub const SSL3_MT_HELLO_REQUEST = @as(c_int, 0); -pub const SSL3_MT_CLIENT_HELLO = @as(c_int, 1); -pub const SSL3_MT_SERVER_HELLO = @as(c_int, 2); -pub const SSL3_MT_NEW_SESSION_TICKET = @as(c_int, 4); -pub const SSL3_MT_END_OF_EARLY_DATA = @as(c_int, 5); -pub const SSL3_MT_ENCRYPTED_EXTENSIONS = @as(c_int, 8); -pub const SSL3_MT_CERTIFICATE = @as(c_int, 11); -pub const SSL3_MT_SERVER_KEY_EXCHANGE = @as(c_int, 12); -pub const SSL3_MT_CERTIFICATE_REQUEST = @as(c_int, 13); -pub const SSL3_MT_SERVER_HELLO_DONE = @as(c_int, 14); -pub const SSL3_MT_CERTIFICATE_VERIFY = @as(c_int, 15); -pub const SSL3_MT_CLIENT_KEY_EXCHANGE = @as(c_int, 16); -pub const SSL3_MT_FINISHED = @as(c_int, 20); -pub const SSL3_MT_CERTIFICATE_STATUS = @as(c_int, 22); -pub const SSL3_MT_SUPPLEMENTAL_DATA = @as(c_int, 23); -pub const SSL3_MT_KEY_UPDATE = @as(c_int, 24); -pub const SSL3_MT_COMPRESSED_CERTIFICATE = @as(c_int, 25); -pub const SSL3_MT_NEXT_PROTO = @as(c_int, 67); -pub const SSL3_MT_CHANNEL_ID = @as(c_int, 203); -pub const SSL3_MT_MESSAGE_HASH = @as(c_int, 254); -pub const DTLS1_MT_HELLO_VERIFY_REQUEST = @as(c_int, 3); -pub const SSL3_MT_SERVER_DONE = SSL3_MT_SERVER_HELLO_DONE; -pub const SSL3_MT_NEWSESSION_TICKET = SSL3_MT_NEW_SESSION_TICKET; -pub const SSL3_MT_CCS = @as(c_int, 1); -pub const OPENSSL_HEADER_TLS1_H = ""; -pub const TLS1_AD_END_OF_EARLY_DATA = @as(c_int, 1); -pub const TLS1_AD_DECRYPTION_FAILED = @as(c_int, 21); -pub const TLS1_AD_RECORD_OVERFLOW = @as(c_int, 22); -pub const TLS1_AD_UNKNOWN_CA = @as(c_int, 48); -pub const TLS1_AD_ACCESS_DENIED = @as(c_int, 49); -pub const TLS1_AD_DECODE_ERROR = @as(c_int, 50); -pub const TLS1_AD_DECRYPT_ERROR = @as(c_int, 51); -pub const TLS1_AD_EXPORT_RESTRICTION = @as(c_int, 60); -pub const TLS1_AD_PROTOCOL_VERSION = @as(c_int, 70); -pub const TLS1_AD_INSUFFICIENT_SECURITY = @as(c_int, 71); -pub const TLS1_AD_INTERNAL_ERROR = @as(c_int, 80); -pub const TLS1_AD_USER_CANCELLED = @as(c_int, 90); -pub const TLS1_AD_NO_RENEGOTIATION = @as(c_int, 100); -pub const TLS1_AD_MISSING_EXTENSION = @as(c_int, 109); -pub const TLS1_AD_UNSUPPORTED_EXTENSION = @as(c_int, 110); -pub const TLS1_AD_CERTIFICATE_UNOBTAINABLE = @as(c_int, 111); -pub const TLS1_AD_UNRECOGNIZED_NAME = @as(c_int, 112); -pub const TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE = @as(c_int, 113); -pub const TLS1_AD_BAD_CERTIFICATE_HASH_VALUE = @as(c_int, 114); -pub const TLS1_AD_UNKNOWN_PSK_IDENTITY = @as(c_int, 115); -pub const TLS1_AD_CERTIFICATE_REQUIRED = @as(c_int, 116); -pub const TLS1_AD_NO_APPLICATION_PROTOCOL = @as(c_int, 120); -pub const TLS1_AD_ECH_REQUIRED = @as(c_int, 121); -pub const TLSEXT_TYPE_server_name = @as(c_int, 0); -pub const TLSEXT_TYPE_status_request = @as(c_int, 5); -pub const TLSEXT_TYPE_ec_point_formats = @as(c_int, 11); -pub const TLSEXT_TYPE_signature_algorithms = @as(c_int, 13); -pub const TLSEXT_TYPE_srtp = @as(c_int, 14); -pub const TLSEXT_TYPE_application_layer_protocol_negotiation = @as(c_int, 16); -pub const TLSEXT_TYPE_padding = @as(c_int, 21); -pub const TLSEXT_TYPE_extended_master_secret = @as(c_int, 23); -pub const TLSEXT_TYPE_quic_transport_parameters_legacy = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xffa5, .hex); -pub const TLSEXT_TYPE_quic_transport_parameters = @as(c_int, 57); -pub const TLSEXT_TYPE_quic_transport_parameters_standard = TLSEXT_TYPE_quic_transport_parameters; -pub const TLSEXT_TYPE_cert_compression = @as(c_int, 27); -pub const TLSEXT_TYPE_session_ticket = @as(c_int, 35); -pub const TLSEXT_TYPE_supported_groups = @as(c_int, 10); -pub const TLSEXT_TYPE_pre_shared_key = @as(c_int, 41); -pub const TLSEXT_TYPE_early_data = @as(c_int, 42); -pub const TLSEXT_TYPE_supported_versions = @as(c_int, 43); -pub const TLSEXT_TYPE_cookie = @as(c_int, 44); -pub const TLSEXT_TYPE_psk_key_exchange_modes = @as(c_int, 45); -pub const TLSEXT_TYPE_certificate_authorities = @as(c_int, 47); -pub const TLSEXT_TYPE_signature_algorithms_cert = @as(c_int, 50); -pub const TLSEXT_TYPE_key_share = @as(c_int, 51); -pub const TLSEXT_TYPE_renegotiate = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xff01, .hex); -pub const TLSEXT_TYPE_delegated_credential = @as(c_int, 0x22); -pub const TLSEXT_TYPE_application_settings = @as(c_int, 17513); -pub const TLSEXT_TYPE_encrypted_client_hello = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xfe0d, .hex); -pub const TLSEXT_TYPE_ech_outer_extensions = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xfd00, .hex); -pub const TLSEXT_TYPE_certificate_timestamp = @as(c_int, 18); -pub const TLSEXT_TYPE_next_proto_neg = @as(c_int, 13172); -pub const TLSEXT_TYPE_channel_id = @as(c_int, 30032); -pub const TLSEXT_STATUSTYPE_nothing = -@as(c_int, 1); -pub const TLSEXT_STATUSTYPE_ocsp = @as(c_int, 1); -pub const TLSEXT_ECPOINTFORMAT_uncompressed = @as(c_int, 0); -pub const TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime = @as(c_int, 1); -pub const TLSEXT_signature_anonymous = @as(c_int, 0); -pub const TLSEXT_signature_rsa = @as(c_int, 1); -pub const TLSEXT_signature_dsa = @as(c_int, 2); -pub const TLSEXT_signature_ecdsa = @as(c_int, 3); -pub const TLSEXT_hash_none = @as(c_int, 0); -pub const TLSEXT_hash_md5 = @as(c_int, 1); -pub const TLSEXT_hash_sha1 = @as(c_int, 2); -pub const TLSEXT_hash_sha224 = @as(c_int, 3); -pub const TLSEXT_hash_sha256 = @as(c_int, 4); -pub const TLSEXT_hash_sha384 = @as(c_int, 5); -pub const TLSEXT_hash_sha512 = @as(c_int, 6); -pub const TLSEXT_cert_compression_zlib = @as(c_int, 1); -pub const TLSEXT_cert_compression_brotli = @as(c_int, 2); -pub const TLSEXT_MAXLEN_host_name = @as(c_int, 255); -pub const TLS1_CK_PSK_WITH_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300008A, .hex); -pub const TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300008B, .hex); -pub const TLS1_CK_PSK_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300008C, .hex); -pub const TLS1_CK_PSK_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300008D, .hex); -pub const TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C035, .hex); -pub const TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C036, .hex); -pub const TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000060, .hex); -pub const TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000061, .hex); -pub const TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000062, .hex); -pub const TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000063, .hex); -pub const TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000064, .hex); -pub const TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000065, .hex); -pub const TLS1_CK_DHE_DSS_WITH_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000066, .hex); -pub const TLS1_CK_RSA_WITH_AES_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300002F, .hex); -pub const TLS1_CK_DH_DSS_WITH_AES_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000030, .hex); -pub const TLS1_CK_DH_RSA_WITH_AES_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000031, .hex); -pub const TLS1_CK_DHE_DSS_WITH_AES_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000032, .hex); -pub const TLS1_CK_DHE_RSA_WITH_AES_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000033, .hex); -pub const TLS1_CK_ADH_WITH_AES_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000034, .hex); -pub const TLS1_CK_RSA_WITH_AES_256_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000035, .hex); -pub const TLS1_CK_DH_DSS_WITH_AES_256_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000036, .hex); -pub const TLS1_CK_DH_RSA_WITH_AES_256_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000037, .hex); -pub const TLS1_CK_DHE_DSS_WITH_AES_256_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000038, .hex); -pub const TLS1_CK_DHE_RSA_WITH_AES_256_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000039, .hex); -pub const TLS1_CK_ADH_WITH_AES_256_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300003A, .hex); -pub const TLS1_CK_RSA_WITH_NULL_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300003B, .hex); -pub const TLS1_CK_RSA_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300003C, .hex); -pub const TLS1_CK_RSA_WITH_AES_256_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300003D, .hex); -pub const TLS1_CK_DH_DSS_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300003E, .hex); -pub const TLS1_CK_DH_RSA_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300003F, .hex); -pub const TLS1_CK_DHE_DSS_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000040, .hex); -pub const TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000041, .hex); -pub const TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000042, .hex); -pub const TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000043, .hex); -pub const TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000044, .hex); -pub const TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000045, .hex); -pub const TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000046, .hex); -pub const TLS1_CK_DHE_RSA_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000067, .hex); -pub const TLS1_CK_DH_DSS_WITH_AES_256_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000068, .hex); -pub const TLS1_CK_DH_RSA_WITH_AES_256_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000069, .hex); -pub const TLS1_CK_DHE_DSS_WITH_AES_256_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300006A, .hex); -pub const TLS1_CK_DHE_RSA_WITH_AES_256_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300006B, .hex); -pub const TLS1_CK_ADH_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300006C, .hex); -pub const TLS1_CK_ADH_WITH_AES_256_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300006D, .hex); -pub const TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000084, .hex); -pub const TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000085, .hex); -pub const TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000086, .hex); -pub const TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000087, .hex); -pub const TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000088, .hex); -pub const TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000089, .hex); -pub const TLS1_CK_RSA_WITH_SEED_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000096, .hex); -pub const TLS1_CK_DH_DSS_WITH_SEED_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000097, .hex); -pub const TLS1_CK_DH_RSA_WITH_SEED_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000098, .hex); -pub const TLS1_CK_DHE_DSS_WITH_SEED_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03000099, .hex); -pub const TLS1_CK_DHE_RSA_WITH_SEED_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300009A, .hex); -pub const TLS1_CK_ADH_WITH_SEED_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300009B, .hex); -pub const TLS1_CK_RSA_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300009C, .hex); -pub const TLS1_CK_RSA_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300009D, .hex); -pub const TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300009E, .hex); -pub const TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300009F, .hex); -pub const TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A0, .hex); -pub const TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A1, .hex); -pub const TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A2, .hex); -pub const TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A3, .hex); -pub const TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A4, .hex); -pub const TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A5, .hex); -pub const TLS1_CK_ADH_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A6, .hex); -pub const TLS1_CK_ADH_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x030000A7, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C001, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C002, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C003, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C004, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C005, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C006, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C007, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C008, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C009, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C00A, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_NULL_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C00B, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C00C, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C00D, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C00E, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C00F, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_NULL_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C010, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C011, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C012, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C013, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C014, .hex); -pub const TLS1_CK_ECDH_anon_WITH_NULL_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C015, .hex); -pub const TLS1_CK_ECDH_anon_WITH_RC4_128_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C016, .hex); -pub const TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C017, .hex); -pub const TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C018, .hex); -pub const TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C019, .hex); -pub const TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C01A, .hex); -pub const TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C01B, .hex); -pub const TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C01C, .hex); -pub const TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C01D, .hex); -pub const TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C01E, .hex); -pub const TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C01F, .hex); -pub const TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C020, .hex); -pub const TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C021, .hex); -pub const TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C022, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C023, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C024, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C025, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C026, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C027, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C028, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C029, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C02A, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C02B, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C02C, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C02D, .hex); -pub const TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C02E, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C02F, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C030, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C031, .hex); -pub const TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300C032, .hex); -pub const TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300CCA8, .hex); -pub const TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300CCA9, .hex); -pub const TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x0300CCAC, .hex); -pub const TLS1_3_CK_AES_128_GCM_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03001301, .hex); -pub const TLS1_3_CK_AES_256_GCM_SHA384 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03001302, .hex); -pub const TLS1_3_CK_CHACHA20_POLY1305_SHA256 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0x03001303, .hex); -pub const TLS1_CK_AES_128_GCM_SHA256 = TLS1_3_CK_AES_128_GCM_SHA256; -pub const TLS1_CK_AES_256_GCM_SHA384 = TLS1_3_CK_AES_256_GCM_SHA384; -pub const TLS1_CK_CHACHA20_POLY1305_SHA256 = TLS1_3_CK_CHACHA20_POLY1305_SHA256; -pub const TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 = "EXP1024-RC4-MD5"; -pub const TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 = "EXP1024-RC2-CBC-MD5"; -pub const TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA = "EXP1024-DES-CBC-SHA"; -pub const TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA = "EXP1024-DHE-DSS-DES-CBC-SHA"; -pub const TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA = "EXP1024-RC4-SHA"; -pub const TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA = "EXP1024-DHE-DSS-RC4-SHA"; -pub const TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA = "DHE-DSS-RC4-SHA"; -pub const TLS1_TXT_RSA_WITH_AES_128_SHA = "AES128-SHA"; -pub const TLS1_TXT_DH_DSS_WITH_AES_128_SHA = "DH-DSS-AES128-SHA"; -pub const TLS1_TXT_DH_RSA_WITH_AES_128_SHA = "DH-RSA-AES128-SHA"; -pub const TLS1_TXT_DHE_DSS_WITH_AES_128_SHA = "DHE-DSS-AES128-SHA"; -pub const TLS1_TXT_DHE_RSA_WITH_AES_128_SHA = "DHE-RSA-AES128-SHA"; -pub const TLS1_TXT_ADH_WITH_AES_128_SHA = "ADH-AES128-SHA"; -pub const TLS1_TXT_RSA_WITH_AES_256_SHA = "AES256-SHA"; -pub const TLS1_TXT_DH_DSS_WITH_AES_256_SHA = "DH-DSS-AES256-SHA"; -pub const TLS1_TXT_DH_RSA_WITH_AES_256_SHA = "DH-RSA-AES256-SHA"; -pub const TLS1_TXT_DHE_DSS_WITH_AES_256_SHA = "DHE-DSS-AES256-SHA"; -pub const TLS1_TXT_DHE_RSA_WITH_AES_256_SHA = "DHE-RSA-AES256-SHA"; -pub const TLS1_TXT_ADH_WITH_AES_256_SHA = "ADH-AES256-SHA"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA = "ECDH-ECDSA-NULL-SHA"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA = "ECDH-ECDSA-RC4-SHA"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA = "ECDH-ECDSA-DES-CBC3-SHA"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA = "ECDH-ECDSA-AES128-SHA"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA = "ECDH-ECDSA-AES256-SHA"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA = "ECDHE-ECDSA-NULL-SHA"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA = "ECDHE-ECDSA-RC4-SHA"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA = "ECDHE-ECDSA-DES-CBC3-SHA"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = "ECDHE-ECDSA-AES128-SHA"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = "ECDHE-ECDSA-AES256-SHA"; -pub const TLS1_TXT_ECDH_RSA_WITH_NULL_SHA = "ECDH-RSA-NULL-SHA"; -pub const TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA = "ECDH-RSA-RC4-SHA"; -pub const TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA = "ECDH-RSA-DES-CBC3-SHA"; -pub const TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA = "ECDH-RSA-AES128-SHA"; -pub const TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA = "ECDH-RSA-AES256-SHA"; -pub const TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA = "ECDHE-RSA-NULL-SHA"; -pub const TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA = "ECDHE-RSA-RC4-SHA"; -pub const TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA = "ECDHE-RSA-DES-CBC3-SHA"; -pub const TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA = "ECDHE-RSA-AES128-SHA"; -pub const TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA = "ECDHE-RSA-AES256-SHA"; -pub const TLS1_TXT_ECDH_anon_WITH_NULL_SHA = "AECDH-NULL-SHA"; -pub const TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA = "AECDH-RC4-SHA"; -pub const TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA = "AECDH-DES-CBC3-SHA"; -pub const TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA = "AECDH-AES128-SHA"; -pub const TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA = "AECDH-AES256-SHA"; -pub const TLS1_TXT_PSK_WITH_RC4_128_SHA = "PSK-RC4-SHA"; -pub const TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA = "PSK-3DES-EDE-CBC-SHA"; -pub const TLS1_TXT_PSK_WITH_AES_128_CBC_SHA = "PSK-AES128-CBC-SHA"; -pub const TLS1_TXT_PSK_WITH_AES_256_CBC_SHA = "PSK-AES256-CBC-SHA"; -pub const TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA = "ECDHE-PSK-AES128-CBC-SHA"; -pub const TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA = "ECDHE-PSK-AES256-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA = "SRP-3DES-EDE-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = "SRP-RSA-3DES-EDE-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = "SRP-DSS-3DES-EDE-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA = "SRP-AES-128-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = "SRP-RSA-AES-128-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = "SRP-DSS-AES-128-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA = "SRP-AES-256-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = "SRP-RSA-AES-256-CBC-SHA"; -pub const TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = "SRP-DSS-AES-256-CBC-SHA"; -pub const TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA = "CAMELLIA128-SHA"; -pub const TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA = "DH-DSS-CAMELLIA128-SHA"; -pub const TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA = "DH-RSA-CAMELLIA128-SHA"; -pub const TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA = "DHE-DSS-CAMELLIA128-SHA"; -pub const TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA = "DHE-RSA-CAMELLIA128-SHA"; -pub const TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA = "ADH-CAMELLIA128-SHA"; -pub const TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA = "CAMELLIA256-SHA"; -pub const TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA = "DH-DSS-CAMELLIA256-SHA"; -pub const TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA = "DH-RSA-CAMELLIA256-SHA"; -pub const TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA = "DHE-DSS-CAMELLIA256-SHA"; -pub const TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA = "DHE-RSA-CAMELLIA256-SHA"; -pub const TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA = "ADH-CAMELLIA256-SHA"; -pub const TLS1_TXT_RSA_WITH_SEED_SHA = "SEED-SHA"; -pub const TLS1_TXT_DH_DSS_WITH_SEED_SHA = "DH-DSS-SEED-SHA"; -pub const TLS1_TXT_DH_RSA_WITH_SEED_SHA = "DH-RSA-SEED-SHA"; -pub const TLS1_TXT_DHE_DSS_WITH_SEED_SHA = "DHE-DSS-SEED-SHA"; -pub const TLS1_TXT_DHE_RSA_WITH_SEED_SHA = "DHE-RSA-SEED-SHA"; -pub const TLS1_TXT_ADH_WITH_SEED_SHA = "ADH-SEED-SHA"; -pub const TLS1_TXT_RSA_WITH_NULL_SHA256 = "NULL-SHA256"; -pub const TLS1_TXT_RSA_WITH_AES_128_SHA256 = "AES128-SHA256"; -pub const TLS1_TXT_RSA_WITH_AES_256_SHA256 = "AES256-SHA256"; -pub const TLS1_TXT_DH_DSS_WITH_AES_128_SHA256 = "DH-DSS-AES128-SHA256"; -pub const TLS1_TXT_DH_RSA_WITH_AES_128_SHA256 = "DH-RSA-AES128-SHA256"; -pub const TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256 = "DHE-DSS-AES128-SHA256"; -pub const TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 = "DHE-RSA-AES128-SHA256"; -pub const TLS1_TXT_DH_DSS_WITH_AES_256_SHA256 = "DH-DSS-AES256-SHA256"; -pub const TLS1_TXT_DH_RSA_WITH_AES_256_SHA256 = "DH-RSA-AES256-SHA256"; -pub const TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256 = "DHE-DSS-AES256-SHA256"; -pub const TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 = "DHE-RSA-AES256-SHA256"; -pub const TLS1_TXT_ADH_WITH_AES_128_SHA256 = "ADH-AES128-SHA256"; -pub const TLS1_TXT_ADH_WITH_AES_256_SHA256 = "ADH-AES256-SHA256"; -pub const TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 = "AES128-GCM-SHA256"; -pub const TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 = "AES256-GCM-SHA384"; -pub const TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 = "DHE-RSA-AES128-GCM-SHA256"; -pub const TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 = "DHE-RSA-AES256-GCM-SHA384"; -pub const TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256 = "DH-RSA-AES128-GCM-SHA256"; -pub const TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384 = "DH-RSA-AES256-GCM-SHA384"; -pub const TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256 = "DHE-DSS-AES128-GCM-SHA256"; -pub const TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384 = "DHE-DSS-AES256-GCM-SHA384"; -pub const TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256 = "DH-DSS-AES128-GCM-SHA256"; -pub const TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384 = "DH-DSS-AES256-GCM-SHA384"; -pub const TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256 = "ADH-AES128-GCM-SHA256"; -pub const TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384 = "ADH-AES256-GCM-SHA384"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256 = "ECDHE-ECDSA-AES128-SHA256"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384 = "ECDHE-ECDSA-AES256-SHA384"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256 = "ECDH-ECDSA-AES128-SHA256"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384 = "ECDH-ECDSA-AES256-SHA384"; -pub const TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 = "ECDHE-RSA-AES128-SHA256"; -pub const TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 = "ECDHE-RSA-AES256-SHA384"; -pub const TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256 = "ECDH-RSA-AES128-SHA256"; -pub const TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384 = "ECDH-RSA-AES256-SHA384"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = "ECDHE-ECDSA-AES128-GCM-SHA256"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = "ECDHE-ECDSA-AES256-GCM-SHA384"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 = "ECDH-ECDSA-AES128-GCM-SHA256"; -pub const TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 = "ECDH-ECDSA-AES256-GCM-SHA384"; -pub const TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = "ECDHE-RSA-AES128-GCM-SHA256"; -pub const TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = "ECDHE-RSA-AES256-GCM-SHA384"; -pub const TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256 = "ECDH-RSA-AES128-GCM-SHA256"; -pub const TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384 = "ECDH-RSA-AES256-GCM-SHA384"; -pub const TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = "ECDHE-RSA-CHACHA20-POLY1305"; -pub const TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = "ECDHE-ECDSA-CHACHA20-POLY1305"; -pub const TLS1_TXT_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 = "ECDHE-PSK-CHACHA20-POLY1305"; -pub const TLS1_3_RFC_AES_128_GCM_SHA256 = "TLS_AES_128_GCM_SHA256"; -pub const TLS1_3_RFC_AES_256_GCM_SHA384 = "TLS_AES_256_GCM_SHA384"; -pub const TLS1_3_RFC_CHACHA20_POLY1305_SHA256 = "TLS_CHACHA20_POLY1305_SHA256"; -pub const TLS1_TXT_AES_128_GCM_SHA256 = TLS1_3_RFC_AES_128_GCM_SHA256; -pub const TLS1_TXT_AES_256_GCM_SHA384 = TLS1_3_RFC_AES_256_GCM_SHA384; -pub const TLS1_TXT_CHACHA20_POLY1305_SHA256 = TLS1_3_RFC_CHACHA20_POLY1305_SHA256; -pub const TLS_CT_RSA_SIGN = @as(c_int, 1); -pub const TLS_CT_DSS_SIGN = @as(c_int, 2); -pub const TLS_CT_RSA_FIXED_DH = @as(c_int, 3); -pub const TLS_CT_DSS_FIXED_DH = @as(c_int, 4); -pub const TLS_CT_ECDSA_SIGN = @as(c_int, 64); -pub const TLS_CT_RSA_FIXED_ECDH = @as(c_int, 65); -pub const TLS_CT_ECDSA_FIXED_ECDH = @as(c_int, 66); -pub const TLS_MD_MAX_CONST_SIZE = @as(c_int, 20); -pub const _SYS_TIME_H_ = ""; -pub const _STRUCT_TIMEVAL64 = ""; -pub const ITIMER_REAL = @as(c_int, 0); -pub const ITIMER_VIRTUAL = @as(c_int, 1); -pub const ITIMER_PROF = @as(c_int, 2); -pub const DST_NONE = @as(c_int, 0); -pub const DST_USA = @as(c_int, 1); -pub const DST_AUST = @as(c_int, 2); -pub const DST_WET = @as(c_int, 3); -pub const DST_MET = @as(c_int, 4); -pub const DST_EET = @as(c_int, 5); -pub const DST_CAN = @as(c_int, 6); -pub inline fn timerisset(tvp: anytype) @TypeOf((tvp.*.tv_sec != 0) or (tvp.*.tv_usec != 0)) { - return (tvp.*.tv_sec != 0) or (tvp.*.tv_usec != 0); -} -pub inline fn timevalcmp(l: anytype, r: anytype, cmp: anytype) @TypeOf(timercmp(l, r, cmp)) { - return timercmp(l, r, cmp); -} -pub const _SYS__SELECT_H_ = ""; -pub const OPENSSL_HEADER_HMAC_H = ""; -pub const SSL_KEY_UPDATE_REQUESTED = @as(c_int, 1); -pub const SSL_KEY_UPDATE_NOT_REQUESTED = @as(c_int, 0); -pub const SSL_ERROR_NONE = @as(c_int, 0); -pub const SSL_ERROR_SSL = @as(c_int, 1); -pub const SSL_ERROR_WANT_READ = @as(c_int, 2); -pub const SSL_ERROR_WANT_WRITE = @as(c_int, 3); -pub const SSL_ERROR_WANT_X509_LOOKUP = @as(c_int, 4); -pub const SSL_ERROR_SYSCALL = @as(c_int, 5); -pub const SSL_ERROR_ZERO_RETURN = @as(c_int, 6); -pub const SSL_ERROR_WANT_CONNECT = @as(c_int, 7); -pub const SSL_ERROR_WANT_ACCEPT = @as(c_int, 8); -pub const SSL_ERROR_WANT_CHANNEL_ID_LOOKUP = @as(c_int, 9); -pub const SSL_ERROR_PENDING_SESSION = @as(c_int, 11); -pub const SSL_ERROR_PENDING_CERTIFICATE = @as(c_int, 12); -pub const SSL_ERROR_WANT_PRIVATE_KEY_OPERATION = @as(c_int, 13); -pub const SSL_ERROR_PENDING_TICKET = @as(c_int, 14); -pub const SSL_ERROR_EARLY_DATA_REJECTED = @as(c_int, 15); -pub const SSL_ERROR_WANT_CERTIFICATE_VERIFY = @as(c_int, 16); -pub const SSL_ERROR_HANDOFF = @as(c_int, 17); -pub const SSL_ERROR_HANDBACK = @as(c_int, 18); -pub const SSL_ERROR_WANT_RENEGOTIATE = @as(c_int, 19); -pub const SSL_ERROR_HANDSHAKE_HINTS_READY = @as(c_int, 20); -pub const DTLS1_VERSION_MAJOR = @as(c_int, 0xfe); -pub const SSL3_VERSION_MAJOR = @as(c_int, 0x03); -pub const SSL3_VERSION = @as(c_int, 0x0300); -pub const TLS1_VERSION = @as(c_int, 0x0301); -pub const TLS1_1_VERSION = @as(c_int, 0x0302); -pub const TLS1_2_VERSION = @as(c_int, 0x0303); -pub const TLS1_3_VERSION = @as(c_int, 0x0304); -pub const DTLS1_VERSION = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xfeff, .hex); -pub const DTLS1_2_VERSION = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xfefd, .hex); -pub const SSL_OP_NO_QUERY_MTU = @as(c_long, 0x00001000); -pub const SSL_OP_NO_TICKET = @as(c_long, 0x00004000); -pub const SSL_OP_CIPHER_SERVER_PREFERENCE = @as(c_long, 0x00400000); -pub const SSL_OP_NO_TLSv1 = @as(c_long, 0x04000000); -pub const SSL_OP_NO_TLSv1_2 = @as(c_long, 0x08000000); -pub const SSL_OP_NO_TLSv1_1 = @as(c_long, 0x10000000); -pub const SSL_OP_NO_TLSv1_3 = @as(c_long, 0x20000000); -pub const SSL_OP_NO_DTLSv1 = SSL_OP_NO_TLSv1; -pub const SSL_OP_NO_DTLSv1_2 = SSL_OP_NO_TLSv1_2; -pub const SSL_MODE_ENABLE_PARTIAL_WRITE = @as(c_long, 0x00000001); -pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = @as(c_long, 0x00000002); -pub const SSL_MODE_NO_AUTO_CHAIN = @as(c_long, 0x00000008); -pub const SSL_MODE_ENABLE_FALSE_START = @as(c_long, 0x00000080); -pub const SSL_MODE_CBC_RECORD_SPLITTING = @as(c_long, 0x00000100); -pub const SSL_MODE_NO_SESSION_CREATION = @as(c_long, 0x00000200); -pub const SSL_MODE_SEND_FALLBACK_SCSV = @as(c_long, 0x00000400); -pub const SSL_SIGN_RSA_PKCS1_SHA1 = @as(c_int, 0x0201); -pub const SSL_SIGN_RSA_PKCS1_SHA256 = @as(c_int, 0x0401); -pub const SSL_SIGN_RSA_PKCS1_SHA384 = @as(c_int, 0x0501); -pub const SSL_SIGN_RSA_PKCS1_SHA512 = @as(c_int, 0x0601); -pub const SSL_SIGN_ECDSA_SHA1 = @as(c_int, 0x0203); -pub const SSL_SIGN_ECDSA_SECP256R1_SHA256 = @as(c_int, 0x0403); -pub const SSL_SIGN_ECDSA_SECP384R1_SHA384 = @as(c_int, 0x0503); -pub const SSL_SIGN_ECDSA_SECP521R1_SHA512 = @as(c_int, 0x0603); -pub const SSL_SIGN_RSA_PSS_RSAE_SHA256 = @as(c_int, 0x0804); -pub const SSL_SIGN_RSA_PSS_RSAE_SHA384 = @as(c_int, 0x0805); -pub const SSL_SIGN_RSA_PSS_RSAE_SHA512 = @as(c_int, 0x0806); -pub const SSL_SIGN_ED25519 = @as(c_int, 0x0807); -pub const SSL_SIGN_RSA_PKCS1_MD5_SHA1 = @import("std").zig.c_translation.promoteIntLiteral(c_int, 0xff01, .hex); -pub const SSL_FILETYPE_PEM = @as(c_int, 1); -pub const SSL_FILETYPE_ASN1 = @as(c_int, 2); -pub const SSL_DEFAULT_CIPHER_LIST = "ALL"; -pub const SSL_MAX_SSL_SESSION_ID_LENGTH = @as(c_int, 32); -pub const SSL_MAX_MASTER_KEY_LENGTH = @as(c_int, 48); -pub const SSL_SESS_CACHE_OFF = @as(c_int, 0x0000); -pub const SSL_SESS_CACHE_CLIENT = @as(c_int, 0x0001); -pub const SSL_SESS_CACHE_SERVER = @as(c_int, 0x0002); -pub const SSL_SESS_CACHE_BOTH = SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_SERVER; -pub const SSL_SESS_CACHE_NO_AUTO_CLEAR = @as(c_int, 0x0080); -pub const SSL_SESS_CACHE_NO_INTERNAL_LOOKUP = @as(c_int, 0x0100); -pub const SSL_SESS_CACHE_NO_INTERNAL_STORE = @as(c_int, 0x0200); -pub const SSL_SESS_CACHE_NO_INTERNAL = SSL_SESS_CACHE_NO_INTERNAL_LOOKUP | SSL_SESS_CACHE_NO_INTERNAL_STORE; -pub const SSL_DEFAULT_SESSION_TIMEOUT = (@as(c_int, 2) * @as(c_int, 60)) * @as(c_int, 60); -pub const SSL_DEFAULT_SESSION_PSK_DHE_TIMEOUT = ((@as(c_int, 2) * @as(c_int, 24)) * @as(c_int, 60)) * @as(c_int, 60); -pub const SSL_DEFAULT_SESSION_AUTH_TIMEOUT = ((@as(c_int, 7) * @as(c_int, 24)) * @as(c_int, 60)) * @as(c_int, 60); -pub const SSL_MAX_SID_CTX_LENGTH = @as(c_int, 32); -pub const SSL_SESSION_CACHE_MAX_SIZE_DEFAULT = @as(c_int, 1024) * @as(c_int, 20); -pub const SSL_DEFAULT_TICKET_KEY_ROTATION_INTERVAL = ((@as(c_int, 2) * @as(c_int, 24)) * @as(c_int, 60)) * @as(c_int, 60); -pub const SSL_TICKET_KEY_NAME_LEN = @as(c_int, 16); -pub const SSL_CURVE_SECP224R1 = @as(c_int, 21); -pub const SSL_CURVE_SECP256R1 = @as(c_int, 23); -pub const SSL_CURVE_SECP384R1 = @as(c_int, 24); -pub const SSL_CURVE_SECP521R1 = @as(c_int, 25); -pub const SSL_CURVE_X25519 = @as(c_int, 29); -pub const SSL_CURVE_CECPQ2 = @as(c_int, 16696); -pub const SSL_VERIFY_NONE = @as(c_int, 0x00); -pub const SSL_VERIFY_PEER = @as(c_int, 0x01); -pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT = @as(c_int, 0x02); -pub const SSL_VERIFY_PEER_IF_NO_OBC = @as(c_int, 0x04); -pub const TLSEXT_NAMETYPE_host_name = @as(c_int, 0); -pub const SSL_TLSEXT_ERR_OK = @as(c_int, 0); -pub const SSL_TLSEXT_ERR_ALERT_WARNING = @as(c_int, 1); -pub const SSL_TLSEXT_ERR_ALERT_FATAL = @as(c_int, 2); -pub const SSL_TLSEXT_ERR_NOACK = @as(c_int, 3); -pub const OPENSSL_NPN_UNSUPPORTED = @as(c_int, 0); -pub const OPENSSL_NPN_NEGOTIATED = @as(c_int, 1); -pub const OPENSSL_NPN_NO_OVERLAP = @as(c_int, 2); -pub const SRTP_AES128_CM_SHA1_80 = @as(c_int, 0x0001); -pub const SRTP_AES128_CM_SHA1_32 = @as(c_int, 0x0002); -pub const SRTP_AES128_F8_SHA1_80 = @as(c_int, 0x0003); -pub const SRTP_AES128_F8_SHA1_32 = @as(c_int, 0x0004); -pub const SRTP_NULL_SHA1_80 = @as(c_int, 0x0005); -pub const SRTP_NULL_SHA1_32 = @as(c_int, 0x0006); -pub const SRTP_AEAD_AES_128_GCM = @as(c_int, 0x0007); -pub const SRTP_AEAD_AES_256_GCM = @as(c_int, 0x0008); -pub const PSK_MAX_IDENTITY_LEN = @as(c_int, 128); -pub const PSK_MAX_PSK_LEN = @as(c_int, 256); -pub const SSL_AD_REASON_OFFSET = @as(c_int, 1000); -pub const SSL_AD_CLOSE_NOTIFY = SSL3_AD_CLOSE_NOTIFY; -pub const SSL_AD_UNEXPECTED_MESSAGE = SSL3_AD_UNEXPECTED_MESSAGE; -pub const SSL_AD_BAD_RECORD_MAC = SSL3_AD_BAD_RECORD_MAC; -pub const SSL_AD_DECRYPTION_FAILED = TLS1_AD_DECRYPTION_FAILED; -pub const SSL_AD_RECORD_OVERFLOW = TLS1_AD_RECORD_OVERFLOW; -pub const SSL_AD_DECOMPRESSION_FAILURE = SSL3_AD_DECOMPRESSION_FAILURE; -pub const SSL_AD_HANDSHAKE_FAILURE = SSL3_AD_HANDSHAKE_FAILURE; -pub const SSL_AD_NO_CERTIFICATE = SSL3_AD_NO_CERTIFICATE; -pub const SSL_AD_BAD_CERTIFICATE = SSL3_AD_BAD_CERTIFICATE; -pub const SSL_AD_UNSUPPORTED_CERTIFICATE = SSL3_AD_UNSUPPORTED_CERTIFICATE; -pub const SSL_AD_CERTIFICATE_REVOKED = SSL3_AD_CERTIFICATE_REVOKED; -pub const SSL_AD_CERTIFICATE_EXPIRED = SSL3_AD_CERTIFICATE_EXPIRED; -pub const SSL_AD_CERTIFICATE_UNKNOWN = SSL3_AD_CERTIFICATE_UNKNOWN; -pub const SSL_AD_ILLEGAL_PARAMETER = SSL3_AD_ILLEGAL_PARAMETER; -pub const SSL_AD_UNKNOWN_CA = TLS1_AD_UNKNOWN_CA; -pub const SSL_AD_ACCESS_DENIED = TLS1_AD_ACCESS_DENIED; -pub const SSL_AD_DECODE_ERROR = TLS1_AD_DECODE_ERROR; -pub const SSL_AD_DECRYPT_ERROR = TLS1_AD_DECRYPT_ERROR; -pub const SSL_AD_EXPORT_RESTRICTION = TLS1_AD_EXPORT_RESTRICTION; -pub const SSL_AD_PROTOCOL_VERSION = TLS1_AD_PROTOCOL_VERSION; -pub const SSL_AD_INSUFFICIENT_SECURITY = TLS1_AD_INSUFFICIENT_SECURITY; -pub const SSL_AD_INTERNAL_ERROR = TLS1_AD_INTERNAL_ERROR; -pub const SSL_AD_INAPPROPRIATE_FALLBACK = SSL3_AD_INAPPROPRIATE_FALLBACK; -pub const SSL_AD_USER_CANCELLED = TLS1_AD_USER_CANCELLED; -pub const SSL_AD_NO_RENEGOTIATION = TLS1_AD_NO_RENEGOTIATION; -pub const SSL_AD_MISSING_EXTENSION = TLS1_AD_MISSING_EXTENSION; -pub const SSL_AD_UNSUPPORTED_EXTENSION = TLS1_AD_UNSUPPORTED_EXTENSION; -pub const SSL_AD_CERTIFICATE_UNOBTAINABLE = TLS1_AD_CERTIFICATE_UNOBTAINABLE; -pub const SSL_AD_UNRECOGNIZED_NAME = TLS1_AD_UNRECOGNIZED_NAME; -pub const SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE = TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE; -pub const SSL_AD_BAD_CERTIFICATE_HASH_VALUE = TLS1_AD_BAD_CERTIFICATE_HASH_VALUE; -pub const SSL_AD_UNKNOWN_PSK_IDENTITY = TLS1_AD_UNKNOWN_PSK_IDENTITY; -pub const SSL_AD_CERTIFICATE_REQUIRED = TLS1_AD_CERTIFICATE_REQUIRED; -pub const SSL_AD_NO_APPLICATION_PROTOCOL = TLS1_AD_NO_APPLICATION_PROTOCOL; -pub const SSL_AD_ECH_REQUIRED = TLS1_AD_ECH_REQUIRED; -pub const SSL_MAX_CERT_LIST_DEFAULT = @as(c_int, 1024) * @as(c_int, 100); -pub const SSL_ST_CONNECT = @as(c_int, 0x1000); -pub const SSL_ST_ACCEPT = @as(c_int, 0x2000); -pub const SSL_ST_MASK = @as(c_int, 0x0FFF); -pub const SSL_ST_INIT = SSL_ST_CONNECT | SSL_ST_ACCEPT; -pub const SSL_ST_OK = @as(c_int, 0x03); -pub const SSL_ST_RENEGOTIATE = @as(c_int, 0x04) | SSL_ST_INIT; -pub const SSL_ST_BEFORE = @as(c_int, 0x05) | SSL_ST_INIT; -pub const TLS_ST_OK = SSL_ST_OK; -pub const TLS_ST_BEFORE = SSL_ST_BEFORE; -pub const SSL_CB_LOOP = @as(c_int, 0x01); -pub const SSL_CB_EXIT = @as(c_int, 0x02); -pub const SSL_CB_READ = @as(c_int, 0x04); -pub const SSL_CB_WRITE = @as(c_int, 0x08); -pub const SSL_CB_ALERT = @as(c_int, 0x4000); -pub const SSL_CB_READ_ALERT = SSL_CB_ALERT | SSL_CB_READ; -pub const SSL_CB_WRITE_ALERT = SSL_CB_ALERT | SSL_CB_WRITE; -pub const SSL_CB_ACCEPT_LOOP = SSL_ST_ACCEPT | SSL_CB_LOOP; -pub const SSL_CB_ACCEPT_EXIT = SSL_ST_ACCEPT | SSL_CB_EXIT; -pub const SSL_CB_CONNECT_LOOP = SSL_ST_CONNECT | SSL_CB_LOOP; -pub const SSL_CB_CONNECT_EXIT = SSL_ST_CONNECT | SSL_CB_EXIT; -pub const SSL_CB_HANDSHAKE_START = @as(c_int, 0x10); -pub const SSL_CB_HANDSHAKE_DONE = @as(c_int, 0x20); -pub const SSL_SENT_SHUTDOWN = @as(c_int, 1); -pub const SSL_RECEIVED_SHUTDOWN = @as(c_int, 2); -pub const SSL_MODE_HANDSHAKE_CUTTHROUGH = SSL_MODE_ENABLE_FALSE_START; -pub inline fn SSL_set_app_data(s: anytype, arg: anytype) @TypeOf(SSL_set_ex_data(s, @as(c_int, 0), @import("std").zig.c_translation.cast([*c]u8, arg))) { - return SSL_set_ex_data(s, @as(c_int, 0), @import("std").zig.c_translation.cast([*c]u8, arg)); -} -pub inline fn SSL_get_app_data(s: anytype) @TypeOf(SSL_get_ex_data(s, @as(c_int, 0))) { - return SSL_get_ex_data(s, @as(c_int, 0)); -} -pub inline fn SSL_SESSION_set_app_data(s: anytype, a: anytype) @TypeOf(SSL_SESSION_set_ex_data(s, @as(c_int, 0), @import("std").zig.c_translation.cast([*c]u8, a))) { - return SSL_SESSION_set_ex_data(s, @as(c_int, 0), @import("std").zig.c_translation.cast([*c]u8, a)); -} -pub inline fn SSL_SESSION_get_app_data(s: anytype) @TypeOf(SSL_SESSION_get_ex_data(s, @as(c_int, 0))) { - return SSL_SESSION_get_ex_data(s, @as(c_int, 0)); -} -pub inline fn SSL_CTX_get_app_data(ctx: anytype) @TypeOf(SSL_CTX_get_ex_data(ctx, @as(c_int, 0))) { - return SSL_CTX_get_ex_data(ctx, @as(c_int, 0)); -} -pub inline fn SSL_CTX_set_app_data(ctx: anytype, arg: anytype) @TypeOf(SSL_CTX_set_ex_data(ctx, @as(c_int, 0), @import("std").zig.c_translation.cast([*c]u8, arg))) { - return SSL_CTX_set_ex_data(ctx, @as(c_int, 0), @import("std").zig.c_translation.cast([*c]u8, arg)); -} -pub inline fn OpenSSL_add_ssl_algorithms() @TypeOf(SSL_library_init()) { - return SSL_library_init(); -} -pub inline fn SSLeay_add_ssl_algorithms() @TypeOf(SSL_library_init()) { - return SSL_library_init(); -} -pub inline fn SSL_get_cipher(ssl: anytype) @TypeOf(SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))) { - return SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)); -} -pub inline fn SSL_get_cipher_bits(ssl: anytype, out_alg_bits: anytype) @TypeOf(SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), out_alg_bits)) { - return SSL_CIPHER_get_bits(SSL_get_current_cipher(ssl), out_alg_bits); -} -pub inline fn SSL_get_cipher_version(ssl: anytype) @TypeOf(SSL_CIPHER_get_version(SSL_get_current_cipher(ssl))) { - return SSL_CIPHER_get_version(SSL_get_current_cipher(ssl)); -} -pub inline fn SSL_get_cipher_name(ssl: anytype) @TypeOf(SSL_CIPHER_get_name(SSL_get_current_cipher(ssl))) { - return SSL_CIPHER_get_name(SSL_get_current_cipher(ssl)); -} -pub inline fn SSL_get_time(session: anytype) @TypeOf(SSL_SESSION_get_time(session)) { - return SSL_SESSION_get_time(session); -} -pub inline fn SSL_set_time(session: anytype, time_1: anytype) @TypeOf(SSL_SESSION_set_time(session, time_1)) { - return SSL_SESSION_set_time(session, time_1); -} -pub inline fn SSL_get_timeout(session: anytype) @TypeOf(SSL_SESSION_get_timeout(session)) { - return SSL_SESSION_get_timeout(session); -} -pub inline fn SSL_set_timeout(session: anytype, timeout: anytype) @TypeOf(SSL_SESSION_set_timeout(session, timeout)) { - return SSL_SESSION_set_timeout(session, timeout); -} -pub const SSL_MODE_AUTO_RETRY = @as(c_int, 0); -pub const SSL_MODE_RELEASE_BUFFERS = @as(c_int, 0); -pub const SSL_MODE_SEND_CLIENTHELLO_TIME = @as(c_int, 0); -pub const SSL_MODE_SEND_SERVERHELLO_TIME = @as(c_int, 0); -pub const SSL_OP_ALL = @as(c_int, 0); -pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = @as(c_int, 0); -pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = @as(c_int, 0); -pub const SSL_OP_EPHEMERAL_RSA = @as(c_int, 0); -pub const SSL_OP_LEGACY_SERVER_CONNECT = @as(c_int, 0); -pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = @as(c_int, 0); -pub const SSL_OP_MICROSOFT_SESS_ID_BUG = @as(c_int, 0); -pub const SSL_OP_MSIE_SSLV2_RSA_PADDING = @as(c_int, 0); -pub const SSL_OP_NETSCAPE_CA_DN_BUG = @as(c_int, 0); -pub const SSL_OP_NETSCAPE_CHALLENGE_BUG = @as(c_int, 0); -pub const SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = @as(c_int, 0); -pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = @as(c_int, 0); -pub const SSL_OP_NO_COMPRESSION = @as(c_int, 0); -pub const SSL_OP_NO_RENEGOTIATION = @as(c_int, 0); -pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = @as(c_int, 0); -pub const SSL_OP_NO_SSLv2 = @as(c_int, 0); -pub const SSL_OP_NO_SSLv3 = @as(c_int, 0); -pub const SSL_OP_PKCS1_CHECK_1 = @as(c_int, 0); -pub const SSL_OP_PKCS1_CHECK_2 = @as(c_int, 0); -pub const SSL_OP_SINGLE_DH_USE = @as(c_int, 0); -pub const SSL_OP_SINGLE_ECDH_USE = @as(c_int, 0); -pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = @as(c_int, 0); -pub const SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = @as(c_int, 0); -pub const SSL_OP_TLS_BLOCK_PADDING_BUG = @as(c_int, 0); -pub const SSL_OP_TLS_D5_BUG = @as(c_int, 0); -pub const SSL_OP_TLS_ROLLBACK_BUG = @as(c_int, 0); -pub const SSL_VERIFY_CLIENT_ONCE = @as(c_int, 0); -pub const SSL_NOTHING = SSL_ERROR_NONE; -pub const SSL_WRITING = SSL_ERROR_WANT_WRITE; -pub const SSL_READING = SSL_ERROR_WANT_READ; -pub inline fn SSL_want_read(ssl: anytype) @TypeOf(SSL_want(ssl) == SSL_READING) { - return SSL_want(ssl) == SSL_READING; -} -pub inline fn SSL_want_write(ssl: anytype) @TypeOf(SSL_want(ssl) == SSL_WRITING) { - return SSL_want(ssl) == SSL_WRITING; -} -pub const SSL_TXT_MEDIUM = "MEDIUM"; -pub const SSL_TXT_HIGH = "HIGH"; -pub const SSL_TXT_FIPS = "FIPS"; -pub const SSL_TXT_kRSA = "kRSA"; -pub const SSL_TXT_kDHE = "kDHE"; -pub const SSL_TXT_kEDH = "kEDH"; -pub const SSL_TXT_kECDHE = "kECDHE"; -pub const SSL_TXT_kEECDH = "kEECDH"; -pub const SSL_TXT_kPSK = "kPSK"; -pub const SSL_TXT_aRSA = "aRSA"; -pub const SSL_TXT_aECDSA = "aECDSA"; -pub const SSL_TXT_aPSK = "aPSK"; -pub const SSL_TXT_DH = "DH"; -pub const SSL_TXT_DHE = "DHE"; -pub const SSL_TXT_EDH = "EDH"; -pub const SSL_TXT_RSA = "RSA"; -pub const SSL_TXT_ECDH = "ECDH"; -pub const SSL_TXT_ECDHE = "ECDHE"; -pub const SSL_TXT_EECDH = "EECDH"; -pub const SSL_TXT_ECDSA = "ECDSA"; -pub const SSL_TXT_PSK = "PSK"; -pub const SSL_TXT_3DES = "3DES"; -pub const SSL_TXT_RC4 = "RC4"; -pub const SSL_TXT_AES128 = "AES128"; -pub const SSL_TXT_AES256 = "AES256"; -pub const SSL_TXT_AES = "AES"; -pub const SSL_TXT_AES_GCM = "AESGCM"; -pub const SSL_TXT_CHACHA20 = "CHACHA20"; -pub const SSL_TXT_MD5 = "MD5"; -pub const SSL_TXT_SHA1 = "SHA1"; -pub const SSL_TXT_SHA = "SHA"; -pub const SSL_TXT_SHA256 = "SHA256"; -pub const SSL_TXT_SHA384 = "SHA384"; -pub const SSL_TXT_SSLV3 = "SSLv3"; -pub const SSL_TXT_TLSV1 = "TLSv1"; -pub const SSL_TXT_TLSV1_1 = "TLSv1.1"; -pub const SSL_TXT_TLSV1_2 = "TLSv1.2"; -pub const SSL_TXT_TLSV1_3 = "TLSv1.3"; -pub const SSL_TXT_ALL = "ALL"; -pub const SSL_TXT_CMPDEF = "COMPLEMENTOFDEFAULT"; -pub inline fn SSL_get_state(ssl: anytype) @TypeOf(SSL_state(ssl)) { - return SSL_state(ssl); -} -pub inline fn SSL_CTX_set_ecdh_auto(ctx: anytype, onoff: anytype) @TypeOf(@as(c_int, 1)) { - _ = @TypeOf(ctx); - _ = @TypeOf(onoff); - return @as(c_int, 1); -} -pub inline fn SSL_set_ecdh_auto(ssl: anytype, onoff: anytype) @TypeOf(@as(c_int, 1)) { - _ = @TypeOf(ssl); - _ = @TypeOf(onoff); - return @as(c_int, 1); -} -pub const SSL_get0_session = SSL_get_session; -pub const OPENSSL_INIT_NO_LOAD_SSL_STRINGS = @as(c_int, 0); -pub const OPENSSL_INIT_LOAD_SSL_STRINGS = @as(c_int, 0); -pub const OPENSSL_INIT_SSL_DEFAULT = @as(c_int, 0); -pub const SSL_SIGN_RSA_PSS_SHA256 = SSL_SIGN_RSA_PSS_RSAE_SHA256; -pub const SSL_SIGN_RSA_PSS_SHA384 = SSL_SIGN_RSA_PSS_RSAE_SHA384; -pub const SSL_SIGN_RSA_PSS_SHA512 = SSL_SIGN_RSA_PSS_RSAE_SHA512; -pub const SSL_R_TLSV1_UNSUPPORTED_EXTENSION = SSL_R_TLSV1_ALERT_UNSUPPORTED_EXTENSION; -pub const SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE = SSL_R_TLSV1_ALERT_CERTIFICATE_UNOBTAINABLE; -pub const SSL_R_TLSV1_UNRECOGNIZED_NAME = SSL_R_TLSV1_ALERT_UNRECOGNIZED_NAME; -pub const SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE = SSL_R_TLSV1_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE; -pub const SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE = SSL_R_TLSV1_ALERT_BAD_CERTIFICATE_HASH_VALUE; -pub const SSL_R_TLSV1_CERTIFICATE_REQUIRED = SSL_R_TLSV1_ALERT_CERTIFICATE_REQUIRED; -pub const SSL_R_APP_DATA_IN_HANDSHAKE = @as(c_int, 100); -pub const SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT = @as(c_int, 101); -pub const SSL_R_BAD_ALERT = @as(c_int, 102); -pub const SSL_R_BAD_CHANGE_CIPHER_SPEC = @as(c_int, 103); -pub const SSL_R_BAD_DATA_RETURNED_BY_CALLBACK = @as(c_int, 104); -pub const SSL_R_BAD_DH_P_LENGTH = @as(c_int, 105); -pub const SSL_R_BAD_DIGEST_LENGTH = @as(c_int, 106); -pub const SSL_R_BAD_ECC_CERT = @as(c_int, 107); -pub const SSL_R_BAD_ECPOINT = @as(c_int, 108); -pub const SSL_R_BAD_HANDSHAKE_RECORD = @as(c_int, 109); -pub const SSL_R_BAD_HELLO_REQUEST = @as(c_int, 110); -pub const SSL_R_BAD_LENGTH = @as(c_int, 111); -pub const SSL_R_BAD_PACKET_LENGTH = @as(c_int, 112); -pub const SSL_R_BAD_RSA_ENCRYPT = @as(c_int, 113); -pub const SSL_R_BAD_SIGNATURE = @as(c_int, 114); -pub const SSL_R_BAD_SRTP_MKI_VALUE = @as(c_int, 115); -pub const SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST = @as(c_int, 116); -pub const SSL_R_BAD_SSL_FILETYPE = @as(c_int, 117); -pub const SSL_R_BAD_WRITE_RETRY = @as(c_int, 118); -pub const SSL_R_BIO_NOT_SET = @as(c_int, 119); -pub const SSL_R_BN_LIB = @as(c_int, 120); -pub const SSL_R_BUFFER_TOO_SMALL = @as(c_int, 121); -pub const SSL_R_CA_DN_LENGTH_MISMATCH = @as(c_int, 122); -pub const SSL_R_CA_DN_TOO_LONG = @as(c_int, 123); -pub const SSL_R_CCS_RECEIVED_EARLY = @as(c_int, 124); -pub const SSL_R_CERTIFICATE_VERIFY_FAILED = @as(c_int, 125); -pub const SSL_R_CERT_CB_ERROR = @as(c_int, 126); -pub const SSL_R_CERT_LENGTH_MISMATCH = @as(c_int, 127); -pub const SSL_R_CHANNEL_ID_NOT_P256 = @as(c_int, 128); -pub const SSL_R_CHANNEL_ID_SIGNATURE_INVALID = @as(c_int, 129); -pub const SSL_R_CIPHER_OR_HASH_UNAVAILABLE = @as(c_int, 130); -pub const SSL_R_CLIENTHELLO_PARSE_FAILED = @as(c_int, 131); -pub const SSL_R_CLIENTHELLO_TLSEXT = @as(c_int, 132); -pub const SSL_R_CONNECTION_REJECTED = @as(c_int, 133); -pub const SSL_R_CONNECTION_TYPE_NOT_SET = @as(c_int, 134); -pub const SSL_R_CUSTOM_EXTENSION_ERROR = @as(c_int, 135); -pub const SSL_R_DATA_LENGTH_TOO_LONG = @as(c_int, 136); -pub const SSL_R_DECODE_ERROR = @as(c_int, 137); -pub const SSL_R_DECRYPTION_FAILED = @as(c_int, 138); -pub const SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC = @as(c_int, 139); -pub const SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG = @as(c_int, 140); -pub const SSL_R_DH_P_TOO_LONG = @as(c_int, 141); -pub const SSL_R_DIGEST_CHECK_FAILED = @as(c_int, 142); -pub const SSL_R_DTLS_MESSAGE_TOO_BIG = @as(c_int, 143); -pub const SSL_R_ECC_CERT_NOT_FOR_SIGNING = @as(c_int, 144); -pub const SSL_R_EMS_STATE_INCONSISTENT = @as(c_int, 145); -pub const SSL_R_ENCRYPTED_LENGTH_TOO_LONG = @as(c_int, 146); -pub const SSL_R_ERROR_ADDING_EXTENSION = @as(c_int, 147); -pub const SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST = @as(c_int, 148); -pub const SSL_R_ERROR_PARSING_EXTENSION = @as(c_int, 149); -pub const SSL_R_EXCESSIVE_MESSAGE_SIZE = @as(c_int, 150); -pub const SSL_R_EXTRA_DATA_IN_MESSAGE = @as(c_int, 151); -pub const SSL_R_FRAGMENT_MISMATCH = @as(c_int, 152); -pub const SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION = @as(c_int, 153); -pub const SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO = @as(c_int, 154); -pub const SSL_R_HTTPS_PROXY_REQUEST = @as(c_int, 155); -pub const SSL_R_HTTP_REQUEST = @as(c_int, 156); -pub const SSL_R_INAPPROPRIATE_FALLBACK = @as(c_int, 157); -pub const SSL_R_INVALID_COMMAND = @as(c_int, 158); -pub const SSL_R_INVALID_MESSAGE = @as(c_int, 159); -pub const SSL_R_INVALID_SSL_SESSION = @as(c_int, 160); -pub const SSL_R_INVALID_TICKET_KEYS_LENGTH = @as(c_int, 161); -pub const SSL_R_LENGTH_MISMATCH = @as(c_int, 162); -pub const SSL_R_MISSING_EXTENSION = @as(c_int, 164); -pub const SSL_R_MISSING_RSA_CERTIFICATE = @as(c_int, 165); -pub const SSL_R_MISSING_TMP_DH_KEY = @as(c_int, 166); -pub const SSL_R_MISSING_TMP_ECDH_KEY = @as(c_int, 167); -pub const SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS = @as(c_int, 168); -pub const SSL_R_MTU_TOO_SMALL = @as(c_int, 169); -pub const SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN = @as(c_int, 170); -pub const SSL_R_NESTED_GROUP = @as(c_int, 171); -pub const SSL_R_NO_CERTIFICATES_RETURNED = @as(c_int, 172); -pub const SSL_R_NO_CERTIFICATE_ASSIGNED = @as(c_int, 173); -pub const SSL_R_NO_CERTIFICATE_SET = @as(c_int, 174); -pub const SSL_R_NO_CIPHERS_AVAILABLE = @as(c_int, 175); -pub const SSL_R_NO_CIPHERS_PASSED = @as(c_int, 176); -pub const SSL_R_NO_CIPHER_MATCH = @as(c_int, 177); -pub const SSL_R_NO_COMPRESSION_SPECIFIED = @as(c_int, 178); -pub const SSL_R_NO_METHOD_SPECIFIED = @as(c_int, 179); -pub const SSL_R_NO_P256_SUPPORT = @as(c_int, 180); -pub const SSL_R_NO_PRIVATE_KEY_ASSIGNED = @as(c_int, 181); -pub const SSL_R_NO_RENEGOTIATION = @as(c_int, 182); -pub const SSL_R_NO_REQUIRED_DIGEST = @as(c_int, 183); -pub const SSL_R_NO_SHARED_CIPHER = @as(c_int, 184); -pub const SSL_R_NULL_SSL_CTX = @as(c_int, 185); -pub const SSL_R_NULL_SSL_METHOD_PASSED = @as(c_int, 186); -pub const SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED = @as(c_int, 187); -pub const SSL_R_OLD_SESSION_VERSION_NOT_RETURNED = @as(c_int, 188); -pub const SSL_R_OUTPUT_ALIASES_INPUT = @as(c_int, 189); -pub const SSL_R_PARSE_TLSEXT = @as(c_int, 190); -pub const SSL_R_PATH_TOO_LONG = @as(c_int, 191); -pub const SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE = @as(c_int, 192); -pub const SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE = @as(c_int, 193); -pub const SSL_R_PROTOCOL_IS_SHUTDOWN = @as(c_int, 194); -pub const SSL_R_PSK_IDENTITY_NOT_FOUND = @as(c_int, 195); -pub const SSL_R_PSK_NO_CLIENT_CB = @as(c_int, 196); -pub const SSL_R_PSK_NO_SERVER_CB = @as(c_int, 197); -pub const SSL_R_READ_TIMEOUT_EXPIRED = @as(c_int, 198); -pub const SSL_R_RECORD_LENGTH_MISMATCH = @as(c_int, 199); -pub const SSL_R_RECORD_TOO_LARGE = @as(c_int, 200); -pub const SSL_R_RENEGOTIATION_ENCODING_ERR = @as(c_int, 201); -pub const SSL_R_RENEGOTIATION_MISMATCH = @as(c_int, 202); -pub const SSL_R_REQUIRED_CIPHER_MISSING = @as(c_int, 203); -pub const SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION = @as(c_int, 204); -pub const SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION = @as(c_int, 205); -pub const SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING = @as(c_int, 206); -pub const SSL_R_SERVERHELLO_TLSEXT = @as(c_int, 207); -pub const SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED = @as(c_int, 208); -pub const SSL_R_SESSION_MAY_NOT_BE_CREATED = @as(c_int, 209); -pub const SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER = @as(c_int, 210); -pub const SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES = @as(c_int, 211); -pub const SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE = @as(c_int, 212); -pub const SSL_R_SSL3_EXT_INVALID_SERVERNAME = @as(c_int, 213); -pub const SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION = @as(c_int, 214); -pub const SSL_R_SSL_HANDSHAKE_FAILURE = @as(c_int, 215); -pub const SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG = @as(c_int, 216); -pub const SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST = @as(c_int, 217); -pub const SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG = @as(c_int, 218); -pub const SSL_R_TOO_MANY_EMPTY_FRAGMENTS = @as(c_int, 219); -pub const SSL_R_TOO_MANY_WARNING_ALERTS = @as(c_int, 220); -pub const SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS = @as(c_int, 221); -pub const SSL_R_UNEXPECTED_EXTENSION = @as(c_int, 222); -pub const SSL_R_UNEXPECTED_MESSAGE = @as(c_int, 223); -pub const SSL_R_UNEXPECTED_OPERATOR_IN_GROUP = @as(c_int, 224); -pub const SSL_R_UNEXPECTED_RECORD = @as(c_int, 225); -pub const SSL_R_UNINITIALIZED = @as(c_int, 226); -pub const SSL_R_UNKNOWN_ALERT_TYPE = @as(c_int, 227); -pub const SSL_R_UNKNOWN_CERTIFICATE_TYPE = @as(c_int, 228); -pub const SSL_R_UNKNOWN_CIPHER_RETURNED = @as(c_int, 229); -pub const SSL_R_UNKNOWN_CIPHER_TYPE = @as(c_int, 230); -pub const SSL_R_UNKNOWN_DIGEST = @as(c_int, 231); -pub const SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE = @as(c_int, 232); -pub const SSL_R_UNKNOWN_PROTOCOL = @as(c_int, 233); -pub const SSL_R_UNKNOWN_SSL_VERSION = @as(c_int, 234); -pub const SSL_R_UNKNOWN_STATE = @as(c_int, 235); -pub const SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED = @as(c_int, 236); -pub const SSL_R_UNSUPPORTED_CIPHER = @as(c_int, 237); -pub const SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM = @as(c_int, 238); -pub const SSL_R_UNSUPPORTED_ELLIPTIC_CURVE = @as(c_int, 239); -pub const SSL_R_UNSUPPORTED_PROTOCOL = @as(c_int, 240); -pub const SSL_R_WRONG_CERTIFICATE_TYPE = @as(c_int, 241); -pub const SSL_R_WRONG_CIPHER_RETURNED = @as(c_int, 242); -pub const SSL_R_WRONG_CURVE = @as(c_int, 243); -pub const SSL_R_WRONG_MESSAGE_TYPE = @as(c_int, 244); -pub const SSL_R_WRONG_SIGNATURE_TYPE = @as(c_int, 245); -pub const SSL_R_WRONG_SSL_VERSION = @as(c_int, 246); -pub const SSL_R_WRONG_VERSION_NUMBER = @as(c_int, 247); -pub const SSL_R_X509_LIB = @as(c_int, 248); -pub const SSL_R_X509_VERIFICATION_SETUP_PROBLEMS = @as(c_int, 249); -pub const SSL_R_SHUTDOWN_WHILE_IN_INIT = @as(c_int, 250); -pub const SSL_R_INVALID_OUTER_RECORD_TYPE = @as(c_int, 251); -pub const SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY = @as(c_int, 252); -pub const SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS = @as(c_int, 253); -pub const SSL_R_DOWNGRADE_DETECTED = @as(c_int, 254); -pub const SSL_R_EXCESS_HANDSHAKE_DATA = @as(c_int, 255); -pub const SSL_R_INVALID_COMPRESSION_LIST = @as(c_int, 256); -pub const SSL_R_DUPLICATE_EXTENSION = @as(c_int, 257); -pub const SSL_R_MISSING_KEY_SHARE = @as(c_int, 258); -pub const SSL_R_INVALID_ALPN_PROTOCOL = @as(c_int, 259); -pub const SSL_R_TOO_MANY_KEY_UPDATES = @as(c_int, 260); -pub const SSL_R_BLOCK_CIPHER_PAD_IS_WRONG = @as(c_int, 261); -pub const SSL_R_NO_CIPHERS_SPECIFIED = @as(c_int, 262); -pub const SSL_R_RENEGOTIATION_EMS_MISMATCH = @as(c_int, 263); -pub const SSL_R_DUPLICATE_KEY_SHARE = @as(c_int, 264); -pub const SSL_R_NO_GROUPS_SPECIFIED = @as(c_int, 265); -pub const SSL_R_NO_SHARED_GROUP = @as(c_int, 266); -pub const SSL_R_PRE_SHARED_KEY_MUST_BE_LAST = @as(c_int, 267); -pub const SSL_R_OLD_SESSION_PRF_HASH_MISMATCH = @as(c_int, 268); -pub const SSL_R_INVALID_SCT_LIST = @as(c_int, 269); -pub const SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA = @as(c_int, 270); -pub const SSL_R_PSK_IDENTITY_BINDER_COUNT_MISMATCH = @as(c_int, 271); -pub const SSL_R_CANNOT_PARSE_LEAF_CERT = @as(c_int, 272); -pub const SSL_R_SERVER_CERT_CHANGED = @as(c_int, 273); -pub const SSL_R_CERTIFICATE_AND_PRIVATE_KEY_MISMATCH = @as(c_int, 274); -pub const SSL_R_CANNOT_HAVE_BOTH_PRIVKEY_AND_METHOD = @as(c_int, 275); -pub const SSL_R_TICKET_ENCRYPTION_FAILED = @as(c_int, 276); -pub const SSL_R_ALPN_MISMATCH_ON_EARLY_DATA = @as(c_int, 277); -pub const SSL_R_WRONG_VERSION_ON_EARLY_DATA = @as(c_int, 278); -pub const SSL_R_UNEXPECTED_EXTENSION_ON_EARLY_DATA = @as(c_int, 279); -pub const SSL_R_NO_SUPPORTED_VERSIONS_ENABLED = @as(c_int, 280); -pub const SSL_R_APPLICATION_DATA_INSTEAD_OF_HANDSHAKE = @as(c_int, 281); -pub const SSL_R_EMPTY_HELLO_RETRY_REQUEST = @as(c_int, 282); -pub const SSL_R_EARLY_DATA_NOT_IN_USE = @as(c_int, 283); -pub const SSL_R_HANDSHAKE_NOT_COMPLETE = @as(c_int, 284); -pub const SSL_R_NEGOTIATED_TB_WITHOUT_EMS_OR_RI = @as(c_int, 285); -pub const SSL_R_SERVER_ECHOED_INVALID_SESSION_ID = @as(c_int, 286); -pub const SSL_R_PRIVATE_KEY_OPERATION_FAILED = @as(c_int, 287); -pub const SSL_R_SECOND_SERVERHELLO_VERSION_MISMATCH = @as(c_int, 288); -pub const SSL_R_OCSP_CB_ERROR = @as(c_int, 289); -pub const SSL_R_SSL_SESSION_ID_TOO_LONG = @as(c_int, 290); -pub const SSL_R_APPLICATION_DATA_ON_SHUTDOWN = @as(c_int, 291); -pub const SSL_R_CERT_DECOMPRESSION_FAILED = @as(c_int, 292); -pub const SSL_R_UNCOMPRESSED_CERT_TOO_LARGE = @as(c_int, 293); -pub const SSL_R_UNKNOWN_CERT_COMPRESSION_ALG = @as(c_int, 294); -pub const SSL_R_INVALID_SIGNATURE_ALGORITHM = @as(c_int, 295); -pub const SSL_R_DUPLICATE_SIGNATURE_ALGORITHM = @as(c_int, 296); -pub const SSL_R_TLS13_DOWNGRADE = @as(c_int, 297); -pub const SSL_R_QUIC_INTERNAL_ERROR = @as(c_int, 298); -pub const SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED = @as(c_int, 299); -pub const SSL_R_TOO_MUCH_READ_EARLY_DATA = @as(c_int, 300); -pub const SSL_R_INVALID_DELEGATED_CREDENTIAL = @as(c_int, 301); -pub const SSL_R_KEY_USAGE_BIT_INCORRECT = @as(c_int, 302); -pub const SSL_R_INCONSISTENT_CLIENT_HELLO = @as(c_int, 303); -pub const SSL_R_CIPHER_MISMATCH_ON_EARLY_DATA = @as(c_int, 304); -pub const SSL_R_QUIC_TRANSPORT_PARAMETERS_MISCONFIGURED = @as(c_int, 305); -pub const SSL_R_UNEXPECTED_COMPATIBILITY_MODE = @as(c_int, 306); -pub const SSL_R_NO_APPLICATION_PROTOCOL = @as(c_int, 307); -pub const SSL_R_NEGOTIATED_ALPS_WITHOUT_ALPN = @as(c_int, 308); -pub const SSL_R_ALPS_MISMATCH_ON_EARLY_DATA = @as(c_int, 309); -pub const SSL_R_ECH_SERVER_CONFIG_AND_PRIVATE_KEY_MISMATCH = @as(c_int, 310); -pub const SSL_R_ECH_SERVER_CONFIG_UNSUPPORTED_EXTENSION = @as(c_int, 311); -pub const SSL_R_UNSUPPORTED_ECH_SERVER_CONFIG = @as(c_int, 312); -pub const SSL_R_ECH_SERVER_WOULD_HAVE_NO_RETRY_CONFIGS = @as(c_int, 313); -pub const SSL_R_INVALID_CLIENT_HELLO_INNER = @as(c_int, 314); -pub const SSL_R_INVALID_ALPN_PROTOCOL_LIST = @as(c_int, 315); -pub const SSL_R_COULD_NOT_PARSE_HINTS = @as(c_int, 316); -pub const SSL_R_INVALID_ECH_PUBLIC_NAME = @as(c_int, 317); -pub const SSL_R_INVALID_ECH_CONFIG_LIST = @as(c_int, 318); -pub const SSL_R_ECH_REJECTED = @as(c_int, 319); -pub const SSL_R_INVALID_OUTER_EXTENSION = @as(c_int, 320); -pub const SSL_R_INCONSISTENT_ECH_NEGOTIATION = @as(c_int, 321); -pub const SSL_R_SSLV3_ALERT_CLOSE_NOTIFY = @as(c_int, 1000); -pub const SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE = @as(c_int, 1010); -pub const SSL_R_SSLV3_ALERT_BAD_RECORD_MAC = @as(c_int, 1020); -pub const SSL_R_TLSV1_ALERT_DECRYPTION_FAILED = @as(c_int, 1021); -pub const SSL_R_TLSV1_ALERT_RECORD_OVERFLOW = @as(c_int, 1022); -pub const SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE = @as(c_int, 1030); -pub const SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE = @as(c_int, 1040); -pub const SSL_R_SSLV3_ALERT_NO_CERTIFICATE = @as(c_int, 1041); -pub const SSL_R_SSLV3_ALERT_BAD_CERTIFICATE = @as(c_int, 1042); -pub const SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE = @as(c_int, 1043); -pub const SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED = @as(c_int, 1044); -pub const SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED = @as(c_int, 1045); -pub const SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN = @as(c_int, 1046); -pub const SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER = @as(c_int, 1047); -pub const SSL_R_TLSV1_ALERT_UNKNOWN_CA = @as(c_int, 1048); -pub const SSL_R_TLSV1_ALERT_ACCESS_DENIED = @as(c_int, 1049); -pub const SSL_R_TLSV1_ALERT_DECODE_ERROR = @as(c_int, 1050); -pub const SSL_R_TLSV1_ALERT_DECRYPT_ERROR = @as(c_int, 1051); -pub const SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION = @as(c_int, 1060); -pub const SSL_R_TLSV1_ALERT_PROTOCOL_VERSION = @as(c_int, 1070); -pub const SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY = @as(c_int, 1071); -pub const SSL_R_TLSV1_ALERT_INTERNAL_ERROR = @as(c_int, 1080); -pub const SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK = @as(c_int, 1086); -pub const SSL_R_TLSV1_ALERT_USER_CANCELLED = @as(c_int, 1090); -pub const SSL_R_TLSV1_ALERT_NO_RENEGOTIATION = @as(c_int, 1100); -pub const SSL_R_TLSV1_ALERT_UNSUPPORTED_EXTENSION = @as(c_int, 1110); -pub const SSL_R_TLSV1_ALERT_CERTIFICATE_UNOBTAINABLE = @as(c_int, 1111); -pub const SSL_R_TLSV1_ALERT_UNRECOGNIZED_NAME = @as(c_int, 1112); -pub const SSL_R_TLSV1_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE = @as(c_int, 1113); -pub const SSL_R_TLSV1_ALERT_BAD_CERTIFICATE_HASH_VALUE = @as(c_int, 1114); -pub const SSL_R_TLSV1_ALERT_UNKNOWN_PSK_IDENTITY = @as(c_int, 1115); -pub const SSL_R_TLSV1_ALERT_CERTIFICATE_REQUIRED = @as(c_int, 1116); -pub const SSL_R_TLSV1_ALERT_NO_APPLICATION_PROTOCOL = @as(c_int, 1120); -pub const SSL_R_TLSV1_ALERT_ECH_REQUIRED = @as(c_int, 1121); -pub const asn1_null_st = struct_asn1_null_st; -pub const ASN1_ITEM_st = struct_ASN1_ITEM_st; -pub const asn1_object_st = struct_asn1_object_st; -pub const asn1_pctx_st = struct_asn1_pctx_st; -pub const asn1_string_st = struct_asn1_string_st; -pub const ASN1_VALUE_st = struct_ASN1_VALUE_st; -pub const asn1_type_st = struct_asn1_type_st; -pub const AUTHORITY_KEYID_st = struct_AUTHORITY_KEYID_st; -pub const BASIC_CONSTRAINTS_st = struct_BASIC_CONSTRAINTS_st; -pub const DIST_POINT_st = struct_DIST_POINT_st; -pub const bignum_st = struct_bignum_st; -pub const DSA_SIG_st = struct_DSA_SIG_st; -pub const ISSUING_DIST_POINT_st = struct_ISSUING_DIST_POINT_st; -pub const NAME_CONSTRAINTS_st = struct_NAME_CONSTRAINTS_st; -pub const X509_pubkey_st = struct_X509_pubkey_st; -pub const Netscape_spkac_st = struct_Netscape_spkac_st; -pub const X509_algor_st = struct_X509_algor_st; -pub const Netscape_spki_st = struct_Netscape_spki_st; -pub const RIPEMD160state_st = struct_RIPEMD160state_st; -pub const X509_VERIFY_PARAM_st = struct_X509_VERIFY_PARAM_st; -pub const X509_crl_st = struct_X509_crl_st; -pub const X509_extension_st = struct_X509_extension_st; -pub const x509_st = struct_x509_st; -pub const openssl_method_common_st = struct_openssl_method_common_st; -pub const rsa_meth_st = struct_rsa_meth_st; -pub const stack_st_void = struct_stack_st_void; -pub const crypto_ex_data_st = struct_crypto_ex_data_st; -pub const bn_mont_ctx_st = struct_bn_mont_ctx_st; -pub const bn_blinding_st = struct_bn_blinding_st; -pub const rsa_st = struct_rsa_st; -pub const dsa_st = struct_dsa_st; -pub const dh_st = struct_dh_st; -pub const ec_key_st = struct_ec_key_st; -pub const evp_pkey_asn1_method_st = struct_evp_pkey_asn1_method_st; -pub const evp_pkey_st = struct_evp_pkey_st; -pub const evp_cipher_st = struct_evp_cipher_st; -pub const evp_cipher_info_st = struct_evp_cipher_info_st; -pub const private_key_st = struct_private_key_st; -pub const X509_info_st = struct_X509_info_st; -pub const X509_name_entry_st = struct_X509_name_entry_st; -pub const X509_name_st = struct_X509_name_st; -pub const X509_req_st = struct_X509_req_st; -pub const X509_sig_st = struct_X509_sig_st; -pub const bignum_ctx = struct_bignum_ctx; -pub const bio_st = struct_bio_st; -pub const bio_method_st = struct_bio_method_st; -pub const blake2b_state_st = struct_blake2b_state_st; -pub const bn_gencb_st = struct_bn_gencb_st; -pub const buf_mem_st = struct_buf_mem_st; -pub const cbb_buffer_st = struct_cbb_buffer_st; -pub const cbb_child_st = struct_cbb_child_st; -pub const cbb_st = struct_cbb_st; -pub const cbs_st = struct_cbs_st; -pub const cmac_ctx_st = struct_cmac_ctx_st; -pub const conf_st = struct_conf_st; -pub const conf_value_st = struct_conf_value_st; -pub const crypto_buffer_pool_st = struct_crypto_buffer_pool_st; -pub const crypto_buffer_st = struct_crypto_buffer_st; -pub const ctr_drbg_state_st = struct_ctr_drbg_state_st; -pub const ec_group_st = struct_ec_group_st; -pub const ec_point_st = struct_ec_point_st; -pub const ecdsa_method_st = struct_ecdsa_method_st; -pub const ecdsa_sig_st = struct_ecdsa_sig_st; -pub const engine_st = struct_engine_st; -pub const env_md_st = struct_env_md_st; -pub const evp_pkey_ctx_st = struct_evp_pkey_ctx_st; -pub const evp_md_pctx_ops = struct_evp_md_pctx_ops; -pub const env_md_ctx_st = struct_env_md_ctx_st; -pub const evp_aead_st = struct_evp_aead_st; -pub const evp_aead_ctx_st_state = union_evp_aead_ctx_st_state; -pub const evp_aead_ctx_st = struct_evp_aead_ctx_st; -pub const evp_cipher_ctx_st = struct_evp_cipher_ctx_st; -pub const evp_encode_ctx_st = struct_evp_encode_ctx_st; -pub const evp_hpke_aead_st = struct_evp_hpke_aead_st; -pub const evp_hpke_ctx_st = struct_evp_hpke_ctx_st; -pub const evp_hpke_kdf_st = struct_evp_hpke_kdf_st; -pub const evp_hpke_kem_st = struct_evp_hpke_kem_st; -pub const evp_hpke_key_st = struct_evp_hpke_key_st; -pub const evp_pkey_method_st = struct_evp_pkey_method_st; -pub const hmac_ctx_st = struct_hmac_ctx_st; -pub const md4_state_st = struct_md4_state_st; -pub const md5_state_st = struct_md5_state_st; -pub const ossl_init_settings_st = struct_ossl_init_settings_st; -pub const pkcs12_st = struct_pkcs12_st; -pub const pkcs8_priv_key_info_st = struct_pkcs8_priv_key_info_st; -pub const rand_meth_st = struct_rand_meth_st; -pub const rc4_key_st = struct_rc4_key_st; -pub const rsa_pss_params_st = struct_rsa_pss_params_st; -pub const sha256_state_st = struct_sha256_state_st; -pub const sha512_state_st = struct_sha512_state_st; -pub const sha_state_st = struct_sha_state_st; -pub const spake2_ctx_st = struct_spake2_ctx_st; -pub const srtp_protection_profile_st = struct_srtp_protection_profile_st; -pub const ssl_cipher_st = struct_ssl_cipher_st; -// pub const ssl_ctx_st = struct_ssl_ctx_st; -// pub const ssl_st = struct_ssl_st; -pub const ssl_early_callback_ctx = struct_ssl_early_callback_ctx; -pub const ssl_ech_keys_st = struct_ssl_ech_keys_st; -pub const ssl_method_st = struct_ssl_method_st; -pub const ssl_private_key_result_t = enum_ssl_private_key_result_t; -pub const ssl_private_key_method_st = struct_ssl_private_key_method_st; -pub const ssl_encryption_level_t = enum_ssl_encryption_level_t; -pub const ssl_quic_method_st = struct_ssl_quic_method_st; -pub const ssl_session_st = struct_ssl_session_st; -pub const ssl_ticket_aead_result_t = enum_ssl_ticket_aead_result_t; -pub const ssl_ticket_aead_method_st = struct_ssl_ticket_aead_method_st; -pub const st_ERR_FNS = struct_st_ERR_FNS; -pub const trust_token_st = struct_trust_token_st; -pub const trust_token_client_st = struct_trust_token_client_st; -pub const trust_token_issuer_st = struct_trust_token_issuer_st; -pub const trust_token_method_st = struct_trust_token_method_st; -pub const v3_ext_ctx = struct_v3_ext_ctx; -pub const x509_attributes_st = struct_x509_attributes_st; -pub const x509_lookup_st = struct_x509_lookup_st; -pub const x509_lookup_method_st = struct_x509_lookup_method_st; -pub const x509_object_st = struct_x509_object_st; -pub const x509_revoked_st = struct_x509_revoked_st; -pub const x509_store_ctx_st = struct_x509_store_ctx_st; -pub const x509_store_st = struct_x509_store_st; -pub const x509_trust_st = struct_x509_trust_st; -pub const __sbuf = struct___sbuf; -pub const stack_st = struct_stack_st; -pub const stack_st_OPENSSL_STRING = struct_stack_st_OPENSSL_STRING; -pub const CRYPTO_dynlock_value = struct_CRYPTO_dynlock_value; -pub const stack_st_BIO = struct_stack_st_BIO; -pub const evp_aead_direction_t = enum_evp_aead_direction_t; -pub const stack_st_CRYPTO_BUFFER = struct_stack_st_CRYPTO_BUFFER; -pub const stack_st_X509 = struct_stack_st_X509; -pub const stack_st_X509_CRL = struct_stack_st_X509_CRL; -pub const timespec = struct_timespec; -pub const tm = struct_tm; -pub const bn_primality_result_t = enum_bn_primality_result_t; -pub const stack_st_ASN1_INTEGER = struct_stack_st_ASN1_INTEGER; -pub const stack_st_ASN1_OBJECT = struct_stack_st_ASN1_OBJECT; -pub const stack_st_ASN1_TYPE = struct_stack_st_ASN1_TYPE; -pub const ec_method_st = struct_ec_method_st; -pub const obj_name_st = struct_obj_name_st; -pub const stack_st_X509_EXTENSION = struct_stack_st_X509_EXTENSION; -pub const stack_st_X509_REVOKED = struct_stack_st_X509_REVOKED; -pub const stack_st_X509_NAME_ENTRY = struct_stack_st_X509_NAME_ENTRY; -pub const stack_st_X509_NAME = struct_stack_st_X509_NAME; -pub const stack_st_X509_ALGOR = struct_stack_st_X509_ALGOR; -pub const stack_st_X509_ATTRIBUTE = struct_stack_st_X509_ATTRIBUTE; -pub const stack_st_DIST_POINT = struct_stack_st_DIST_POINT; -pub const stack_st_GENERAL_NAME = struct_stack_st_GENERAL_NAME; -pub const stack_st_X509_TRUST = struct_stack_st_X509_TRUST; -pub const stack_st_GENERAL_NAMES = struct_stack_st_GENERAL_NAMES; -pub const AUTHORITY_INFO_ACCESS = struct_stack_st_ACCESS_DESCRIPTION; -pub const stack_st_X509_INFO = struct_stack_st_X509_INFO; -pub const stack_st_X509_LOOKUP = struct_stack_st_X509_LOOKUP; -pub const stack_st_X509_OBJECT = struct_stack_st_X509_OBJECT; -pub const stack_st_X509_VERIFY_PARAM = struct_stack_st_X509_VERIFY_PARAM; -pub const fips_counter_t = enum_fips_counter_t; -pub const stack_st_SSL_CIPHER = struct_stack_st_SSL_CIPHER; -pub const ssl_verify_result_t = enum_ssl_verify_result_t; -pub const stack_st_SRTP_PROTECTION_PROFILE = struct_stack_st_SRTP_PROTECTION_PROFILE; -pub const ssl_early_data_reason_t = enum_ssl_early_data_reason_t; -pub const ssl_renegotiate_mode_t = enum_ssl_renegotiate_mode_t; -pub const ssl_select_cert_result_t = enum_ssl_select_cert_result_t; -pub const ssl_comp_st = struct_ssl_comp_st; -pub const stack_st_SSL_COMP = struct_stack_st_SSL_COMP; -pub const ssl_conf_ctx_st = struct_ssl_conf_ctx_st; -pub const ssl_compliance_policy_t = enum_ssl_compliance_policy_t; - -pub extern fn RAND_bytes(buf: [*]u8, len: usize) c_int; - -/// RAND_enable_fork_unsafe_buffering enables efficient buffered reading of -/// /dev/urandom. It adds an overhead of a few KB of memory per thread. It must -/// be called before the first call to |RAND_bytes|. -/// -/// |fd| must be -1. We no longer support setting the file descriptor with this -/// function. -/// -/// It has an unusual name because the buffer is unsafe across calls to |fork|. -/// Hence, this function should never be called by libraries. -pub extern fn RAND_enable_fork_unsafe_buffering(c_int) void; - -pub extern fn SSL_new(ctx: ?*SSL_CTX) ?*SSL; - -pub extern fn EVP_md4() *const EVP_MD; -pub extern fn EVP_md5() *const EVP_MD; -pub extern fn EVP_sha1() *const EVP_MD; -pub extern fn EVP_sha224() *const EVP_MD; -pub extern fn EVP_sha256() *const EVP_MD; -pub extern fn EVP_sha384() *const EVP_MD; -pub extern fn EVP_sha512() *const EVP_MD; -pub extern fn EVP_sha512_224() *const EVP_MD; -pub extern fn EVP_sha512_256() *const EVP_MD; -pub extern fn EVP_sha3_224() *const EVP_MD; -pub extern fn EVP_sha3_256() *const EVP_MD; -pub extern fn EVP_sha3_384() *const EVP_MD; -pub extern fn EVP_sha3_512() *const EVP_MD; - -pub extern fn EVP_blake2b256() *const EVP_MD; -pub extern fn EVP_blake2b512() *const EVP_MD; - -pub extern fn ERR_clear_error() void; -pub extern fn ERR_set_mark() c_int; -pub extern fn ERR_pop_to_mark() c_int; -pub extern fn ERR_get_next_error_library() c_int; - -pub const struct_bio_st = extern struct { - method: [*c]const BIO_METHOD, - _init: c_int, - shutdown: c_int, - flags: c_int, - retry_reason: c_int, - num: c_int, - references: CRYPTO_refcount_t, - ptr: ?*anyopaque, - next_bio: ?*BIO, - num_read: usize, - num_write: usize, - - pub fn isEmpty(this: *struct_bio_st) bool { - return BIO_eof(this) > 0; - } - - pub fn init() !*struct_bio_st { - return BIO_new(BIO_s_mem()) orelse error.OutOfMemory; - } - - /// Create a read-only `BIO` using an existing buffer. `buffer` is not - /// copied, and ownership is not transfered. - /// - /// `buffer` must outlive the returned `BIO`. - /// - /// Returns an error if - /// - the buffer is empty - /// - BIO initialization fails (same as `.init()`). - pub fn initReadonlyView(buffer: []const u8) !*struct_bio_st { - // NOTE: not exposing len parameter. If we want to ignore their - // suggestion and pass a negative value to make it treat `buffer` as a - // null-terminated string, create a separate `initReadonlyViewZ` - // constructor. - return BIO_new_mem_buf(buffer.ptr, buffer.len); - } - - pub fn deinit(this: *struct_bio_st) void { - _ = BIO_free(this); - } - - pub fn slice(this: *struct_bio_st) []u8 { - var buf_mem: ?*BUF_MEM = null; - bun.assert(BIO_get_mem_ptr(this, &buf_mem) > -1); - if (buf_mem) |buf| { - if (buf.data == null) return &[_]u8{}; - - return buf.data[0..buf.length]; - } - - return &[_]u8{}; - } - - pub fn pending(this: *const struct_bio_st) usize { - return BIO_ctrl_pending(this); - } - - pub fn write(this: *struct_bio_st, buffer: []const u8) !usize { - const rc = BIO_write(this, buffer.ptr, @as(c_int, @intCast(buffer.len))); - - return if (rc > -1) - return @as(usize, @intCast(rc)) - else - return error.Fail; - } - - pub fn read(this: *struct_bio_st, buffer: []u8) !usize { - const rc = BIO_read(this, buffer.ptr, @as(c_int, @intCast(buffer.len))); - return if (rc > -1) - return @as(usize, @intCast(rc)) - else - return error.Fail; - } -}; - -pub const CertError = error{ - OK, - UNABLE_TO_GET_ISSUER_CERT, - UNABLE_TO_GET_CRL, - UNABLE_TO_DECRYPT_CERT_SIGNATURE, - UNABLE_TO_DECRYPT_CRL_SIGNATURE, - UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, - CERT_SIGNATURE_FAILURE, - CRL_SIGNATURE_FAILURE, - CERT_NOT_YET_VALID, - CRL_NOT_YET_VALID, - CERT_HAS_EXPIRED, - CRL_HAS_EXPIRED, - ERROR_IN_CERT_NOT_BEFORE_FIELD, - ERROR_IN_CERT_NOT_AFTER_FIELD, - ERROR_IN_CRL_LAST_UPDATE_FIELD, - ERROR_IN_CRL_NEXT_UPDATE_FIELD, - OUT_OF_MEM, - DEPTH_ZERO_SELF_SIGNED_CERT, - SELF_SIGNED_CERT_IN_CHAIN, - UNABLE_TO_GET_ISSUER_CERT_LOCALLY, - UNABLE_TO_VERIFY_LEAF_SIGNATURE, - CERT_CHAIN_TOO_LONG, - CERT_REVOKED, - INVALID_CA, - INVALID_NON_CA, - PATH_LENGTH_EXCEEDED, - PROXY_PATH_LENGTH_EXCEEDED, - PROXY_CERTIFICATES_NOT_ALLOWED, - INVALID_PURPOSE, - CERT_UNTRUSTED, - CERT_REJECTED, - APPLICATION_VERIFICATION, - SUBJECT_ISSUER_MISMATCH, - AKID_SKID_MISMATCH, - AKID_ISSUER_SERIAL_MISMATCH, - KEYUSAGE_NO_CERTSIGN, - UNABLE_TO_GET_CRL_ISSUER, - UNHANDLED_CRITICAL_EXTENSION, - KEYUSAGE_NO_CRL_SIGN, - KEYUSAGE_NO_DIGITAL_SIGNATURE, - UNHANDLED_CRITICAL_CRL_EXTENSION, - INVALID_EXTENSION, - INVALID_POLICY_EXTENSION, - NO_EXPLICIT_POLICY, - DIFFERENT_CRL_SCOPE, - UNSUPPORTED_EXTENSION_FEATURE, - UNNESTED_RESOURCE, - PERMITTED_VIOLATION, - EXCLUDED_VIOLATION, - SUBTREE_MINMAX, - UNSUPPORTED_CONSTRAINT_TYPE, - UNSUPPORTED_CONSTRAINT_SYNTAX, - UNSUPPORTED_NAME_SYNTAX, - CRL_PATH_VALIDATION_ERROR, - SUITE_B_INVALID_VERSION, - SUITE_B_INVALID_ALGORITHM, - SUITE_B_INVALID_CURVE, - SUITE_B_INVALID_SIGNATURE_ALGORITHM, - SUITE_B_LOS_NOT_ALLOWED, - SUITE_B_CANNOT_SIGN_P_384_WITH_P_256, - HOSTNAME_MISMATCH, - EMAIL_MISMATCH, - IP_ADDRESS_MISMATCH, - INVALID_CALL, - STORE_LOOKUP, - NAME_CONSTRAINTS_WITHOUT_SANS, - UNKNOWN_CERTIFICATE_VERIFICATION_ERROR, -}; - -pub fn getCertErrorFromNo(error_no: i32) CertError { - return switch (error_no) { - X509_V_OK => error.OK, - X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT => error.UNABLE_TO_GET_ISSUER_CERT, - X509_V_ERR_UNABLE_TO_GET_CRL => error.UNABLE_TO_GET_CRL, - X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE => error.UNABLE_TO_DECRYPT_CERT_SIGNATURE, - X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE => error.UNABLE_TO_DECRYPT_CRL_SIGNATURE, - X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY => error.UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, - X509_V_ERR_CERT_SIGNATURE_FAILURE => error.CERT_SIGNATURE_FAILURE, - X509_V_ERR_CRL_SIGNATURE_FAILURE => error.CRL_SIGNATURE_FAILURE, - X509_V_ERR_CERT_NOT_YET_VALID => error.CERT_NOT_YET_VALID, - X509_V_ERR_CRL_NOT_YET_VALID => error.CRL_NOT_YET_VALID, - X509_V_ERR_CERT_HAS_EXPIRED => error.CERT_HAS_EXPIRED, - X509_V_ERR_CRL_HAS_EXPIRED => error.CRL_HAS_EXPIRED, - X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD => error.ERROR_IN_CERT_NOT_BEFORE_FIELD, - X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD => error.ERROR_IN_CERT_NOT_AFTER_FIELD, - X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD => error.ERROR_IN_CRL_LAST_UPDATE_FIELD, - X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD => error.ERROR_IN_CRL_NEXT_UPDATE_FIELD, - X509_V_ERR_OUT_OF_MEM => error.OUT_OF_MEM, - X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT => error.DEPTH_ZERO_SELF_SIGNED_CERT, - X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN => error.SELF_SIGNED_CERT_IN_CHAIN, - X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY => error.UNABLE_TO_GET_ISSUER_CERT_LOCALLY, - X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE => error.UNABLE_TO_VERIFY_LEAF_SIGNATURE, - X509_V_ERR_CERT_CHAIN_TOO_LONG => error.CERT_CHAIN_TOO_LONG, - X509_V_ERR_CERT_REVOKED => error.CERT_REVOKED, - X509_V_ERR_INVALID_CA => error.INVALID_CA, - X509_V_ERR_INVALID_NON_CA => error.INVALID_NON_CA, - X509_V_ERR_PATH_LENGTH_EXCEEDED => error.PATH_LENGTH_EXCEEDED, - X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED => error.PROXY_PATH_LENGTH_EXCEEDED, - X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED => error.PROXY_CERTIFICATES_NOT_ALLOWED, - X509_V_ERR_INVALID_PURPOSE => error.INVALID_PURPOSE, - X509_V_ERR_CERT_UNTRUSTED => error.CERT_UNTRUSTED, - X509_V_ERR_CERT_REJECTED => error.CERT_REJECTED, - X509_V_ERR_APPLICATION_VERIFICATION => error.APPLICATION_VERIFICATION, - X509_V_ERR_SUBJECT_ISSUER_MISMATCH => error.SUBJECT_ISSUER_MISMATCH, - X509_V_ERR_AKID_SKID_MISMATCH => error.AKID_SKID_MISMATCH, - X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH => error.AKID_ISSUER_SERIAL_MISMATCH, - X509_V_ERR_KEYUSAGE_NO_CERTSIGN => error.KEYUSAGE_NO_CERTSIGN, - X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER => error.UNABLE_TO_GET_CRL_ISSUER, - X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION => error.UNHANDLED_CRITICAL_EXTENSION, - X509_V_ERR_KEYUSAGE_NO_CRL_SIGN => error.KEYUSAGE_NO_CRL_SIGN, - X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE => error.KEYUSAGE_NO_DIGITAL_SIGNATURE, - X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION => error.UNHANDLED_CRITICAL_CRL_EXTENSION, - X509_V_ERR_INVALID_EXTENSION => error.INVALID_EXTENSION, - X509_V_ERR_INVALID_POLICY_EXTENSION => error.INVALID_POLICY_EXTENSION, - X509_V_ERR_NO_EXPLICIT_POLICY => error.NO_EXPLICIT_POLICY, - X509_V_ERR_DIFFERENT_CRL_SCOPE => error.DIFFERENT_CRL_SCOPE, - X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE => error.UNSUPPORTED_EXTENSION_FEATURE, - X509_V_ERR_UNNESTED_RESOURCE => error.UNNESTED_RESOURCE, - X509_V_ERR_PERMITTED_VIOLATION => error.PERMITTED_VIOLATION, - X509_V_ERR_EXCLUDED_VIOLATION => error.EXCLUDED_VIOLATION, - X509_V_ERR_SUBTREE_MINMAX => error.SUBTREE_MINMAX, - X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE => error.UNSUPPORTED_CONSTRAINT_TYPE, - X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX => error.UNSUPPORTED_CONSTRAINT_SYNTAX, - X509_V_ERR_UNSUPPORTED_NAME_SYNTAX => error.UNSUPPORTED_NAME_SYNTAX, - X509_V_ERR_CRL_PATH_VALIDATION_ERROR => error.CRL_PATH_VALIDATION_ERROR, - X509_V_ERR_SUITE_B_INVALID_VERSION => error.SUITE_B_INVALID_VERSION, - X509_V_ERR_SUITE_B_INVALID_ALGORITHM => error.SUITE_B_INVALID_ALGORITHM, - X509_V_ERR_SUITE_B_INVALID_CURVE => error.SUITE_B_INVALID_CURVE, - X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM => error.SUITE_B_INVALID_SIGNATURE_ALGORITHM, - X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED => error.SUITE_B_LOS_NOT_ALLOWED, - X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 => error.SUITE_B_CANNOT_SIGN_P_384_WITH_P_256, - X509_V_ERR_HOSTNAME_MISMATCH => error.HOSTNAME_MISMATCH, - X509_V_ERR_EMAIL_MISMATCH => error.EMAIL_MISMATCH, - X509_V_ERR_IP_ADDRESS_MISMATCH => error.IP_ADDRESS_MISMATCH, - X509_V_ERR_INVALID_CALL => error.INVALID_CALL, - X509_V_ERR_STORE_LOOKUP => error.STORE_LOOKUP, - X509_V_ERR_NAME_CONSTRAINTS_WITHOUT_SANS => error.NAME_CONSTRAINTS_WITHOUT_SANS, - else => error.UNKNOWN_CERTIFICATE_VERIFICATION_ERROR, - }; -} - -pub const SSL = opaque { - pub const Error = error{ - SSL, - WantRead, - WantWrite, - WantX509Lookup, - Syscall, - ZeroReturn, - WantConnect, - WantAccept, - WantChannelIdLookup, - PendingSession, - PendingCertificate, - WantPrivateKeyOperation, - PendingTicket, - EarlyDataRejected, - WantCertificateVerify, - Handoff, - Handback, - WantRenegotiate, - HandshakeHintsReady, - }; - extern fn us_ssl_socket_verify_error_from_ssl(ssl: *SSL) bun.uws.us_bun_verify_error_t; - pub fn getVerifyError(this: *SSL) bun.uws.us_bun_verify_error_t { - return us_ssl_socket_verify_error_from_ssl(this); - } - - pub fn shutdown(this: *SSL) void { - _ = SSL_shutdown(this); - } - - pub inline fn deinit(this: *SSL) void { - _ = SSL_free(this); - } - - pub inline fn init(ctx: *SSL_CTX) *SSL { - return SSL_new(ctx); - } - - pub inline fn isInitFinished(ssl: *const SSL) bool { - return SSL_is_init_finished(ssl) > 0; - } - - pub inline fn pending(ssl: *SSL) usize { - return @as(usize, @intCast(SSL_pending(ssl))); - } - - pub inline fn hasPending(ssl: *SSL) bool { - return SSL_has_pending(ssl) > 0; - } - - pub inline fn setFD(this: *SSL, fd: c_int) void { - _ = SSL_set_fd(this, fd); - } - - pub inline fn setIsClient(ssl: *SSL, comptime is_client: bool) void { - if (comptime is_client) { - SSL_set_connect_state(ssl); - } else { - SSL_set_accept_state(ssl); - } - } - - pub inline fn setBIO(ssl: *SSL, in: *BIO, out: *BIO) void { - SSL_set_bio(ssl, in, out); - } - - pub fn setHostname(ssl: *SSL, hostname: [*c]const u8) void { - _ = SSL_set_tlsext_host_name(ssl, hostname); - } - - pub fn configureHTTPClient(ssl: *SSL, hostname: [:0]const u8) void { - configureHTTPClientWithALPN(ssl, hostname, .h1); - } - - pub const AlpnOffer = enum { h1, h1_or_h2, h2_only }; - - pub fn configureHTTPClientWithALPN(ssl: *SSL, hostname: [:0]const u8, offer: AlpnOffer) void { - if (hostname.len > 0) ssl.setHostname(hostname); - _ = SSL_clear_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT); - _ = SSL_set_options(ssl, SSL_OP_LEGACY_SERVER_CONNECT); - - const alpn_h1 = &[_]u8{ 8, 'h', 't', 't', 'p', '/', '1', '.', '1' }; - const alpn_h2 = &[_]u8{ 2, 'h', '2' }; - const alpn_h2_h1 = &[_]u8{ 2, 'h', '2', 8, 'h', 't', 't', 'p', '/', '1', '.', '1' }; - const alpns: []const u8 = switch (offer) { - .h1 => alpn_h1, - .h1_or_h2 => alpn_h2_h1, - .h2_only => alpn_h2, - }; - bun.assert(SSL_set_alpn_protos(ssl, alpns.ptr, alpns.len) == 0); - - SSL_enable_signed_cert_timestamps(ssl); - SSL_enable_ocsp_stapling(ssl); - } - - pub fn handshake(this: *SSL) Error!void { - const rc = SSL_connect(this); - return switch (SSL_get_error(this, rc)) { - SSL_ERROR_SSL => return error.SSL, - SSL_ERROR_WANT_READ => return error.WantRead, - SSL_ERROR_WANT_WRITE => return error.WantWrite, - SSL_ERROR_WANT_X509_LOOKUP => return error.WantX509Lookup, - SSL_ERROR_SYSCALL => return error.Syscall, - SSL_ERROR_ZERO_RETURN => return error.ZeroReturn, - SSL_ERROR_WANT_CONNECT => return error.WantConnect, - SSL_ERROR_WANT_ACCEPT => return error.WantAccept, - SSL_ERROR_WANT_CHANNEL_ID_LOOKUP => return error.WantChannelIdLookup, - SSL_ERROR_PENDING_SESSION => return error.PendingSession, - SSL_ERROR_PENDING_CERTIFICATE => return error.PendingCertificate, - SSL_ERROR_WANT_PRIVATE_KEY_OPERATION => return error.WantPrivateKeyOperation, - SSL_ERROR_PENDING_TICKET => return error.PendingTicket, - SSL_ERROR_EARLY_DATA_REJECTED => return error.EarlyDataRejected, - SSL_ERROR_WANT_CERTIFICATE_VERIFY => return error.WantCertificateVerify, - SSL_ERROR_HANDOFF => return error.Handoff, - SSL_ERROR_HANDBACK => return error.Handback, - SSL_ERROR_WANT_RENEGOTIATE => return error.WantRenegotiate, - SSL_ERROR_HANDSHAKE_HINTS_READY => return error.HandshakeHintsReady, - else => {}, - }; - } - - const Output = bun.Output; - const Environment = bun.Environment; - - pub fn read(this: *SSL, buf: []u8) Error!usize { - const rc = SSL_read(this, buf.ptr, @as(c_int, @intCast(buf.len))); - return switch (SSL_get_error(this, rc)) { - SSL_ERROR_SSL => error.SSL, - SSL_ERROR_WANT_READ => error.WantRead, - SSL_ERROR_WANT_WRITE => error.WantWrite, - SSL_ERROR_WANT_X509_LOOKUP => error.WantX509Lookup, - SSL_ERROR_SYSCALL => error.Syscall, - SSL_ERROR_ZERO_RETURN => error.ZeroReturn, - SSL_ERROR_WANT_CONNECT => error.WantConnect, - SSL_ERROR_WANT_ACCEPT => error.WantAccept, - SSL_ERROR_WANT_CHANNEL_ID_LOOKUP => error.WantChannelIdLookup, - SSL_ERROR_PENDING_SESSION => error.PendingSession, - SSL_ERROR_PENDING_CERTIFICATE => error.PendingCertificate, - SSL_ERROR_WANT_PRIVATE_KEY_OPERATION => error.WantPrivateKeyOperation, - SSL_ERROR_PENDING_TICKET => error.PendingTicket, - SSL_ERROR_EARLY_DATA_REJECTED => error.EarlyDataRejected, - SSL_ERROR_WANT_CERTIFICATE_VERIFY => error.WantCertificateVerify, - SSL_ERROR_HANDOFF => error.Handoff, - SSL_ERROR_HANDBACK => error.Handback, - SSL_ERROR_WANT_RENEGOTIATE => error.WantRenegotiate, - SSL_ERROR_HANDSHAKE_HINTS_READY => error.HandshakeHintsReady, - else => @as(usize, @intCast(rc)), - }; - } - - pub fn write(this: *SSL, buf: []const u8) Error!u32 { - const rc = SSL_write(this, buf.ptr, @as(c_int, @intCast(buf.len))); - return switch (SSL_get_error(this, rc)) { - SSL_ERROR_SSL => { - if (comptime Environment.isDebug) { - const errdescription = std.mem.span(SSL_error_description(SSL_ERROR_SSL).?); - Output.prettyError("SSL_ERROR: {s}", .{errdescription}); - } - return error.SSL; - }, - SSL_ERROR_WANT_READ => error.WantRead, - SSL_ERROR_WANT_WRITE => error.WantWrite, - SSL_ERROR_WANT_X509_LOOKUP => error.WantX509Lookup, - SSL_ERROR_SYSCALL => error.Syscall, - SSL_ERROR_ZERO_RETURN => error.ZeroReturn, - SSL_ERROR_WANT_CONNECT => error.WantConnect, - SSL_ERROR_WANT_ACCEPT => error.WantAccept, - SSL_ERROR_WANT_CHANNEL_ID_LOOKUP => error.WantChannelIdLookup, - SSL_ERROR_PENDING_SESSION => error.PendingSession, - SSL_ERROR_PENDING_CERTIFICATE => error.PendingCertificate, - SSL_ERROR_WANT_PRIVATE_KEY_OPERATION => error.WantPrivateKeyOperation, - SSL_ERROR_PENDING_TICKET => error.PendingTicket, - SSL_ERROR_EARLY_DATA_REJECTED => error.EarlyDataRejected, - SSL_ERROR_WANT_CERTIFICATE_VERIFY => error.WantCertificateVerify, - SSL_ERROR_HANDOFF => error.Handoff, - SSL_ERROR_HANDBACK => error.Handback, - SSL_ERROR_WANT_RENEGOTIATE => error.WantRenegotiate, - SSL_ERROR_HANDSHAKE_HINTS_READY => error.HandshakeHintsReady, - else => @as(u32, @intCast(rc)), - }; - } - - pub fn readAll(this: *SSL, buf: []u8) Error![]u8 { - var rbio = SSL_get_rbio(this); - const start_len = rbio.slice().len; - const written = try this.read(buf); - return rbio.slice()[start_len..][0..written]; - } - - pub fn writeAll(this: *SSL, buf: []const u8) Error![]const u8 { - var rbio = SSL_get_wbio(this); - const start_len = rbio.slice().len; - const written = try this.write(buf); - return rbio.slice()[start_len..][0..written]; - } -}; - -pub const VerifyResult = enum(c_int) { - ok = 0, - invalid = 1, - retry = 2, -}; -pub const VerifyCallback = *const fn (*SSL, [*c]u8) callconv(.c) VerifyResult; - -pub extern fn SSL_CTX_set_custom_verify(ctx: ?*SSL_CTX, mode: c_int, callback: ?VerifyCallback) void; - -pub const SSL_CTX = opaque { - pub fn init() ?*SSL_CTX { - var ctx = SSL_CTX_new(TLS_with_buffers_method()) orelse return null; - ctx.setCustomVerify(noop_custom_verify); - ctx.setup(); - return ctx; - } - - pub fn setup(ctx: *SSL_CTX) void { - if (auto_crypto_buffer_pool == null) auto_crypto_buffer_pool = CRYPTO_BUFFER_POOL_new(); - SSL_CTX_set0_buffer_pool(ctx, auto_crypto_buffer_pool); - _ = SSL_CTX_set_cipher_list(ctx, SSL_DEFAULT_CIPHER_LIST); - } - - pub inline fn setCustomVerify(this: *SSL_CTX, cb: ?VerifyCallback) void { - SSL_CTX_set_custom_verify(this, 0, cb); - // SSL_CTX_set_custom_verify(this, 1, cb); - // SSL_CTX_set_custom_verify(this, 2, cb); - } - - pub fn deinit(this: *SSL_CTX) void { - SSL_CTX_free(this); - } -}; - -fn noop_custom_verify(_: *SSL, _: [*c]u8) callconv(.c) VerifyResult { - return VerifyResult.ok; -} - -threadlocal var auto_crypto_buffer_pool: ?*CRYPTO_BUFFER_POOL = null; - -pub const BIOMethod = struct { - pub const create = *const fn (*BIO) callconv(.c) c_int; - pub const destroy = *const fn (*BIO) callconv(.c) c_int; - pub const write = *const fn (*BIO, [*c]const u8, c_int) callconv(.c) c_int; - pub const read = *const fn (*BIO, [*c]u8, c_int) callconv(.c) c_int; - pub const gets = *const fn (*BIO, [*c]u8, c_int) callconv(.c) c_int; - pub const ctrl = *const fn (*BIO, c_int, c_long, ?*anyopaque) callconv(.c) c_long; - pub fn init( - name: [:0]const u8, - comptime create__: ?create, - comptime destroy__: ?destroy, - comptime write__: ?write, - comptime read__: ?read, - comptime gets__: ?gets, - comptime ctrl__: ?ctrl, - ) *BIO_METHOD { - const method = BIO_meth_new(BIO_get_new_index() | BIO_TYPE_SOURCE_SINK, name); - if (comptime create__) |create_| { - bun.assert(BIO_meth_set_create(method, create_) > 0); - } - if (comptime destroy__) |destroy_| { - bun.assert(BIO_meth_set_destroy(method, destroy_) > 0); - } - if (comptime write__) |write_| { - bun.assert(BIO_meth_set_write(method, write_) > 0); - } - if (comptime read__) |read_| { - bun.assert(BIO_meth_set_read(method, read_) > 0); - } - if (comptime gets__) |gets_| { - bun.assert(BIO_meth_set_gets(method, gets_) > 0); - } - if (comptime ctrl__) |ctrl_| { - bun.assert(BIO_meth_set_ctrl(method, ctrl_) > 0); - } - - return method; - } -}; - -pub fn getError(this: *SSL, rc: c_int) SSL.Error!u32 { - return switch (SSL_get_error(this, rc)) { - SSL_ERROR_SSL => error.SSL, - SSL_ERROR_WANT_READ => error.WantRead, - SSL_ERROR_WANT_WRITE => error.WantWrite, - SSL_ERROR_WANT_X509_LOOKUP => error.WantX509Lookup, - SSL_ERROR_SYSCALL => error.Syscall, - SSL_ERROR_ZERO_RETURN => error.ZeroReturn, - SSL_ERROR_WANT_CONNECT => error.WantConnect, - SSL_ERROR_WANT_ACCEPT => error.WantAccept, - SSL_ERROR_WANT_CHANNEL_ID_LOOKUP => error.WantChannelIdLookup, - SSL_ERROR_PENDING_SESSION => error.PendingSession, - SSL_ERROR_PENDING_CERTIFICATE => error.PendingCertificate, - SSL_ERROR_WANT_PRIVATE_KEY_OPERATION => error.WantPrivateKeyOperation, - SSL_ERROR_PENDING_TICKET => error.PendingTicket, - SSL_ERROR_EARLY_DATA_REJECTED => error.EarlyDataRejected, - SSL_ERROR_WANT_CERTIFICATE_VERIFY => error.WantCertificateVerify, - SSL_ERROR_HANDOFF => error.Handoff, - SSL_ERROR_HANDBACK => error.Handback, - SSL_ERROR_WANT_RENEGOTIATE => error.WantRenegotiate, - SSL_ERROR_HANDSHAKE_HINTS_READY => error.HandshakeHintsReady, - else => @as(u32, @intCast(rc)), - }; -} - -const bun = @import("bun"); -const std = @import("std"); - -const C = @import("std").zig.c_builtins; -const DECLARE_ASN1_ALLOC_FUNCTIONS_name = C.DECLARE_ASN1_ALLOC_FUNCTIONS_name; -const DECLARE_ASN1_FUNCTIONS_name = C.DECLARE_ASN1_FUNCTIONS_name; -const DEFINE_NAMED_STACK_OF = C.DEFINE_NAMED_STACK_OF; -const NULL = C.NULL; -const enum_ssl_verify_result_t = C.enum_ssl_verify_result_t; -const struct_timespec = C.struct_timespec; -const struct_timeval = C.struct_timeval; -const struct_tm = C.struct_tm; -const time_t = C.time_t; -const timercmp = C.timercmp; -const va_list = C.va_list; diff --git a/src/brotli/brotli.zig b/src/brotli/brotli.zig deleted file mode 100644 index 0ac0ca9aa2fc..000000000000 --- a/src/brotli/brotli.zig +++ /dev/null @@ -1,287 +0,0 @@ -pub const c = @import("../brotli_sys/brotli_c.zig"); -const BrotliDecoder = c.BrotliDecoder; -const BrotliEncoder = c.BrotliEncoder; - -pub const BrotliAllocator = struct { - pub fn alloc(_: ?*anyopaque, len: usize) callconv(.c) *anyopaque { - if (bun.heap_breakdown.enabled) { - const zone = bun.heap_breakdown.getZone("brotli"); - return zone.malloc_zone_malloc(len) orelse bun.outOfMemory(); - } - - return mimalloc.mi_malloc(len) orelse bun.outOfMemory(); - } - - pub fn free(_: ?*anyopaque, data: ?*anyopaque) callconv(.c) void { - if (bun.heap_breakdown.enabled) { - const zone = bun.heap_breakdown.getZone("brotli"); - zone.malloc_zone_free(data); - return; - } - - mimalloc.mi_free(data); - } -}; - -pub const DecoderOptions = struct { - pub const Params = std.enums.EnumFieldStruct(c.BrotliDecoderParameter, bool, false); - - params: Params = Params{ - .LARGE_WINDOW = true, - .DISABLE_RING_BUFFER_REALLOCATION = false, - }, -}; - -pub const BrotliReaderArrayList = struct { - pub const State = enum { - Uninitialized, - Inflating, - End, - Error, - }; - - input: []const u8, - list: std.ArrayListUnmanaged(u8), - list_allocator: std.mem.Allocator, - list_ptr: *std.ArrayListUnmanaged(u8), - brotli: *BrotliDecoder, - state: State = State.Uninitialized, - total_out: usize = 0, - total_in: usize = 0, - flushOp: BrotliEncoder.Operation, - finishFlushOp: BrotliEncoder.Operation, - fullFlushOp: BrotliEncoder.Operation, - - pub const new = bun.TrivialNew(BrotliReaderArrayList); - - pub fn newWithOptions(input: []const u8, list: *std.ArrayListUnmanaged(u8), allocator: std.mem.Allocator, options: DecoderOptions) !*BrotliReaderArrayList { - return BrotliReaderArrayList.new(try initWithOptions(input, list, allocator, options, .process, .finish, .flush)); - } - - pub fn initWithOptions( - input: []const u8, - list: *std.ArrayListUnmanaged(u8), - allocator: std.mem.Allocator, - options: DecoderOptions, - flushOp: BrotliEncoder.Operation, - finishFlushOp: BrotliEncoder.Operation, - fullFlushOp: BrotliEncoder.Operation, - ) !BrotliReaderArrayList { - if (!BrotliDecoder.initializeBrotli()) { - return error.BrotliFailedToLoad; - } - - var brotli = BrotliDecoder.createInstance(&BrotliAllocator.alloc, &BrotliAllocator.free, null) orelse return error.BrotliFailedToCreateInstance; - if (options.params.LARGE_WINDOW) - _ = brotli.setParameter(c.BrotliDecoderParameter.LARGE_WINDOW, 1); - if (options.params.DISABLE_RING_BUFFER_REALLOCATION) - _ = brotli.setParameter(c.BrotliDecoderParameter.DISABLE_RING_BUFFER_REALLOCATION, 1); - - bun.assert(list.items.ptr != input.ptr); - - return .{ - .input = input, - .list_ptr = list, - .list = list.*, - .list_allocator = allocator, - .brotli = brotli, - .flushOp = flushOp, - .finishFlushOp = finishFlushOp, - .fullFlushOp = fullFlushOp, - }; - } - - pub fn end(this: *BrotliReaderArrayList) void { - this.state = .End; - } - - pub fn readAll(this: *BrotliReaderArrayList, is_done: bool) !void { - defer this.list_ptr.* = this.list; - - if (this.state == .End or this.state == .Error) { - return; - } - - bun.assert(this.list.items.ptr != this.input.ptr); - - while (this.state == State.Uninitialized or this.state == State.Inflating) { - var unused_capacity = this.list.unusedCapacitySlice(); - - if (unused_capacity.len < 4096) { - try this.list.ensureUnusedCapacity(this.list_allocator, 4096); - unused_capacity = this.list.unusedCapacitySlice(); - } - - bun.assert(unused_capacity.len > 0); - - var next_in = this.input[this.total_in..]; - - var in_remaining = next_in.len; - var out_remaining = unused_capacity.len; - - // https://github.com/google/brotli/blob/fef82ea10435abb1500b615b1b2c6175d429ec6c/go/cbrotli/reader.go#L15-L27 - const result = this.brotli.decompressStream( - &in_remaining, - @ptrCast(&next_in), - &out_remaining, - @ptrCast(&unused_capacity.ptr), - null, - ); - - const bytes_written = unused_capacity.len -| out_remaining; - const bytes_read = next_in.len -| in_remaining; - - this.list.items.len += bytes_written; - this.total_in += bytes_read; - - switch (result) { - .success => { - if (comptime bun.Environment.allow_assert) { - bun.assert(this.brotli.isFinished()); - } - this.end(); - return; - }, - .err => { - this.state = .Error; - if (comptime bun.Environment.allow_assert) { - const code = this.brotli.getErrorCode(); - bun.Output.debugWarn("Brotli error: {s} ({d})", .{ @tagName(code), @intFromEnum(code) }); - } - - return error.BrotliDecompressionError; - }, - - .needs_more_input => { - if (in_remaining > 0) { - @panic("Brotli wants more data"); - } - this.state = .Inflating; - if (is_done) { - // Stream is truncated - we're at EOF but decoder needs more data - this.state = .Error; - return error.BrotliDecompressionError; - } - // Not at EOF - we can retry with more data - return error.ShortRead; - }, - .needs_more_output => { - try this.list.ensureTotalCapacity(this.list_allocator, this.list.capacity + 4096); - this.state = .Inflating; - }, - } - } - } - - pub fn deinit(this: *BrotliReaderArrayList) void { - this.brotli.destroyInstance(); - bun.destroy(this); - } -}; - -pub const BrotliCompressionStream = struct { - pub const State = enum { - Inflating, - End, - Error, - }; - - brotli: *BrotliEncoder, - state: State = State.Inflating, - total_out: usize = 0, - total_in: usize = 0, - flushOp: BrotliEncoder.Operation, - finishFlushOp: BrotliEncoder.Operation, - fullFlushOp: BrotliEncoder.Operation, - - pub fn init( - flushOp: BrotliEncoder.Operation, - finishFlushOp: BrotliEncoder.Operation, - fullFlushOp: BrotliEncoder.Operation, - ) !BrotliCompressionStream { - const instance = BrotliEncoder.createInstance(&BrotliAllocator.alloc, &BrotliAllocator.free, null) orelse return error.BrotliFailedToCreateInstance; - - return BrotliCompressionStream{ - .brotli = instance, - .flushOp = flushOp, - .finishFlushOp = finishFlushOp, - .fullFlushOp = fullFlushOp, - }; - } - - pub fn writeChunk(this: *BrotliCompressionStream, input: []const u8, last: bool) ![]const u8 { - this.total_in += input.len; - const result = this.brotli.compressStream(if (last) this.finishFlushOp else this.flushOp, input); - - if (!result.success) { - this.state = .Error; - return error.BrotliCompressionError; - } - - return result.output; - } - - pub fn write(this: *BrotliCompressionStream, input: []const u8, last: bool) ![]const u8 { - if (this.state == .End or this.state == .Error) { - return ""; - } - - return this.writeChunk(input, last); - } - - pub fn end(this: *BrotliCompressionStream) ![]const u8 { - defer this.state = .End; - - return try this.write("", true); - } - - pub fn deinit(this: *BrotliCompressionStream) void { - this.brotli.destroyInstance(); - } - - fn NewWriter(comptime InputWriter: type) type { - return struct { - compressor: *BrotliCompressionStream, - input_writer: InputWriter, - - const Self = @This(); - pub const WriteError = error{BrotliCompressionError} || InputWriter.Error; - pub const Writer = std.Io.GenericWriter(@This(), WriteError, Self.write); - - pub fn init(compressor: *BrotliCompressionStream, input_writer: InputWriter) Self { - return Self{ - .compressor = compressor, - .input_writer = input_writer, - }; - } - - pub fn write(self: Self, to_compress: []const u8) WriteError!usize { - const decompressed = try self.compressor.write(to_compress, false); - try self.input_writer.writeAll(decompressed); - return to_compress.len; - } - - pub fn end(self: Self) !usize { - const decompressed = try self.compressor.end(); - try self.input_writer.writeAll(decompressed); - } - - pub fn writer(self: Self) Writer { - return Writer{ .context = self }; - } - }; - } - - pub fn writerContext(this: *BrotliCompressionStream, writable: anytype) NewWriter(@TypeOf(writable)) { - return NewWriter(@TypeOf(writable)).init(this, writable); - } - - pub fn writer(this: *BrotliCompressionStream, writable: anytype) NewWriter(@TypeOf(writable)).Writer { - return this.writerContext(writable).writer(); - } -}; - -const std = @import("std"); - -const bun = @import("bun"); -const mimalloc = bun.mimalloc; diff --git a/src/brotli_sys/brotli_c.zig b/src/brotli_sys/brotli_c.zig deleted file mode 100644 index 57f690bc1ed2..000000000000 --- a/src/brotli_sys/brotli_c.zig +++ /dev/null @@ -1,334 +0,0 @@ -// TODO: prefer generating this file via translate_c - -pub const brotli_alloc_func = ?*const fn (?*anyopaque, usize) callconv(.c) ?*anyopaque; -pub const brotli_free_func = ?*const fn (?*anyopaque, *anyopaque) callconv(.c) void; -pub const struct_BrotliSharedDictionaryStruct = opaque {}; -pub const BrotliSharedDictionary = struct_BrotliSharedDictionaryStruct; -pub const BROTLI_SHARED_DICTIONARY_RAW: c_int = 0; -pub const BROTLI_SHARED_DICTIONARY_SERIALIZED: c_int = 1; -pub const enum_BrotliSharedDictionaryType = c_uint; -pub const BrotliSharedDictionaryType = enum_BrotliSharedDictionaryType; -// pub extern fn BrotliSharedDictionaryCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) ?*BrotliSharedDictionary; -// pub extern fn BrotliSharedDictionaryDestroyInstance(dict: ?*BrotliSharedDictionary) void; -// pub extern fn BrotliSharedDictionaryAttach(dict: ?*BrotliSharedDictionary, @"type": BrotliSharedDictionaryType, data_size: usize, data: [*]const u8) c_int; - -pub extern fn BrotliDecoderSetParameter(state: *BrotliDecoder, param: c_uint, value: u32) callconv(.c) c_int; -pub extern fn BrotliDecoderAttachDictionary(state: *BrotliDecoder, @"type": BrotliSharedDictionaryType, data_size: usize, data: [*]const u8) callconv(.c) c_int; -pub extern fn BrotliDecoderCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) callconv(.c) ?*BrotliDecoder; -pub extern fn BrotliDecoderDestroyInstance(state: *BrotliDecoder) callconv(.c) void; -pub extern fn BrotliDecoderDecompress(encoded_size: usize, encoded_buffer: [*]const u8, decoded_size: *usize, decoded_buffer: [*]u8) callconv(.c) BrotliDecoderResult; -pub extern fn BrotliDecoderDecompressStream(state: *BrotliDecoder, available_in: *usize, next_in: *?[*]const u8, available_out: *usize, next_out: *?[*]u8, total_out: ?*usize) callconv(.c) BrotliDecoderResult; -pub extern fn BrotliDecoderHasMoreOutput(state: *const BrotliDecoder) callconv(.c) c_int; -pub extern fn BrotliDecoderTakeOutput(state: *BrotliDecoder, size: *usize) callconv(.c) ?[*]const u8; -pub extern fn BrotliDecoderIsUsed(state: *const BrotliDecoder) callconv(.c) c_int; -pub extern fn BrotliDecoderIsFinished(state: *const BrotliDecoder) callconv(.c) c_int; -pub extern fn BrotliDecoderGetErrorCode(state: *const BrotliDecoder) callconv(.c) BrotliDecoderErrorCode2; -pub extern fn BrotliDecoderErrorString(c: BrotliDecoderErrorCode) callconv(.c) ?[*:0]const u8; -pub extern fn BrotliDecoderVersion() callconv(.c) u32; - -pub const BrotliDecoder = opaque { - const BrotliDecoderSetMetadataCallbacks = fn (state: *BrotliDecoder, start_func: brotli_decoder_metadata_start_func, chunk_func: brotli_decoder_metadata_chunk_func, @"opaque": ?*anyopaque) callconv(.c) void; - const brotli_decoder_metadata_start_func = ?*const fn (?*anyopaque, usize) callconv(.c) void; - const brotli_decoder_metadata_chunk_func = ?*const fn (?*anyopaque, [*]const u8, usize) callconv(.c) void; - - pub fn setParameter(state: *BrotliDecoder, param: BrotliDecoderParameter, value: u32) callconv(.c) bool { - return BrotliDecoderSetParameter(state, @intFromEnum(param), value) > 0; - } - - pub fn attachDictionary(state: *BrotliDecoder, @"type": BrotliSharedDictionaryType, data: []const u8) callconv(.c) c_int { - return BrotliDecoderAttachDictionary(state, @"type", data.len, data.ptr); - } - - pub fn createInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) callconv(.c) ?*BrotliDecoder { - return BrotliDecoderCreateInstance(alloc_func, free_func, @"opaque"); - } - - pub fn destroyInstance(state: *BrotliDecoder) callconv(.c) void { - return BrotliDecoderDestroyInstance(state); - } - - pub fn decompress(encoded: []const u8, decoded: *[]u8) callconv(.c) BrotliDecoderResult { - return BrotliDecoderDecompress(encoded.len, encoded.ptr, &decoded.len, decoded.ptr); - } - - pub fn decompressStream(state: *BrotliDecoder, available_in: *usize, next_in: *?[*]const u8, available_out: *usize, next_out: *?[*]u8, total_out: ?*usize) callconv(.c) BrotliDecoderResult { - return BrotliDecoderDecompressStream(state, available_in, next_in, available_out, next_out, total_out); - } - - pub fn hasMoreOutput(state: *const BrotliDecoder) callconv(.c) bool { - return BrotliDecoderHasMoreOutput(state) != 0; - } - - pub fn takeOutput(state: *BrotliDecoder) callconv(.c) []const u8 { - var max_size: usize = std.math.maxInt(usize); - const ptr = BrotliDecoderTakeOutput(state, &max_size) orelse return ""; - return ptr[0..max_size]; - } - - pub fn isUsed(state: *const BrotliDecoder) callconv(.c) bool { - return BrotliDecoderIsUsed(state) != 0; - } - - pub fn isFinished(state: *const BrotliDecoder) callconv(.c) bool { - return BrotliDecoderIsFinished(state) != 0; - } - - pub fn getErrorCode(state: *const BrotliDecoder) callconv(.c) BrotliDecoderErrorCode { - return @enumFromInt(@intFromEnum(BrotliDecoderGetErrorCode(state))); - } - - pub fn errorString(c: BrotliDecoderErrorCode) callconv(.c) [:0]const u8 { - return bun.sliceTo(BrotliDecoderErrorString(c) orelse "", 0); - } - - pub fn version() callconv(.c) u32 { - return BrotliDecoderVersion(); - } - - pub fn initializeBrotli() bool { - return true; - } -}; -pub const BrotliDecoderResult = enum(c_uint) { - err = 0, - success = 1, - needs_more_input = 2, - needs_more_output = 3, -}; -pub const BROTLI_DECODER_NO_ERROR: c_int = 0; -pub const BROTLI_DECODER_SUCCESS: c_int = 1; -pub const BROTLI_DECODER_NEEDS_MORE_INPUT: c_int = 2; -pub const BROTLI_DECODER_NEEDS_MORE_OUTPUT: c_int = 3; -pub const BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE: c_int = -1; -pub const BROTLI_DECODER_ERROR_FORMAT_RESERVED: c_int = -2; -pub const BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE: c_int = -3; -pub const BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET: c_int = -4; -pub const BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME: c_int = -5; -pub const BROTLI_DECODER_ERROR_FORMAT_CL_SPACE: c_int = -6; -pub const BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE: c_int = -7; -pub const BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT: c_int = -8; -pub const BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1: c_int = -9; -pub const BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2: c_int = -10; -pub const BROTLI_DECODER_ERROR_FORMAT_TRANSFORM: c_int = -11; -pub const BROTLI_DECODER_ERROR_FORMAT_DICTIONARY: c_int = -12; -pub const BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS: c_int = -13; -pub const BROTLI_DECODER_ERROR_FORMAT_PADDING_1: c_int = -14; -pub const BROTLI_DECODER_ERROR_FORMAT_PADDING_2: c_int = -15; -pub const BROTLI_DECODER_ERROR_FORMAT_DISTANCE: c_int = -16; -pub const BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY: c_int = -18; -pub const BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET: c_int = -19; -pub const BROTLI_DECODER_ERROR_INVALID_ARGUMENTS: c_int = -20; -pub const BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES: c_int = -21; -pub const BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS: c_int = -22; -pub const BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP: c_int = -25; -pub const BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1: c_int = -26; -pub const BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2: c_int = -27; -pub const BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES: c_int = -30; -pub const BROTLI_DECODER_ERROR_UNREACHABLE: c_int = -31; -pub const BrotliDecoderErrorCode = enum(c_int) { - FORMAT_EXUBERANT_NIBBLE = -1, - FORMAT_RESERVED = -2, - FORMAT_EXUBERANT_META_NIBBLE = -3, - FORMAT_SIMPLE_HUFFMAN_ALPHABET = -4, - FORMAT_SIMPLE_HUFFMAN_SAME = -5, - FORMAT_CL_SPACE = -6, - FORMAT_HUFFMAN_SPACE = -7, - FORMAT_CONTEXT_MAP_REPEAT = -8, - FORMAT_BLOCK_LENGTH_1 = -9, - FORMAT_BLOCK_LENGTH_2 = -10, - FORMAT_TRANSFORM = -11, - FORMAT_DICTIONARY = -12, - FORMAT_WINDOW_BITS = -13, - FORMAT_PADDING_1 = -14, - FORMAT_PADDING_2 = -15, - FORMAT_DISTANCE = -16, - COMPOUND_DICTIONARY = -18, - DICTIONARY_NOT_SET = -19, - INVALID_ARGUMENTS = -20, - ALLOC_CONTEXT_MODES = -21, - ALLOC_TREE_GROUPS = -22, - ALLOC_CONTEXT_MAP = -25, - ALLOC_RING_BUFFER_1 = -26, - ALLOC_RING_BUFFER_2 = -27, - ALLOC_BLOCK_TYPE_TREES = -30, - UNREACHABLE = -31, -}; -pub const BrotliDecoderErrorCode2 = enum(c_int) { - NO_ERROR = 0, - SUCCESS = 1, - NEEDS_MORE_INPUT = 2, - NEEDS_MORE_OUTPUT = 3, - ERROR_FORMAT_EXUBERANT_NIBBLE = -1, - ERROR_FORMAT_RESERVED = -2, - ERROR_FORMAT_EXUBERANT_META_NIBBLE = -3, - ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET = -4, - ERROR_FORMAT_SIMPLE_HUFFMAN_SAME = -5, - ERROR_FORMAT_CL_SPACE = -6, - ERROR_FORMAT_HUFFMAN_SPACE = -7, - ERROR_FORMAT_CONTEXT_MAP_REPEAT = -8, - ERROR_FORMAT_BLOCK_LENGTH_1 = -9, - ERROR_FORMAT_BLOCK_LENGTH_2 = -10, - ERROR_FORMAT_TRANSFORM = -11, - ERROR_FORMAT_DICTIONARY = -12, - ERROR_FORMAT_WINDOW_BITS = -13, - ERROR_FORMAT_PADDING_1 = -14, - ERROR_FORMAT_PADDING_2 = -15, - ERROR_FORMAT_DISTANCE = -16, - ERROR_COMPOUND_DICTIONARY = -18, - ERROR_DICTIONARY_NOT_SET = -19, - ERROR_INVALID_ARGUMENTS = -20, - ERROR_ALLOC_CONTEXT_MODES = -21, - ERROR_ALLOC_TREE_GROUPS = -22, - ERROR_ALLOC_CONTEXT_MAP = -25, - ERROR_ALLOC_RING_BUFFER_1 = -26, - ERROR_ALLOC_RING_BUFFER_2 = -27, - ERROR_ALLOC_BLOCK_TYPE_TREES = -30, - ERROR_UNREACHABLE = -31, -}; -pub const BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION: c_int = 0; -pub const BROTLI_DECODER_PARAM_LARGE_WINDOW: c_int = 1; -pub const BrotliDecoderParameter = enum(c_uint) { - DISABLE_RING_BUFFER_REALLOCATION = 0, - LARGE_WINDOW = 1, -}; - -pub const BROTLI_UINT32_MAX = ~@import("std").zig.c_translation.cast(u32, @as(c_int, 0)); -pub const BROTLI_SIZE_MAX = ~@import("std").zig.c_translation.cast(usize, @as(c_int, 0)); -pub const BROTLI_LAST_ERROR_CODE = BROTLI_DECODER_ERROR_UNREACHABLE; -pub const BrotliSharedDictionaryStruct = struct_BrotliSharedDictionaryStruct; - -pub const struct_BrotliEncoderPreparedDictionaryStruct = opaque {}; -pub const BrotliEncoderPreparedDictionary = struct_BrotliEncoderPreparedDictionaryStruct; -extern fn BrotliSharedDictionaryCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) ?*BrotliSharedDictionary; -extern fn BrotliSharedDictionaryDestroyInstance(dict: ?*BrotliSharedDictionary) void; -extern fn BrotliSharedDictionaryAttach(dict: ?*BrotliSharedDictionary, @"type": BrotliSharedDictionaryType, data_size: usize, data: [*c]const u8) c_int; -pub const BROTLI_MODE_GENERIC: c_int = 0; -pub const BROTLI_MODE_TEXT: c_int = 1; -pub const BROTLI_MODE_FONT: c_int = 2; -pub const BrotliEncoderMode = enum(c_uint) { - generic = 0, - text = 1, - font = 2, -}; -pub const BROTLI_OPERATION_PROCESS: c_int = 0; -pub const BROTLI_OPERATION_FLUSH: c_int = 1; -pub const BROTLI_OPERATION_FINISH: c_int = 2; -pub const BROTLI_OPERATION_EMIT_METADATA: c_int = 3; - -pub const BROTLI_PARAM_MODE: c_int = 0; -pub const BROTLI_PARAM_QUALITY: c_int = 1; -pub const BROTLI_PARAM_LGWIN: c_int = 2; -pub const BROTLI_PARAM_LGBLOCK: c_int = 3; -pub const BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: c_int = 4; -pub const BROTLI_PARAM_SIZE_HINT: c_int = 5; -pub const BROTLI_PARAM_LARGE_WINDOW: c_int = 6; -pub const BROTLI_PARAM_NPOSTFIX: c_int = 7; -pub const BROTLI_PARAM_NDIRECT: c_int = 8; -pub const BROTLI_PARAM_STREAM_OFFSET: c_int = 9; -pub const BrotliEncoderParameter = enum(c_uint) { - mode = 0, - quality = 1, - lgwin = 2, - lgblock = 3, - disable_literal_context_modeling = 4, - size_hint = 5, - large_window = 6, - npostfix = 7, - ndirect = 8, - stream_offset = 9, - // update kMaxBrotliParam in src/js/node/zlib.ts if this list changes -}; - -pub extern fn BrotliEncoderSetParameter(state: *BrotliEncoder, param: c_uint, value: u32) c_int; -pub extern fn BrotliEncoderCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) ?*BrotliEncoder; -pub extern fn BrotliEncoderDestroyInstance(state: *BrotliEncoder) void; -pub extern fn BrotliEncoderPrepareDictionary(@"type": BrotliSharedDictionaryType, data_size: usize, data: [*c]const u8, quality: c_int, alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) *BrotliEncoderPreparedDictionary; -pub extern fn BrotliEncoderDestroyPreparedDictionary(dictionary: *BrotliEncoderPreparedDictionary) void; -pub extern fn BrotliEncoderAttachPreparedDictionary(state: *BrotliEncoder, dictionary: ?*const BrotliEncoderPreparedDictionary) c_int; -pub extern fn BrotliEncoderMaxCompressedSize(input_size: usize) usize; -pub extern fn BrotliEncoderCompress(quality: c_int, lgwin: c_int, mode: BrotliEncoderMode, input_size: usize, input_buffer: [*]const u8, encoded_size: *usize, encoded_buffer: [*]u8) c_int; -pub extern fn BrotliEncoderCompressStream(state: *BrotliEncoder, op: BrotliEncoder.Operation, available_in: *usize, next_in: *?[*]const u8, available_out: *usize, next_in: ?*?[*]u8, total_out: ?*usize) c_int; -pub extern fn BrotliEncoderIsFinished(state: *BrotliEncoder) c_int; -pub extern fn BrotliEncoderHasMoreOutput(state: *BrotliEncoder) c_int; -pub extern fn BrotliEncoderTakeOutput(state: *BrotliEncoder, size: *usize) ?[*]const u8; -pub extern fn BrotliEncoderEstimatePeakMemoryUsage(quality: c_int, lgwin: c_int, input_size: usize) usize; -pub extern fn BrotliEncoderGetPreparedDictionarySize(dictionary: ?*const BrotliEncoderPreparedDictionary) usize; -pub extern fn BrotliEncoderVersion() u32; - -pub const BrotliEncoder = opaque { - pub const Operation = enum(c_uint) { - process = 0, - flush = 1, - finish = 2, - emit_metadata = 3, - }; - - pub fn createInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) callconv(.c) ?*BrotliEncoder { - return BrotliEncoderCreateInstance(alloc_func, free_func, @"opaque"); - } - - pub fn destroyInstance(state: *BrotliEncoder) callconv(.c) void { - return BrotliEncoderDestroyInstance(state); - } - - pub fn hasMoreOutput(state: *BrotliEncoder) callconv(.c) bool { - return BrotliEncoderHasMoreOutput(state) > 0; - } - - pub fn takeOutput(state: *BrotliEncoder) []const u8 { - var size: usize = 0; - if (BrotliEncoderTakeOutput(state, &size)) |ptr| { - return ptr[0..size]; - } - - return ""; - } - - pub const CompressionResult = struct { - success: bool = false, - has_more: bool = false, - output: []const u8 = "", - }; - - // https://github.com/google/brotli/blob/2ad58d8603294f5ee33d23bb725e0e6a17c1de50/go/cbrotli/writer.go#L23-L40 - pub fn compressStream(state: *BrotliEncoder, op: Operation, data: []const u8) CompressionResult { - var available_in = data.len; - var next_in: ?[*]const u8 = data.ptr; - - var available_out: usize = 0; - - var result = CompressionResult{}; - - result.success = BrotliEncoderCompressStream(state, op, &available_in, &next_in, &available_out, null, null) > 0; - - if (result.success) { - result.output = takeOutput(state); - } - - result.has_more = BrotliEncoderHasMoreOutput(state) > 0; - - return result; - } - - pub fn setParameter(state: *BrotliEncoder, param: BrotliEncoderParameter, value: u32) bool { - return BrotliEncoderSetParameter(state, @intFromEnum(param), value) > 0; - } -}; - -pub const SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH = 4; -pub const SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH = 31; -pub const SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS = 64; -pub const SHARED_BROTLI_MAX_COMPOUND_DICTS = 15; -pub const BROTLI_MIN_WINDOW_BITS = 10; -pub const BROTLI_MAX_WINDOW_BITS = 24; -pub const BROTLI_LARGE_MAX_WINDOW_BITS = 30; -pub const BROTLI_MIN_INPUT_BLOCK_BITS = 16; -pub const BROTLI_MAX_INPUT_BLOCK_BITS = 24; -pub const BROTLI_MIN_QUALITY = 0; -pub const BROTLI_MAX_QUALITY = 11; -pub const BROTLI_DEFAULT_QUALITY = 11; -pub const BROTLI_DEFAULT_WINDOW = 22; -pub const BROTLI_DEFAULT_MODE = BROTLI_MODE_GENERIC; - -const std = @import("std"); -const bun = @import("root").bun; diff --git a/src/bun.js.zig b/src/bun.js.zig deleted file mode 100644 index 3ec408f48815..000000000000 --- a/src/bun.js.zig +++ /dev/null @@ -1,656 +0,0 @@ -pub const jsc = @import("./jsc/jsc.zig"); -pub const webcore = @import("./runtime/webcore.zig"); -pub const api = @import("./runtime/api.zig"); -pub const bindgen = @import("./jsc/bindgen.zig"); - -pub fn applyStandaloneRuntimeFlags(b: *bun.Transpiler, graph: *const bun.StandaloneModuleGraph) void { - b.options.env.disable_default_env_files = graph.flags.disable_default_env_files; - b.options.env.behavior = if (graph.flags.disable_default_env_files) - .disable - else - .load_all_without_inlining; - - b.resolver.opts.load_tsconfig_json = !graph.flags.disable_autoload_tsconfig; - b.resolver.opts.load_package_json = !graph.flags.disable_autoload_package_json; -} - -pub const Run = struct { - ctx: Command.Context, - vm: *VirtualMachine, - entry_path: string, - arena: Arena, - any_unhandled: bool = false, - is_html_entrypoint: bool = false, - - var run: Run = undefined; - - pub fn bootStandalone(ctx: Command.Context, entry_path: string, graph_ptr: *bun.StandaloneModuleGraph) !void { - jsc.markBinding(@src()); - bun.jsc.initialize(false); - bun.analytics.Features.standalone_executable += 1; - - js_ast.Expr.Data.Store.create(); - js_ast.Stmt.Data.Store.create(); - const arena = Arena.init(); - - // Load bunfig.toml unless disabled by compile flags - // Note: config loading with execArgv is handled earlier in cli.zig via loadConfig - if (!ctx.debug.loaded_bunfig and !graph_ptr.flags.disable_autoload_bunfig) { - try bun.cli.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", ctx, .RunCommand); - } - - run = .{ - .vm = try VirtualMachine.initWithModuleGraph(.{ - .allocator = arena.allocator(), - .log = ctx.log, - .args = ctx.args, - .graph = graph_ptr, - .is_main_thread = true, - .smol = ctx.runtime_options.smol, - .debugger = ctx.runtime_options.debugger, - .dns_result_order = DNSResolver.Order.fromStringOrDie(ctx.runtime_options.dns_result_order), - }), - .arena = arena, - .ctx = ctx, - .entry_path = entry_path, - }; - - var vm = run.vm; - var b = &vm.transpiler; - vm.preload = ctx.preloads; - vm.argv = ctx.passthrough; - vm.arena = &run.arena; - vm.allocator = vm.arena.allocator(); - - b.options.install = ctx.install; - b.resolver.opts.install = ctx.install; - b.resolver.opts.global_cache = ctx.debug.global_cache; - b.resolver.opts.prefer_offline_install = (ctx.debug.offline_mode_setting orelse .online) == .offline; - b.resolver.opts.prefer_latest_install = (ctx.debug.offline_mode_setting orelse .online) == .latest; - b.options.global_cache = b.resolver.opts.global_cache; - b.options.prefer_offline_install = b.resolver.opts.prefer_offline_install; - b.options.prefer_latest_install = b.resolver.opts.prefer_latest_install; - b.resolver.env_loader = b.env; - - b.options.minify_identifiers = ctx.bundler_options.minify_identifiers; - b.options.minify_whitespace = ctx.bundler_options.minify_whitespace; - b.options.ignore_dce_annotations = ctx.bundler_options.ignore_dce_annotations; - b.resolver.opts.minify_identifiers = ctx.bundler_options.minify_identifiers; - b.resolver.opts.minify_whitespace = ctx.bundler_options.minify_whitespace; - - b.options.serve_plugins = ctx.args.serve_plugins; - b.options.bunfig_path = ctx.args.bunfig_path; - - // b.options.minify_syntax = ctx.bundler_options.minify_syntax; - - switch (ctx.debug.macros) { - .disable => { - b.options.no_macros = true; - }, - .map => |macros| { - b.options.macro_remap = macros; - }, - .unspecified => {}, - } - - applyStandaloneRuntimeFlags(b, graph_ptr); - - b.configureDefines() catch { - failWithBuildError(vm); - }; - - AsyncHTTP.loadEnv(vm.allocator, vm.log, b.env); - - vm.loadExtraEnvAndSourceCodePrinter(); - vm.is_main_thread = true; - jsc.VirtualMachine.is_main_thread_vm = true; - - bun.http.experimental_http2_client_from_cli = ctx.runtime_options.experimental_http2_fetch; - bun.http.experimental_http3_client_from_cli = ctx.runtime_options.experimental_http3_fetch; - doPreconnect(ctx.runtime_options.preconnect); - - const callback = OpaqueWrap(Run, Run.start); - vm.global.vm().holdAPILock(&run, callback); - } - - fn doPreconnect(preconnect: []const string) void { - if (preconnect.len == 0) return; - bun.HTTPThread.init(&.{}); - - for (preconnect) |url_str| { - const url = bun.URL.parse(url_str); - - if (!url.isHTTP() and !url.isHTTPS()) { - Output.errGeneric("preconnect URL must be HTTP or HTTPS: {f}", .{bun.fmt.quote(url_str)}); - Global.exit(1); - } - - if (url.hostname.len == 0) { - Output.errGeneric("preconnect URL must have a hostname: {f}", .{bun.fmt.quote(url_str)}); - Global.exit(1); - } - - if (!url.hasValidPort()) { - Output.errGeneric("preconnect URL must have a valid port: {f}", .{bun.fmt.quote(url_str)}); - Global.exit(1); - } - - AsyncHTTP.preconnect(url, false); - } - } - - fn bootBunShell(ctx: Command.Context, entry_path: []const u8) !bun.shell.ExitCode { - @branchHint(.cold); - - // this is a hack: make dummy bundler so we can use its `.runEnvLoader()` function to populate environment variables probably should split out the functionality - var bundle = try bun.Transpiler.init( - ctx.allocator, - ctx.log, - try @import("./jsc/config.zig").configureTransformOptionsForBunVM(ctx.allocator, ctx.args), - null, - ); - try bundle.runEnvLoader(bundle.options.env.disable_default_env_files); - const mini = jsc.MiniEventLoop.initGlobal(bundle.env, null); - mini.top_level_dir = ctx.args.absolute_working_dir orelse ""; - return bun.shell.Interpreter.initAndRunFromFile(ctx, mini, entry_path); - } - - pub fn boot(ctx: Command.Context, entry_path: string, loader: ?bun.options.Loader) !void { - jsc.markBinding(@src()); - - if (!ctx.debug.loaded_bunfig) { - try bun.cli.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", ctx, .RunCommand); - } - - // The shell does not need to initialize JSC. - // JSC initialization costs 1-3ms. We skip this if we know it's a shell script. - if (strings.endsWithComptime(entry_path, ".sh")) { - const exit_code = try bootBunShell(ctx, entry_path); - Global.exit(exit_code); - return; - } - - bun.jsc.initialize(ctx.runtime_options.eval.eval_and_print); - - js_ast.Expr.Data.Store.create(); - js_ast.Stmt.Data.Store.create(); - const arena = Arena.init(); - - run = .{ - .vm = try VirtualMachine.init( - .{ - .allocator = arena.allocator(), - .log = ctx.log, - .args = ctx.args, - .store_fd = ctx.debug.hot_reload != .none, - .smol = ctx.runtime_options.smol, - .eval = ctx.runtime_options.eval.eval_and_print, - .debugger = ctx.runtime_options.debugger, - .dns_result_order = DNSResolver.Order.fromStringOrDie(ctx.runtime_options.dns_result_order), - .is_main_thread = true, - }, - ), - .arena = arena, - .ctx = ctx, - .entry_path = entry_path, - }; - - var vm = run.vm; - var b = &vm.transpiler; - vm.preload = ctx.preloads; - vm.argv = ctx.passthrough; - vm.arena = &run.arena; - vm.allocator = vm.arena.allocator(); - - if (ctx.runtime_options.eval.script.len > 0) { - const script_source = try bun.default_allocator.create(logger.Source); - script_source.* = logger.Source.initPathString(entry_path, ctx.runtime_options.eval.script); - vm.module_loader.eval_source = script_source; - - if (ctx.runtime_options.eval.eval_and_print) { - b.options.dead_code_elimination = false; - } - } else if (ctx.runtime_options.cron_title.len > 0 and ctx.runtime_options.cron_period.len > 0) { - // Cron execution mode: wrap the entry point in a script that imports the - // module and calls default.scheduled(controller) - // Escape path for embedding in JS string literal (handle backslashes on Windows) - const escaped_path = try escapeForJSString(bun.default_allocator, entry_path); - defer bun.default_allocator.free(escaped_path); - const escaped_period = try escapeForJSString(bun.default_allocator, ctx.runtime_options.cron_period); - defer bun.default_allocator.free(escaped_period); - const cron_script = try std.fmt.allocPrint(bun.default_allocator, - \\const mod = await import("{s}"); - \\const scheduled = (mod.default || mod).scheduled; - \\if (typeof scheduled !== "function") throw new Error("Module does not export default.scheduled()"); - \\const controller = {{ cron: "{s}", type: "scheduled", scheduledTime: Date.now() }}; - \\await scheduled(controller); - , .{ escaped_path, escaped_period }); - // entry_path must end with /[eval] for the transpiler to use eval_source - const trigger = bun.pathLiteral("/[eval]"); - var cwd_buf: bun.PathBuffer = undefined; - const cwd_slice = switch (bun.sys.getcwd(&cwd_buf)) { - .result => |cwd| cwd, - .err => return error.SystemResources, - }; - var eval_path_buf: [bun.MAX_PATH_BYTES + trigger.len]u8 = undefined; - @memcpy(eval_path_buf[0..cwd_slice.len], cwd_slice); - @memcpy(eval_path_buf[cwd_slice.len..][0..trigger.len], trigger); - const eval_entry_path = eval_path_buf[0 .. cwd_slice.len + trigger.len]; - // Heap-allocate the path so it outlives this stack frame - const heap_entry_path = try bun.default_allocator.dupe(u8, eval_entry_path); - const script_source = try bun.default_allocator.create(logger.Source); - script_source.* = logger.Source.initPathString(heap_entry_path, cron_script); - vm.module_loader.eval_source = script_source; - run.entry_path = heap_entry_path; - } - - b.options.install = ctx.install; - b.resolver.opts.install = ctx.install; - b.resolver.opts.global_cache = ctx.debug.global_cache; - b.resolver.opts.prefer_offline_install = (ctx.debug.offline_mode_setting orelse .online) == .offline; - b.resolver.opts.prefer_latest_install = (ctx.debug.offline_mode_setting orelse .online) == .latest; - b.options.global_cache = b.resolver.opts.global_cache; - b.options.prefer_offline_install = b.resolver.opts.prefer_offline_install; - b.options.prefer_latest_install = b.resolver.opts.prefer_latest_install; - b.resolver.env_loader = b.env; - - b.options.minify_identifiers = ctx.bundler_options.minify_identifiers; - b.options.minify_whitespace = ctx.bundler_options.minify_whitespace; - b.options.ignore_dce_annotations = ctx.bundler_options.ignore_dce_annotations; - b.resolver.opts.minify_identifiers = ctx.bundler_options.minify_identifiers; - b.resolver.opts.minify_whitespace = ctx.bundler_options.minify_whitespace; - - b.options.env.behavior = .load_all_without_inlining; - // b.options.minify_syntax = ctx.bundler_options.minify_syntax; - - switch (ctx.debug.macros) { - .disable => { - b.options.no_macros = true; - }, - .map => |macros| { - b.options.macro_remap = macros; - }, - .unspecified => {}, - } - - b.configureDefines() catch { - failWithBuildError(vm); - }; - - AsyncHTTP.loadEnv(vm.allocator, vm.log, b.env); - - vm.loadExtraEnvAndSourceCodePrinter(); - vm.is_main_thread = true; - jsc.VirtualMachine.is_main_thread_vm = true; - - // Allow setting a custom timezone - if (vm.transpiler.env.get("TZ")) |tz| { - if (tz.len > 0) { - _ = vm.global.setTimeZone(&jsc.ZigString.init(tz)); - } - } - - vm.transpiler.env.loadTracy(); - - bun.http.experimental_http2_client_from_cli = ctx.runtime_options.experimental_http2_fetch; - bun.http.experimental_http3_client_from_cli = ctx.runtime_options.experimental_http3_fetch; - doPreconnect(ctx.runtime_options.preconnect); - - vm.main_is_html_entrypoint = (loader orelse vm.transpiler.options.loader(std.fs.path.extension(entry_path))) == .html; - - const callback = OpaqueWrap(Run, Run.start); - vm.global.vm().holdAPILock(&run, callback); - } - - fn onUnhandledRejectionBeforeClose(this: *jsc.VirtualMachine, _: *jsc.JSGlobalObject, value: jsc.JSValue) void { - this.runErrorHandler(value, this.onUnhandledRejectionExceptionList); - run.any_unhandled = true; - } - - pub fn start(this: *Run) void { - var vm = this.vm; - vm.hot_reload = this.ctx.debug.hot_reload; - vm.onUnhandledRejection = &onUnhandledRejectionBeforeClose; - - // Start CPU profiler if enabled - if (this.ctx.runtime_options.cpu_prof.enabled) { - const cpu_prof_opts = this.ctx.runtime_options.cpu_prof; - - vm.cpu_profiler_config = CPUProfiler.CPUProfilerConfig{ - .name = cpu_prof_opts.name, - .dir = cpu_prof_opts.dir, - .md_format = cpu_prof_opts.md_format, - .json_format = cpu_prof_opts.json_format, - .interval = cpu_prof_opts.interval, - }; - CPUProfiler.setSamplingInterval(cpu_prof_opts.interval); - CPUProfiler.startCPUProfiler(vm.jsc_vm); - bun.analytics.Features.cpu_profile += 1; - } - - // Set up heap profiler config if enabled (actual profiling happens on exit) - if (this.ctx.runtime_options.heap_prof.enabled) { - const heap_prof_opts = this.ctx.runtime_options.heap_prof; - - vm.heap_profiler_config = HeapProfiler.HeapProfilerConfig{ - .name = heap_prof_opts.name, - .dir = heap_prof_opts.dir, - .text_format = heap_prof_opts.text_format, - }; - bun.analytics.Features.heap_snapshot += 1; - } - - this.addConditionalGlobals(); - do_redis_preconnect: { - // This must happen within the API lock, which is why it's not in the "doPreconnect" function - if (this.ctx.runtime_options.redis_preconnect) { - // Go through the global object's getter because Bun.redis is a - // PropertyCallback which means we don't have a WriteBarrier we can access - const global = vm.global; - const bun_object = vm.global.toJSValue().get(global, "Bun") catch |err| { - vm.global.reportActiveExceptionAsUnhandled(err); - break :do_redis_preconnect; - } orelse break :do_redis_preconnect; - const redis = bun_object.get(global, "redis") catch |err| { - vm.global.reportActiveExceptionAsUnhandled(err); - break :do_redis_preconnect; - } orelse break :do_redis_preconnect; - const client = redis.as(bun.valkey.JSValkeyClient) orelse break :do_redis_preconnect; - // If connection fails, this will become an unhandled promise rejection, which is fine. - _ = client.doConnect(vm.global, redis) catch |err| { - vm.global.reportActiveExceptionAsUnhandled(err); - break :do_redis_preconnect; - }; - } - } - - do_postgres_preconnect: { - if (this.ctx.runtime_options.sql_preconnect) { - const global = vm.global; - const bun_object = vm.global.toJSValue().get(global, "Bun") catch |err| { - global.reportActiveExceptionAsUnhandled(err); - break :do_postgres_preconnect; - } orelse break :do_postgres_preconnect; - const sql_object = bun_object.get(global, "sql") catch |err| { - global.reportActiveExceptionAsUnhandled(err); - break :do_postgres_preconnect; - } orelse break :do_postgres_preconnect; - const connect_fn = sql_object.get(global, "connect") catch |err| { - global.reportActiveExceptionAsUnhandled(err); - break :do_postgres_preconnect; - } orelse break :do_postgres_preconnect; - _ = connect_fn.call(global, sql_object, &.{}) catch |err| { - global.reportActiveExceptionAsUnhandled(err); - break :do_postgres_preconnect; - }; - } - } - - switch (this.ctx.debug.hot_reload) { - .hot => jsc.hot_reloader.HotReloader.enableHotModuleReloading(vm, this.entry_path), - .watch => jsc.hot_reloader.WatchReloader.enableHotModuleReloading(vm, this.entry_path), - else => {}, - } - - if (strings.eqlComptime(this.entry_path, ".") and vm.transpiler.fs.top_level_dir.len > 0) { - this.entry_path = vm.transpiler.fs.top_level_dir; - } - - var printed_sourcemap_warning_and_version = false; - - if (vm.loadEntryPoint(this.entry_path)) |promise| { - if (promise.status() == .rejected) { - const handled = vm.uncaughtException(vm.global, promise.result(vm.global.vm()), true); - promise.setHandled(); - vm.pending_internal_promise_reported_at = vm.hot_reload_counter; - - if (vm.hot_reload != .none or handled) { - vm.addMainToWatcherIfNeeded(); - vm.eventLoop().tick(); - vm.eventLoop().tickPossiblyForever(); - } else { - vm.exit_handler.exit_code = 1; - vm.onExit(); - - if (run.any_unhandled) { - printed_sourcemap_warning_and_version = true; - bun.jsc.SavedSourceMap.MissingSourceMapNoteInfo.print(); - - Output.prettyErrorln( - "\n{s}", - .{Global.unhandled_error_bun_version_string}, - ); - } - vm.globalExit(); - } - } - - _ = promise.result(vm.global.vm()); - - if (vm.log.msgs.items.len > 0) { - dumpBuildError(vm); - vm.log.msgs.items.len = 0; - } - } else |err| { - if (vm.log.msgs.items.len > 0) { - dumpBuildError(vm); - vm.log.msgs.items.len = 0; - } else { - Output.prettyErrorln("Error occurred loading entry point: {s}", .{@errorName(err)}); - Output.flush(); - } - // TODO: Do a event loop tick when we figure out how to watch the file that wasn't found - // under hot reload mode - vm.exit_handler.exit_code = 1; - vm.onExit(); - if (run.any_unhandled) { - printed_sourcemap_warning_and_version = true; - bun.jsc.SavedSourceMap.MissingSourceMapNoteInfo.print(); - - Output.prettyErrorln( - "\n{s}", - .{Global.unhandled_error_bun_version_string}, - ); - } - vm.globalExit(); - } - - // don't run the GC if we don't actually need to - if (vm.isEventLoopAlive() or - vm.eventLoop().tickConcurrentWithCount() > 0) - { - vm.global.vm().releaseWeakRefs(); - _ = vm.arena.gc(); - _ = vm.global.vm().runGC(false); - vm.tick(); - } - - // Initial synchronous evaluation of the entrypoint is done (TLA may - // still be pending and will resolve in the loop below); the embedded - // source pages are off the hot path now. No-op unless this is a - // compiled standalone binary, and skip under --watch/--hot since those - // re-read source on every reload. - if (!this.vm.isWatcherEnabled()) { - bun.StandaloneModuleGraph.hintSourcePagesDontNeed(); - } - - { - if (this.vm.isWatcherEnabled()) { - vm.reportExceptionInHotReloadedModuleIfNeeded(); - - while (true) { - while (vm.isEventLoopAlive()) { - vm.tick(); - - // Report exceptions in hot-reloaded modules - vm.reportExceptionInHotReloadedModuleIfNeeded(); - - vm.eventLoop().autoTickActive(); - } - - vm.onBeforeExit(); - - vm.reportExceptionInHotReloadedModuleIfNeeded(); - - vm.eventLoop().tickPossiblyForever(); - } - } else { - while (vm.isEventLoopAlive()) { - vm.tick(); - vm.eventLoop().autoTickActive(); - } - - if (this.ctx.runtime_options.eval.eval_and_print) { - const to_print = brk: { - const result: jsc.JSValue = vm.entry_point_result.value.get() orelse .js_undefined; - if (result.asAnyPromise()) |promise| { - switch (promise.status()) { - .pending => { - result.then2(vm.global, .js_undefined, Bun__onResolveEntryPointResult, Bun__onRejectEntryPointResult) catch {}; // TODO: properly propagate exception upwards - - vm.tick(); - vm.eventLoop().autoTickActive(); - - while (vm.isEventLoopAlive()) { - vm.tick(); - vm.eventLoop().autoTickActive(); - } - - break :brk result; - }, - else => break :brk promise.result(vm.jsc_vm), - } - } - - break :brk result; - }; - - to_print.print(vm.global, .Log, .Log); - } - - vm.onBeforeExit(); - } - - if (vm.log.msgs.items.len > 0) { - dumpBuildError(vm); - Output.flush(); - } - } - - vm.onUnhandledRejection = &onUnhandledRejectionBeforeClose; - vm.global.handleRejectedPromises(); - vm.onExit(); - - if (this.any_unhandled and !printed_sourcemap_warning_and_version) { - this.vm.exit_handler.exit_code = 1; - - bun.jsc.SavedSourceMap.MissingSourceMapNoteInfo.print(); - - Output.prettyErrorln( - "\n{s}", - .{Global.unhandled_error_bun_version_string}, - ); - } - - bun.api.napi.fixDeadCodeElimination(); - bun.webcore.BakeResponse.fixDeadCodeElimination(); - bun.crash_handler.fixDeadCodeElimination(); - @import("./jsc/JSSecrets.zig").fixDeadCodeElimination(); - vm.globalExit(); - } - - fn addConditionalGlobals(this: *Run) void { - const vm = this.vm; - const runtime_options: *const Command.RuntimeOptions = &this.ctx.runtime_options; - - if (runtime_options.eval.script.len > 0) { - bun.cpp.Bun__ExposeNodeModuleGlobals(vm.global); - } - if (runtime_options.expose_gc) { - bun.cpp.JSC__JSGlobalObject__addGc(vm.global); - } - } -}; - -pub export fn Bun__onResolveEntryPointResult(global: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) callconv(jsc.conv) noreturn { - const arguments = callframe.arguments_old(1).slice(); - const result = arguments[0]; - result.print(global, .Log, .Log); - Global.exit(global.bunVM().exit_handler.exit_code); - return .js_undefined; -} - -pub export fn Bun__onRejectEntryPointResult(global: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) callconv(jsc.conv) noreturn { - const arguments = callframe.arguments_old(1).slice(); - const result = arguments[0]; - result.print(global, .Log, .Log); - Global.exit(global.bunVM().exit_handler.exit_code); - return .js_undefined; -} - -noinline fn dumpBuildError(vm: *jsc.VirtualMachine) void { - @branchHint(.cold); - - Output.flush(); - - const writer = Output.errorWriterBuffered(); - defer Output.flush(); - - vm.log.print(writer) catch {}; -} - -pub noinline fn failWithBuildError(vm: *jsc.VirtualMachine) noreturn { - @branchHint(.cold); - dumpBuildError(vm); - Global.exit(1); -} - -const OpaqueWrap = jsc.OpaqueWrap; -const VirtualMachine = jsc.VirtualMachine; - -const string = []const u8; - -/// Escape a string for safe embedding in a JS double-quoted string literal. -/// Escapes backslashes, double quotes, newlines, etc. -fn escapeForJSString(allocator: std.mem.Allocator, input: []const u8) ![]const u8 { - var needs_escape = false; - for (input) |c| { - if (c == '\\' or c == '"' or c == '\n' or c == '\r' or c == '\t') { - needs_escape = true; - break; - } - } - if (!needs_escape) return allocator.dupe(u8, input); - - var result = try std.array_list.Managed(u8).initCapacity(allocator, input.len + 16); - for (input) |c| { - switch (c) { - '\\' => try result.appendSlice("\\\\"), - '"' => try result.appendSlice("\\\""), - '\n' => try result.appendSlice("\\n"), - '\r' => try result.appendSlice("\\r"), - '\t' => try result.appendSlice("\\t"), - else => try result.append(c), - } - } - return result.toOwnedSlice(); -} - -const CPUProfiler = @import("./jsc/BunCPUProfiler.zig"); -const HeapProfiler = @import("./jsc/BunHeapProfiler.zig"); -const options = @import("./bundler/options.zig"); -const std = @import("std"); -const Command = @import("./runtime/cli/cli.zig").Command; -const which = @import("./which/which.zig").which; - -const bun = @import("bun"); -const Global = bun.Global; -const Output = bun.Output; -const default_allocator = bun.default_allocator; -const js_ast = bun.ast; -const logger = bun.logger; -const strings = bun.strings; -const transpiler = bun.transpiler; -const Arena = bun.allocators.MimallocArena; -const AsyncHTTP = bun.http.AsyncHTTP; -const DNSResolver = bun.api.dns.Resolver; diff --git a/src/bun.zig b/src/bun.zig deleted file mode 100644 index a1cf3361bfaf..000000000000 --- a/src/bun.zig +++ /dev/null @@ -1,3824 +0,0 @@ -//! This is the root source file of Bun's zig module. It can be imported using -//! `@import("bun")`, and should be able to reach all code via `.` syntax. -//! -//! Prefer adding new code into a separate file and adding an import, or putting -//! code in the relevant namespace. - -const bun = @This(); - -pub const Environment = @import("./bun_core/env.zig"); -pub const env_var = @import("./bun_core/env_var.zig"); -pub const feature_flag = env_var.feature_flag; - -pub const use_mimalloc = @import("build_options").use_mimalloc; -pub const default_allocator: std.mem.Allocator = allocators.c_allocator; -/// Zero-sized type whose `allocator` method returns `default_allocator`. -pub const DefaultAllocator = allocators.Default; -/// Zeroing memory allocator -pub const z_allocator: std.mem.Allocator = allocators.z_allocator; - -pub const callmod_inline: std.builtin.CallModifier = if (builtin.mode == .Debug) .auto else .always_inline; -pub const callconv_inline: std.builtin.CallingConvention = if (builtin.mode == .Debug) .auto else .@"inline"; - -/// In debug builds, this will catch memory leaks. In release builds, it is mimalloc. -pub const debug_allocator: std.mem.Allocator = if (Environment.isDebug or Environment.enable_asan) - debug_allocator_data.allocator -else - default_allocator; - -pub const debug_allocator_data = struct { - comptime { - if (!Environment.isDebug) @compileError("only available in debug"); - } - pub var backing: ?std.heap.DebugAllocator(.{}) = null; - pub const allocator: std.mem.Allocator = .{ - .ptr = undefined, - .vtable = &.{ - .alloc = &alloc, - .resize = &resize, - .remap = &remap, - .free = &free, - }, - }; - - fn alloc(_: *anyopaque, new_len: usize, alignment: std.mem.Alignment, ret_addr: usize) ?[*]u8 { - return backing.?.allocator().rawAlloc(new_len, alignment, ret_addr); - } - - fn resize(_: *anyopaque, mem: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) bool { - return backing.?.allocator().rawResize(mem, alignment, new_len, ret_addr); - } - - fn remap(_: *anyopaque, mem: []u8, alignment: std.mem.Alignment, new_len: usize, ret_addr: usize) ?[*]u8 { - return backing.?.allocator().rawRemap(mem, alignment, new_len, ret_addr); - } - - fn free(_: *anyopaque, mem: []u8, alignment: std.mem.Alignment, ret_addr: usize) void { - return backing.?.allocator().rawFree(mem, alignment, ret_addr); - } -}; - -pub extern "c" fn powf(x: f32, y: f32) f32; -pub extern "c" fn pow(x: f64, y: f64) f64; - -/// Restrict a value to a certain interval unless it is a float and NaN. -pub inline fn clamp(self: anytype, min: @TypeOf(self), max: @TypeOf(self)) @TypeOf(self) { - bun.debugAssert(min <= max); - if (comptime (@TypeOf(self) == f32 or @TypeOf(self) == f64)) { - return clampFloat(self, min, max); - } - return std.math.clamp(self, min, max); -} - -/// Restrict a value to a certain interval unless it is NaN. -/// -/// Returns `max` if `self` is greater than `max`, and `min` if `self` is -/// less than `min`. Otherwise this returns `self`. -/// -/// Note that this function returns NaN if the initial value was NaN as -/// well. -pub inline fn clampFloat(_self: anytype, min: @TypeOf(_self), max: @TypeOf(_self)) @TypeOf(_self) { - if (comptime !(@TypeOf(_self) == f32 or @TypeOf(_self) == f64)) { - @compileError("Only call this on floats."); - } - var self = _self; - if (self < min) { - self = min; - } - if (self > max) { - self = max; - } - return self; -} - -/// Converts a floating-point value to an integer following Rust semantics. -/// This provides safe conversion that mimics Rust's `as` operator behavior, -/// unlike Zig's `@intFromFloat` which panics on out-of-range values. -/// -/// Conversion rules: -/// - If finite and within target integer range: truncates toward zero -/// - If NaN: returns 0 -/// - If out-of-range (including infinities): clamp to target min/max bounds -pub fn intFromFloat(comptime Int: type, value: anytype) Int { - const Float = @TypeOf(value); - comptime { - // Simple type check - let the compiler do the heavy lifting - if (!(Float == f32 or Float == f64)) { - @compileError("intFromFloat: value must be f32 or f64"); - } - } - - // Handle NaN - if (std.math.isNan(value)) { - return 0; - } - - // Handle out-of-range values (including infinities) - const min_int = std.math.minInt(Int); - const max_int = std.math.maxInt(Int); - - // Check the truncated value directly against integer bounds - const truncated = @trunc(value); - - // Use f64 for comparison to avoid precision issues - if (truncated > @as(f64, @floatFromInt(max_int))) { - return max_int; - } - if (truncated < @as(f64, @floatFromInt(min_int))) { - return min_int; - } - - // Additional safety check: ensure we can safely convert - if (truncated != truncated) { // Check for NaN in truncated value - return 0; - } - - // Safe to convert - truncate toward zero - return @as(Int, @intFromFloat(truncated)); -} - -pub fn typedAllocator(comptime T: type) std.mem.Allocator { - if (heap_breakdown.enabled) - return heap_breakdown.allocator(comptime T); - - return default_allocator; -} - -pub inline fn namedAllocator(comptime name: [:0]const u8) std.mem.Allocator { - if (heap_breakdown.enabled) - return heap_breakdown.namedAllocator(name); - - return default_allocator; -} - -pub const OOM = std.mem.Allocator.Error; - -pub const JSError = error{ - /// There is an active exception on the global object. - /// You should almost never have to construct this manually. - JSError, - // XXX: This is temporary! meghan will remove this soon - OutOfMemory, - /// Similar to error.JSError but always represents a termination exception. - JSTerminated, -}; - -pub const JSTerminated = error{ - /// JavaScript execution has been terminated. - /// This condition is indicated by throwing an exception, so most code should still handle it - /// with JSError. If you expect that you will not throw any errors other than the termination - /// exception, you can catch JSError, assert that the exception is the termination exception, - /// and return error.JSTerminated. - JSTerminated, -}; - -pub const JSOOM = OOM || JSError; - -pub const ci = @import("./runtime/cli/ci_info.zig"); - -/// Cross-platform system APIs -pub const sys = @import("./sys/sys.zig"); -/// Deprecated: use bun.sys.S -pub const S = sys.S; -pub const O = sys.O; -pub const Mode = sys.Mode; - -// Platform-specific system APIs. If something can be implemented on multiple -// platforms, it does not belong in these three namespaces. -pub const windows = @import("./sys/windows/windows.zig"); -pub const darwin = @import("./platform/darwin.zig"); -pub const linux = @import("./platform/linux.zig"); - -/// Translated from `c-headers-for-zig.h` for the current platform. -pub const c = @import("translated-c-headers"); -pub const tty = @import("./bun_core/tty.zig"); - -pub const sha = @import("./sha_hmac/sha.zig"); -pub const FeatureFlags = @import("./bun_core/feature_flags.zig"); -pub const meta = @import("./meta/meta.zig"); -pub const base64 = @import("./base64/base64.zig"); -pub const path = @import("./paths/resolve_path.zig"); -pub const resolver = @import("./resolver/resolver.zig"); -pub const DirIterator = @import("./runtime/node/dir_iterator.zig"); -pub const PackageJSON = @import("./resolver/package_json.zig").PackageJSON; -pub const fmt = @import("./bun_core/fmt.zig"); - -// This file is gennerated, but cant be placed in the build/debug/codegen -// folder because zig will complain about outside-of-module stuff -/// All functions and interfaces provided from Bun's `bindgen` utility. -pub const gen = @import("./jsc/bindings/GeneratedBindings.zig"); - -comptime { - // This file is gennerated, but cant be placed in the build/debug/codegen - // folder because zig will complain about outside-of-module stuff - _ = &@import("./jsc/bindings/GeneratedJS2Native.zig"); - _ = &gen; // reference bindings - // Exports `us_dispatch_*` for loop.c — nothing in Zig calls them, but the - // C event loop link-depends on them. - _ = &uws.dispatch; -} - -/// Copied from Zig std.trait -pub const trait = @import("./meta/traits.zig"); -/// Copied from Zig std.Progress before 0.13 rewrite -pub const Progress = @import("./bun_core/Progress.zig"); -/// Modified version of Zig's ComptimeStringMap -pub const comptime_string_map = @import("./collections/comptime_string_map.zig"); -pub const ComptimeStringMap = comptime_string_map.ComptimeStringMap; -pub const ComptimeStringMap16 = comptime_string_map.ComptimeStringMap16; -pub const ComptimeStringMapWithKeyType = comptime_string_map.ComptimeStringMapWithKeyType; - -pub const glob = @import("./glob/glob.zig"); -pub const patch = @import("./patch/patch.zig"); -pub const ini = @import("./ini/ini.zig"); -pub const bits = @import("./meta/bits.zig"); -pub const css = @import("./css/css_parser.zig"); -pub const SmallList = css.SmallList; -pub const csrf = @import("./csrf/csrf.zig"); -pub const validators = @import("./runtime/node/util/validators.zig"); - -pub const shell = @import("./runtime/shell/shell.zig"); -pub const md = @import("./md/root.zig"); - -pub const Output = @import("./bun_core/output.zig"); -pub const Global = @import("./bun_core/Global.zig"); -pub const ParentDeathWatchdog = @import("./aio/ParentDeathWatchdog.zig"); - -pub const FD = @import("./sys/fd.zig").FD; -pub const MovableIfWindowsFd = @import("./sys/fd.zig").MovableIfWindowsFd; - -/// Thin wrapper around iovec / libuv buffer -/// This is used for readv/writev calls. -pub const PlatformIOVec = if (Environment.isWindows) - windows.libuv.uv_buf_t -else - std.posix.iovec; - -pub const PlatformIOVecConst = if (Environment.isWindows) - windows.libuv.uv_buf_t -else - std.posix.iovec_const; - -pub fn platformIOVecCreate(input: []const u8) PlatformIOVec { - // TODO: remove this constCast by making the input mutable - return .{ .len = @truncate(input.len), .base = @constCast(input.ptr) }; -} - -pub fn platformIOVecConstCreate(input: []const u8) PlatformIOVecConst { - // TODO: remove this constCast by adding uv_buf_t_const - return .{ .len = @truncate(input.len), .base = @constCast(input.ptr) }; -} - -pub fn platformIOVecToSlice(iovec: PlatformIOVec) []u8 { - if (Environment.isWindows) return windows.libuv.uv_buf_t.slice(iovec); - return iovec.base[0..iovec.len]; -} - -pub const libarchive = @import("./libarchive/libarchive.zig"); - -pub const paths = @import("./paths/paths.zig"); -pub const MAX_PATH_BYTES = paths.MAX_PATH_BYTES; -pub const PathBuffer = paths.PathBuffer; -pub const PATH_MAX_WIDE = paths.PATH_MAX_WIDE; -pub const WPathBuffer = paths.WPathBuffer; -pub const OSPathChar = paths.OSPathChar; -pub const OSPathSliceZ = paths.OSPathSliceZ; -pub const OSPathSlice = paths.OSPathSlice; -pub const OSPathBuffer = paths.OSPathBuffer; -pub const Path = paths.Path; -pub const AbsPath = paths.AbsPath; -pub const AutoAbsPath = paths.AutoAbsPath; -pub const RelPath = paths.RelPath; -pub const AutoRelPath = paths.AutoRelPath; -pub const EnvPath = paths.EnvPath; -pub const path_buffer_pool = paths.path_buffer_pool; -pub const w_path_buffer_pool = paths.w_path_buffer_pool; -pub const os_path_buffer_pool = paths.os_path_buffer_pool; - -/// A lazily heap-allocated per-thread instance of `T`. -/// -/// Use this instead of `threadlocal var x: T = undefined` when `T` is -/// large (`bun.PathBuffer`, fixed arrays, structs of buffers). PE/COFF has -/// no TLS-BSS equivalent, so on Windows every zero-initialized threadlocal -/// is written into bun.exe's `.tls` section as raw zeros — with ~50 -/// `bun.PathBuffer` threadlocals (96 KB each on Windows vs 4 KB on POSIX) -/// that was ~5 MB of the binary and ~5 MB copied into every thread's TLS -/// block at thread creation whether or not it ever touched the resolver. -/// Behind a pointer, the per-thread footprint is 8 bytes on disk and the -/// backing memory is allocated only on first use. -/// -/// `T` is typically an anonymous struct literal, which gives each -/// instantiation a distinct `threadlocal var ptr` even if the field layout -/// happens to match another call site. -/// -/// Allocations are threaded onto a per-thread intrusive list so -/// `deleteAllPoolsForThreadExit()` (called from `WebWorker.shutdown()`) -/// can free them when a Worker thread exits. Without that, a short-lived -/// Worker that loaded its entry module through the resolver would orphan -/// the whole `Bufs` struct (~150 KB POSIX / ~3 MB Windows) until process -/// exit — mimalloc's abandoned-heap reclaim only recycles *freed* blocks. -/// Long-lived threads (main, pooled bundler/install workers) simply hold -/// the allocation for their lifetime. -pub fn ThreadlocalBuffers(comptime T: type) type { - return struct { - threadlocal var instance: ?*T = null; - - // Header + payload allocated together so the type-erased free - // function can recover the full allocation from the node pointer. - const Storage = struct { - node: ThreadlocalBuffersNode, - data: T, - }; - - pub inline fn get() *T { - return instance orelse alloc(); - } - - noinline fn alloc() *T { - @branchHint(.cold); - const s = default_allocator.create(Storage) catch outOfMemory(); - // Apply field default values. For the common case of - // `field: PathBuffer = undefined` this is a no-op in release - // builds; for wrappers around structs with real defaults (e.g. - // `NodeFS{ .vm = null }`) it's required for correctness. - s.* = .{ - .node = .{ .next = threadlocal_buffers_head, .free = free }, - .data = .{}, - }; - threadlocal_buffers_head = &s.node; - instance = &s.data; - return &s.data; - } - - fn free(node: *ThreadlocalBuffersNode) void { - instance = null; - const s: *Storage = @alignCast(@fieldParentPtr("node", node)); - default_allocator.destroy(s); - } - }; -} - -/// Intrusive list node prepended to every `ThreadlocalBuffers` allocation -/// so `freeAllThreadlocalBuffers()` can walk them without knowing each -/// instantiation's `T`. -const ThreadlocalBuffersNode = struct { - next: ?*ThreadlocalBuffersNode, - free: *const fn (*ThreadlocalBuffersNode) void, -}; -threadlocal var threadlocal_buffers_head: ?*ThreadlocalBuffersNode = null; - -/// Free every `ThreadlocalBuffers` allocation made on the current thread. -/// Called from `deleteAllPoolsForThreadExit()` just before a Worker thread -/// exits. After this returns, a subsequent `get()` on the same thread -/// re-allocates (so ordering relative to other shutdown code is not -/// load-bearing). -pub fn freeAllThreadlocalBuffers() void { - var node = threadlocal_buffers_head; - threadlocal_buffers_head = null; - while (node) |n| { - const next = n.next; - n.free(n); - node = next; - } -} - -pub inline fn cast(comptime To: type, value: anytype) To { - if (@typeInfo(@TypeOf(value)) == .int) { - return @ptrFromInt(@as(usize, value)); - } - - return @ptrCast(@alignCast(value)); -} - -pub fn len(value: anytype) usize { - return switch (@typeInfo(@TypeOf(value))) { - .array => |info| info.len, - .vector => |info| info.len, - .pointer => |info| switch (info.size) { - .one => switch (@typeInfo(info.child)) { - .array => |array| brk: { - if (array.sentinel_ptr != null) { - @compileError("use bun.sliceTo"); - } - - break :brk array.len; - }, - else => @compileError("invalid type given to std.mem.len"), - }, - .many => { - const sentinel_ptr = info.sentinel_ptr orelse - @compileError("length of pointer with no sentinel"); - const sentinel = @as(*align(1) const info.child, @ptrCast(sentinel_ptr)).*; - - return std.mem.indexOfSentinel(info.child, sentinel, value); - }, - .c => { - assert(value != null); - return std.mem.indexOfSentinel(info.child, 0, value); - }, - .slice => value.len, - }, - .@"struct" => |info| if (info.is_tuple) { - return info.fields.len; - } else @compileError("invalid type given to std.mem.len"), - else => @compileError("invalid type given to std.mem.len"), - }; -} - -fn Span(comptime T: type) type { - switch (@typeInfo(T)) { - .optional => |optional_info| { - return ?Span(optional_info.child); - }, - .pointer => |ptr_info| { - var new_ptr_info = ptr_info; - switch (ptr_info.size) { - .one => switch (@typeInfo(ptr_info.child)) { - .array => |info| { - new_ptr_info.child = info.child; - new_ptr_info.sentinel_ptr = info.sentinel_ptr; - }, - else => @compileError("invalid type given to std.mem.Span"), - }, - .c => { - new_ptr_info.sentinel_ptr = &@as(ptr_info.child, 0); - new_ptr_info.is_allowzero = false; - }, - .many, .slice => {}, - } - new_ptr_info.size = .slice; - return @Type(.{ .pointer = new_ptr_info }); - }, - else => @compileError("invalid type given to std.mem.Span: " ++ @typeName(T)), - } -} - -pub fn span(pointer: anytype) Span(@TypeOf(pointer)) { - if (@typeInfo(@TypeOf(pointer)) == .optional) { - if (pointer) |non_null| { - return span(non_null); - } else { - return null; - } - } - const Result = Span(@TypeOf(pointer)); - const l = len(pointer); - const ptr_info = @typeInfo(Result).pointer; - if (ptr_info.sentinel_ptr) |s_ptr| { - const s = @as(*align(1) const ptr_info.child, @ptrCast(s_ptr)).*; - return pointer[0..l :s]; - } else { - return pointer[0..l]; - } -} - -pub const IdentityContext = @import("./collections/identity_context.zig").IdentityContext; -pub const ArrayIdentityContext = @import("./collections/identity_context.zig").ArrayIdentityContext; -pub const StringHashMapUnowned = struct { - pub const Key = struct { - hash: u64, - len: usize, - - pub fn init(str: []const u8) Key { - return Key{ - .hash = hash(str), - .len = str.len, - }; - } - }; - - pub const Adapter = struct { - pub fn eql(_: @This(), a: Key, b: Key) bool { - return a.hash == b.hash and a.len == b.len; - } - - pub fn hash(_: @This(), key: Key) u64 { - return key.hash; - } - }; -}; - -pub const collections = @import("./collections/collections.zig"); -pub const MultiArrayList = bun.collections.MultiArrayList; -pub const BabyList = collections.BabyList; -pub const ByteList = collections.ByteList; // alias of BabyList(u8) -pub const OffsetByteList = collections.OffsetByteList; -pub const bit_set = collections.bit_set; -pub const HiveArray = collections.HiveArray; -pub const BoundedArray = collections.BoundedArray; - -pub fn DebugOnly(comptime Type: type) type { - if (comptime Environment.isDebug) { - return Type; - } - - return void; -} - -pub fn DebugOnlyDefault(comptime val: anytype) if (Environment.isDebug) @TypeOf(val) else void { - if (comptime Environment.isDebug) { - return val; - } - - return {}; -} - -pub inline fn range(comptime min: anytype, comptime max: anytype) [max - min]usize { - return comptime brk: { - var slice: [max - min]usize = undefined; - for (min..max) |i| { - slice[i - min] = i; - } - break :brk slice; - }; -} - -pub fn copy(comptime Type: type, dest: []Type, src: []const Type) void { - const input: []const u8 = std.mem.sliceAsBytes(src); - const output: []u8 = std.mem.sliceAsBytes(dest); - - return memmove(output, input); -} - -pub fn clone(item: anytype, allocator: std.mem.Allocator) !@TypeOf(item) { - const T = @TypeOf(item); - - if (std.meta.hasFn(T, "clone")) { - return try item.clone(allocator); - } - - const Child = std.meta.Child(T); - if (comptime trait.isContainer(Child)) { - if (std.meta.hasFn(Child, "clone")) { - const slice = try allocator.alloc(Child, item.len); - for (slice, 0..) |*val, i| { - val.* = try item[i].clone(allocator); - } - return slice; - } - - @compileError("Expected clone() to exist for slice child: " ++ @typeName(Child)); - } - - return try allocator.dupe(Child, item); -} - -pub const LinearFifo = @import("./collections/linear_fifo.zig").LinearFifo; -pub const LinearFifoBufferType = @import("./collections/linear_fifo.zig").LinearFifoBufferType; - -/// hash a string -pub fn hash(content: []const u8) u64 { - return std.hash.Wyhash.hash(0, content); -} - -/// Get a random-ish value -pub fn fastRandom() u64 { - const pcrng = struct { - const random_seed = struct { - var seed_value: std.atomic.Value(u64) = std.atomic.Value(u64).init(0); - pub fn get() u64 { - // This is slightly racy but its fine because this memoization is done as a performance optimization - // and we only need to do it once per process - var value = seed_value.load(.monotonic); - while (value == 0) : (value = seed_value.load(.monotonic)) { - if (comptime Environment.isDebug or Environment.is_canary) { - if (bun.env_var.BUN_DEBUG_HASH_RANDOM_SEED.get()) |v| { - seed_value.store(v, .monotonic); - return v; - } - } - csprng(std.mem.asBytes(&value)); - seed_value.store(value, .monotonic); - } - - return value; - } - }; - - var prng_: ?std.Random.DefaultPrng = null; - - pub fn get() u64 { - if (prng_ == null) { - prng_ = std.Random.DefaultPrng.init(random_seed.get()); - } - - return prng_.?.random().uintAtMost(u64, std.math.maxInt(u64)); - } - }; - - return pcrng.get(); -} - -pub fn hashWithSeed(seed: u64, content: []const u8) u64 { - return std.hash.Wyhash.hash(seed, content); -} - -pub fn hash32(content: []const u8) u32 { - const res = hash(content); - return @as(u32, @truncate(res)); -} - -pub fn csprng(bytes: []u8) void { - _ = BoringSSL.c.RAND_bytes(bytes.ptr, bytes.len); -} - -pub const ObjectPool = @import("./collections/pool.zig").ObjectPool; - -pub fn assertNonBlocking(fd: anytype) void { - assert((std.posix.fcntl(fd, std.posix.F.GETFL, 0) catch unreachable) & O.NONBLOCK != 0); -} - -pub fn ensureNonBlocking(fd: anytype) void { - const current = std.posix.fcntl(fd, std.posix.F.GETFL, 0) catch 0; - _ = std.posix.fcntl(fd, std.posix.F.SETFL, current | O.NONBLOCK) catch 0; -} - -const global_scope_log = sys.syslog; -pub fn isReadable(fd: FD) PollFlag { - if (comptime Environment.isWindows) { - @panic("TODO on Windows"); - } - assert(fd != invalid_fd); - var polls = [_]std.posix.pollfd{ - .{ - .fd = fd.cast(), - .events = std.posix.POLL.IN | std.posix.POLL.ERR | std.posix.POLL.HUP, - .revents = 0, - }, - }; - - const result = (std.posix.poll(&polls, 0) catch 0) != 0; - const rc = if (result and polls[0].revents & (std.posix.POLL.HUP | std.posix.POLL.ERR) != 0) - PollFlag.hup - else if (result) - PollFlag.ready - else - PollFlag.not_ready; - global_scope_log("poll({f}, .readable): {} ({s}{s})", .{ - fd, - result, - @tagName(rc), - if (polls[0].revents & std.posix.POLL.ERR != 0) " ERR " else "", - }); - return rc; -} - -pub const PollFlag = enum { ready, not_ready, hup }; -pub fn isWritable(fd: FD) PollFlag { - if (comptime Environment.isWindows) { - var polls = [_]std.os.windows.ws2_32.WSAPOLLFD{ - .{ - .fd = fd.asSocketFd(), - .events = std.posix.POLL.WRNORM, - .revents = 0, - }, - }; - const rc = std.os.windows.ws2_32.WSAPoll(&polls, 1, 0); - const result = (if (rc != std.os.windows.ws2_32.SOCKET_ERROR) @as(usize, @intCast(rc)) else 0) != 0; - global_scope_log("poll({f}) writable: {f} ({d})", .{ fd, result, polls[0].revents }); - if (result and polls[0].revents & std.posix.POLL.WRNORM != 0) { - return .hup; - } else if (result) { - return .ready; - } else { - return .not_ready; - } - return; - } - assert(fd != invalid_fd); - - var polls = [_]std.posix.pollfd{ - .{ - .fd = fd.cast(), - .events = std.posix.POLL.OUT | std.posix.POLL.ERR | std.posix.POLL.HUP, - .revents = 0, - }, - }; - - const result = (std.posix.poll(&polls, 0) catch 0) != 0; - const rc = if (result and polls[0].revents & (std.posix.POLL.HUP | std.posix.POLL.ERR) != 0) - PollFlag.hup - else if (result) - PollFlag.ready - else - PollFlag.not_ready; - global_scope_log("poll({f}, .writable): {} ({s}{s})", .{ - fd, - result, - @tagName(rc), - if (polls[0].revents & std.posix.POLL.ERR != 0) " ERR " else "", - }); - return rc; -} - -/// Do not use this function, call std.debug.panic directly. -/// -/// This function used to panic in debug, and be `unreachable` in release -/// however, if something is possibly reachable, it should not be marked unreachable. -/// It now panics in all release modes. -pub inline fn unreachablePanic(comptime fmts: []const u8, args: anytype) noreturn { - // if (comptime !Environment.allow_assert) unreachable; - std.debug.panic(fmts, args); -} - -pub fn StringEnum(comptime Type: type, comptime Map: anytype, value: []const u8) ?Type { - return ComptimeStringMap(Type, Map).get(value); -} - -pub const Bunfig = @import("./runtime/cli/bunfig.zig").Bunfig; - -pub const HTTPThread = @import("./http/http.zig").HTTPThread; -pub const http = @import("./http/http.zig"); - -pub const ptr = @import("./ptr/ptr.zig"); -pub const TaggedPointer = ptr.TaggedPointer; -pub const TaggedPointerUnion = ptr.TaggedPointerUnion; - -pub fn onceUnsafe(comptime function: anytype, comptime ReturnType: type) ReturnType { - const Result = struct { - var value: ReturnType = undefined; - var ran = false; - - pub fn execute() ReturnType { - if (ran) return value; - ran = true; - value = function(); - return value; - } - }; - - return Result.execute(); -} - -pub fn isHeapMemory(mem: anytype) bool { - if (comptime use_mimalloc) { - const Memory = @TypeOf(mem); - if (comptime std.meta.trait.isSingleItemPtr(Memory)) { - return mimalloc.mi_is_in_heap_region(mem); - } - return mimalloc.mi_is_in_heap_region(std.mem.sliceAsBytes(mem).ptr); - } - return false; -} - -pub const memory = @import("./bun_alloc/memory.zig"); -pub const allocators = @import("./bun_alloc/bun_alloc.zig"); -pub const mimalloc = allocators.mimalloc; -pub const MimallocArena = allocators.MimallocArena; -pub const AllocationScope = allocators.AllocationScope; -pub const NullableAllocator = allocators.NullableAllocator; -pub const MaxHeapAllocator = allocators.MaxHeapAllocator; - -pub const isSliceInBuffer = allocators.isSliceInBuffer; -pub const isSliceInBufferT = allocators.isSliceInBufferT; - -pub inline fn sliceInBuffer(stable: []const u8, value: []const u8) []const u8 { - if (allocators.sliceRange(stable, value)) |_| { - return value; - } - if (strings.indexOf(stable, value)) |index| { - return stable[index..][0..value.len]; - } - return value; -} - -pub fn rangeOfSliceInBuffer(slice: []const u8, buffer: []const u8) ?[2]u32 { - if (!isSliceInBuffer(slice, buffer)) return null; - const r = [_]u32{ - @as(u32, @truncate(@intFromPtr(slice.ptr) -| @intFromPtr(buffer.ptr))), - @as(u32, @truncate(slice.len)), - }; - if (comptime Environment.allow_assert) - assert(strings.eqlLong(slice, buffer[r[0]..][0..r[1]], false)); - return r; -} - -// TODO: prefer .invalid decl literal over this -// Please prefer `bun.FD.Optional.none` over this -pub const invalid_fd: FD = .invalid; - -pub const bun_js = @import("./bun.js.zig"); -/// Bindings to JavaScriptCore and other JavaScript primatives. -/// Web and runtime-specific APIs should go in `webcore` and `api`. -pub const jsc = bun_js.jsc; -/// JavaScript Web APIs -pub const webcore = bun_js.webcore; -/// "api" in this context means "the Bun APIs", as in "the exposed JS APIs" -pub const api = bun_js.api; - -pub const logger = @import("./logger/logger.zig"); -pub const default_thread_stack_size = ThreadPool.default_thread_stack_size; -pub const picohttp = @import("./picohttp/picohttp.zig"); -pub const uws = @import("./uws/uws.zig"); -pub const BoringSSL = @import("./boringssl/boringssl.zig"); -pub const LOLHTML = @import("./lolhtml_sys/lol_html.zig"); -pub const clap = @import("./clap/clap.zig"); -pub const analytics = @import("./analytics/analytics.zig"); -pub const zlib = @import("./zlib/zlib.zig"); -pub const simdutf = @import("./simdutf_sys/simdutf.zig"); - -pub var start_time: i128 = 0; - -pub fn openFileZ(pathZ: [:0]const u8, open_flags: std.fs.File.OpenFlags) !std.fs.File { - var flags: i32 = 0; - switch (open_flags.mode) { - .read_only => flags |= O.RDONLY, - .write_only => flags |= O.WRONLY, - .read_write => flags |= O.RDWR, - } - - const res = try sys.open(pathZ, flags, 0).unwrap(); - return std.fs.File{ .handle = res.cast() }; -} - -pub fn openFile(path_: []const u8, open_flags: std.fs.File.OpenFlags) !std.fs.File { - if (comptime Environment.isWindows) { - var flags: i32 = 0; - switch (open_flags.mode) { - .read_only => flags |= O.RDONLY, - .write_only => flags |= O.WRONLY, - .read_write => flags |= O.RDWR, - } - - const fd = try sys.openA(path_, flags, 0).unwrap(); - return fd.stdFile(); - } - - return try openFileZ(&try std.posix.toPosixPath(path_), open_flags); -} - -pub fn openDir(dir: std.fs.Dir, path_: [:0]const u8) !std.fs.Dir { - if (comptime Environment.isWindows) { - const res = try sys.openDirAtWindowsA(.fromStdDir(dir), path_, .{ .iterable = true, .can_rename_or_delete = true, .read_only = true }).unwrap(); - return res.stdDir(); - } else { - const fd = try sys.openat(.fromStdDir(dir), path_, O.DIRECTORY | O.CLOEXEC | O.RDONLY, 0).unwrap(); - return fd.stdDir(); - } -} - -pub fn openDirNoRenamingOrDeletingWindows(dir: FD, path_: [:0]const u8) !std.fs.Dir { - if (comptime !Environment.isWindows) @compileError("use openDir!"); - const res = try sys.openDirAtWindowsA(dir, path_, .{ .iterable = true, .can_rename_or_delete = false, .read_only = true }).unwrap(); - return res.stdDir(); -} - -pub fn openDirA(dir: std.fs.Dir, path_: []const u8) !std.fs.Dir { - if (comptime Environment.isWindows) { - const res = try sys.openDirAtWindowsA(.fromStdDir(dir), path_, .{ .iterable = true, .can_rename_or_delete = true, .read_only = true }).unwrap(); - return res.stdDir(); - } else { - const fd = try sys.openatA(.fromStdDir(dir), path_, O.DIRECTORY | O.CLOEXEC | O.RDONLY, 0).unwrap(); - return fd.stdDir(); - } -} - -pub fn openDirForIteration(dir: FD, path_: []const u8) sys.Maybe(FD) { - if (comptime Environment.isWindows) { - return sys.openDirAtWindowsA(dir, path_, .{ .iterable = true, .can_rename_or_delete = false, .read_only = true }); - } - return sys.openatA(dir, path_, O.DIRECTORY | O.CLOEXEC | O.RDONLY, 0); -} - -pub fn openDirForIterationOSPath(dir: FD, path_: []const OSPathChar) sys.Maybe(FD) { - if (comptime Environment.isWindows) { - return sys.openDirAtWindows(dir, path_, .{ .iterable = true, .can_rename_or_delete = false, .read_only = true }); - } - return sys.openatA(dir, path_, O.DIRECTORY | O.CLOEXEC | O.RDONLY, 0); -} - -pub fn openDirAbsolute(path_: []const u8) !std.fs.Dir { - const fd = if (comptime Environment.isWindows) - try sys.openDirAtWindowsA(invalid_fd, path_, .{ .iterable = true, .can_rename_or_delete = true, .read_only = true }).unwrap() - else - try sys.openA(path_, O.DIRECTORY | O.CLOEXEC | O.RDONLY, 0).unwrap(); - - return fd.stdDir(); -} - -pub fn openDirAbsoluteNotForDeletingOrRenaming(path_: []const u8) !std.fs.Dir { - const fd = if (comptime Environment.isWindows) - try sys.openDirAtWindowsA(invalid_fd, path_, .{ .iterable = true, .can_rename_or_delete = false, .read_only = true }).unwrap() - else - try sys.openA(path_, O.DIRECTORY | O.CLOEXEC | O.RDONLY, 0).unwrap(); - - return fd.stdDir(); -} - -/// Note: You likely do not need this function. See the pattern in env_var.zig for adding -/// environment variables. -/// TODO(markovejnovic): Sunset this function when its last usage is removed. -/// This wrapper exists to avoid the call to sliceTo(0) -/// Zig's sliceTo(0) is scalar -pub fn getenvZAnyCase(key: [:0]const u8) ?[]const u8 { - for (std.os.environ) |lineZ| { - const line = sliceTo(lineZ, 0); - const key_end = strings.indexOfCharUsize(line, '=') orelse line.len; - if (strings.eqlCaseInsensitiveASCII(line[0..key_end], key, true)) { - return line[@min(key_end + 1, line.len)..]; - } - } - - return null; -} - -/// Note: You likely do not need this function. See the pattern in env_var.zig for adding -/// environment variables. -/// TODO(markovejnovic): Sunset this function when its last usage is removed. -/// This wrapper exists to avoid the call to sliceTo(0) -/// Zig's sliceTo(0) is scalar -pub fn getenvZ(key: [:0]const u8) ?[]const u8 { - if (comptime !Environment.isNative) { - return null; - } - - if (comptime Environment.isWindows) { - return getenvZAnyCase(key); - } - - const pointer = std.c.getenv(key.ptr) orelse return null; - return sliceTo(pointer, 0); -} - -/// Note: You likely do not need this function. See the pattern in env_var.zig for adding -/// environment variables. -/// TODO(markovejnovic): Sunset this function when its last usage is removed. -pub fn getenvTruthy(key: [:0]const u8) bool { - if (getenvZ(key)) |value| return std.mem.eql(u8, value, "true") or std.mem.eql(u8, value, "1"); - return false; -} - -pub const U32HashMapContext = struct { - pub fn hash(_: @This(), value: u32) u64 { - return @intCast(value); - } - pub fn eql(_: @This(), a: u32, b: u32) bool { - return a == b; - } - pub fn pre(input: u32) Prehashed { - return Prehashed{ - .value = @This().hash(.{}, input), - .input = input, - }; - } - - pub const Prehashed = struct { - value: u64, - input: u32, - pub fn hash(this: @This(), value: u32) u64 { - if (value == this.input) return this.value; - return @intCast(value); - } - - pub fn eql(_: @This(), a: u32, b: u32) bool { - return a == b; - } - }; -}; -// These wrappers exist to use our strings.eqlLong function -pub const StringArrayHashMapContext = struct { - pub fn hash(_: @This(), s: []const u8) u32 { - return @as(u32, @truncate(std.hash.Wyhash.hash(0, s))); - } - pub fn eql(_: @This(), a: []const u8, b: []const u8, _: usize) bool { - return strings.eqlLong(a, b, true); - } - - pub fn pre(input: []const u8) Prehashed { - return Prehashed{ - .value = @This().hash(.{}, input), - .input = input, - }; - } - - pub const Prehashed = struct { - value: u32, - input: []const u8, - - pub fn hash(this: @This(), s: []const u8) u32 { - if (s.ptr == this.input.ptr and s.len == this.input.len) - return this.value; - return @as(u32, @truncate(std.hash.Wyhash.hash(0, s))); - } - - pub fn eql(_: @This(), a: []const u8, b: []const u8, _: usize) bool { - return strings.eqlLong(a, b, true); - } - }; -}; - -pub const CaseInsensitiveASCIIStringContext = struct { - pub fn hash(_: @This(), str_: []const u8) u32 { - var buf: [1024]u8 = undefined; - if (str_.len < buf.len) { - return @truncate(std.hash.Wyhash.hash(0, strings.copyLowercase(str_, &buf))); - } - var str = str_; - var wyhash = std.hash.Wyhash.init(0); - while (str.len > 0) { - const length = @min(str.len, buf.len); - wyhash.update(strings.copyLowercase(str[0..length], &buf)); - str = str[length..]; - } - return @truncate(wyhash.final()); - } - - pub fn eql(_: @This(), a: []const u8, b: []const u8, _: usize) bool { - return strings.eqlCaseInsensitiveASCIIICheckLength(a, b); - } - - pub fn pre(input: []const u8) Prehashed { - return Prehashed{ - .value = @This().hash(.{}, input), - .input = input, - }; - } - - pub const Prehashed = struct { - value: u32, - input: []const u8, - - pub fn hash(this: @This(), s: []const u8) u32 { - if (s.ptr == this.input.ptr and s.len == this.input.len) - return this.value; - return CaseInsensitiveASCIIStringContext.hash(.{}, s); - } - - pub fn eql(_: @This(), a: []const u8, b: []const u8) bool { - return strings.eqlCaseInsensitiveASCIIICheckLength(a, b); - } - }; -}; - -pub const StringHashMapContext = struct { - pub fn hash(_: @This(), s: []const u8) u64 { - return std.hash.Wyhash.hash(0, s); - } - pub fn eql(_: @This(), a: []const u8, b: []const u8) bool { - return strings.eqlLong(a, b, true); - } - - pub fn pre(input: []const u8) Prehashed { - return Prehashed{ - .value = @This().hash(.{}, input), - .input = input, - }; - } - - pub const Prehashed = struct { - value: u64, - input: []const u8, - pub fn hash(this: @This(), s: []const u8) u64 { - if (s.ptr == this.input.ptr and s.len == this.input.len) - return this.value; - return StringHashMapContext.hash(.{}, s); - } - - pub fn eql(_: @This(), a: []const u8, b: []const u8) bool { - return strings.eqlLong(a, b, true); - } - }; - - pub const PrehashedCaseInsensitive = struct { - value: u64, - input: []const u8, - pub fn init(allocator: std.mem.Allocator, input: []const u8) PrehashedCaseInsensitive { - const out = allocator.alloc(u8, input.len) catch unreachable; - _ = strings.copyLowercase(input, out); - return PrehashedCaseInsensitive{ - .value = StringHashMapContext.hash(.{}, out), - .input = out, - }; - } - pub fn deinit(this: @This(), allocator: std.mem.Allocator) void { - allocator.free(this.input); - } - pub fn hash(this: @This(), s: []const u8) u64 { - if (s.ptr == this.input.ptr and s.len == this.input.len) - return this.value; - return StringHashMapContext.hash(.{}, s); - } - - pub fn eql(_: @This(), a: []const u8, b: []const u8) bool { - return strings.eqlCaseInsensitiveASCIIICheckLength(a, b); - } - }; -}; - -pub fn StringArrayHashMap(comptime Type: type) type { - return std.ArrayHashMap([]const u8, Type, StringArrayHashMapContext, true); -} - -pub fn CaseInsensitiveASCIIStringArrayHashMap(comptime Type: type) type { - return std.ArrayHashMap([]const u8, Type, CaseInsensitiveASCIIStringContext, true); -} - -pub fn CaseInsensitiveASCIIStringArrayHashMapUnmanaged(comptime Type: type) type { - return std.ArrayHashMapUnmanaged([]const u8, Type, CaseInsensitiveASCIIStringContext, true); -} - -pub fn StringArrayHashMapUnmanaged(comptime Type: type) type { - return std.ArrayHashMapUnmanaged([]const u8, Type, StringArrayHashMapContext, true); -} - -pub fn StringHashMap(comptime Type: type) type { - return std.HashMap([]const u8, Type, StringHashMapContext, std.hash_map.default_max_load_percentage); -} - -pub fn StringHashMapUnmanaged(comptime Type: type) type { - return std.HashMapUnmanaged([]const u8, Type, StringHashMapContext, std.hash_map.default_max_load_percentage); -} - -pub fn FDHashMap(comptime Type: type) type { - return std.HashMap(FD, Type, FD.HashMapContext, std.hash_map.default_max_load_percentage); -} - -pub fn U32HashMap(comptime Type: type) type { - return std.HashMap(u32, Type, U32HashMapContext, std.hash_map.default_max_load_percentage); -} - -pub const copyFileErrnoConvert = CopyFile.copyFileErrorConvert; -pub const copyFileRange = CopyFile.copyFileRange; -pub const canUseCopyFileRangeSyscall = CopyFile.canUseCopyFileRangeSyscall; -pub const disableCopyFileRangeSyscall = CopyFile.disableCopyFileRangeSyscall; -pub const can_use_ioctl_ficlone = CopyFile.can_use_ioctl_ficlone; -pub const disable_ioctl_ficlone = CopyFile.disable_ioctl_ficlone; -pub const copyFile = CopyFile.copyFile; -pub const copyFileWithState = CopyFile.copyFileWithState; -pub const CopyFileState = CopyFile.CopyFileState; - -pub fn parseDouble(input: []const u8) !f64 { - if (comptime Environment.isWasm) { - return try std.fmt.parseFloat(f64, input); - } - return jsc.wtf.parseDouble(input); -} - -pub const SignalCode = @import("./sys/SignalCode.zig").SignalCode; - -pub fn isMissingIOUring() bool { - if (comptime !Environment.isLinux) - // it is not missing when it was not supposed to be there in the first place - return false; - - // cache the boolean value - const Missing = struct { - pub var is_missing_io_uring: ?bool = null; - }; - - return Missing.is_missing_io_uring orelse brk: { - const kernel = analytics.GenerateHeader.GeneratePlatform.kernelVersion(); - // io_uring was introduced in earlier versions of Linux, but it was not - // really usable for us until 5.3 - const result = kernel.major < 5 or (kernel.major == 5 and kernel.minor < 3); - Missing.is_missing_io_uring = result; - break :brk result; - }; -} - -pub const cli = @import("./runtime/cli/cli.zig"); - -pub const install = @import("./install/install.zig"); -pub const PackageManager = install.PackageManager; -pub const RunCommand = @import("./runtime/cli/run_command.zig").RunCommand; - -pub const fs = @import("./resolver/fs.zig"); -pub const transpiler = @import("./bundler/transpiler.zig"); -pub const Transpiler = transpiler.Transpiler; -pub const which = @import("./which/which.zig").which; -pub const js_parser = @import("./js_parser/parser.zig"); -pub const js_printer = @import("./js_printer/js_printer.zig"); -pub const js_lexer = @import("./js_parser/lexer.zig"); -pub const ast = @import("./js_parser/js_parser.zig"); - -pub const interchange = @import("./interchange/interchange.zig"); -pub const json = interchange.json; - -pub fn enumMap(comptime T: type, comptime args: anytype) (fn (T) [:0]const u8) { - const Map = struct { - const vargs = args; - const labels = brk: { - var vabels_ = std.enums.EnumArray(T, [:0]const u8).initFill(""); - @setEvalBranchQuota(99999); - for (vargs) |field| { - vabels_.set(field.@"0", field.@"1"); - } - break :brk vabels_; - }; - - pub fn get(input: T) [:0]const u8 { - return labels.get(input); - } - }; - - return Map.get; -} - -pub fn ComptimeEnumMap(comptime T: type) type { - var entries: [std.enums.values(T).len]struct { [:0]const u8, T } = undefined; - for (std.enums.values(T), &entries) |value, *entry| { - entry.* = .{ .@"0" = @tagName(value), .@"1" = value }; - } - return ComptimeStringMap(T, entries); -} - -/// Write 0's for every byte in Type -/// Ignores default struct values. -pub fn zero(comptime Type: type) Type { - var out: [@sizeOf(Type)]u8 align(@alignOf(Type)) = undefined; - @memset(@as([*]u8, @ptrCast(&out))[0..out.len], 0); - return @as(Type, @bitCast(out)); -} -pub const c_ares = @import("./cares_sys/c_ares.zig"); -pub const URL = @import("./url/url.zig").URL; -pub const FormData = @import("./runtime/webcore/FormData.zig").FormData; - -var needs_proc_self_workaround: bool = false; - -/// TODO: move to bun.sys -// This is our "polyfill" when /proc/self/fd is not available it's only -// necessary on linux because other platforms don't have an optional -// /proc/self/fd -fn getFdPathViaCWD(fd: std.posix.fd_t, buf: *bun.PathBuffer) ![]u8 { - const prev_fd = try std.posix.openatZ(std.fs.cwd().fd, ".", .{ .DIRECTORY = true }, 0); - var needs_chdir = false; - defer { - if (needs_chdir) std.posix.fchdir(prev_fd) catch unreachable; - std.posix.close(prev_fd); - } - try std.posix.fchdir(fd); - needs_chdir = true; - return std.posix.getcwd(buf); -} - -pub const getcwd = std.posix.getcwd; - -pub fn getcwdAlloc(allocator: std.mem.Allocator) ![:0]u8 { - var temp: PathBuffer = undefined; - const temp_slice = try getcwd(&temp); - return allocator.dupeZ(u8, temp_slice); -} - -/// TODO: move to bun.sys and add a method onto FD -/// Get the absolute path to a file descriptor. -/// On Linux, when `/proc/self/fd` is not available, this function will attempt to use `fchdir` and `getcwd` to get the path instead. -pub fn getFdPath(fd: FD, buf: *bun.PathBuffer) ![]u8 { - if (comptime Environment.isWindows) { - var wide_buf: WPathBuffer = undefined; - const wide_slice = try windows.GetFinalPathNameByHandle(fd.native(), .{}, wide_buf[0..]); - const res = strings.copyUTF16IntoUTF8(buf[0..], wide_slice); - return buf[0..res.written]; - } - - if (comptime Environment.allow_assert) { - // We need a way to test that the workaround is working - // but we don't want to do this check in a release build - const ProcSelfWorkAroundForDebugging = struct { - pub var has_checked = false; - }; - - if (!ProcSelfWorkAroundForDebugging.has_checked) { - ProcSelfWorkAroundForDebugging.has_checked = true; - needs_proc_self_workaround = bun.env_var.BUN_NEEDS_PROC_SELF_WORKAROUND.get(); - } - } else if (comptime !Environment.isLinux) { - return try std.os.getFdPath(fd.native(), buf); - } - - if (needs_proc_self_workaround) { - return getFdPathViaCWD(fd.native(), buf); - } - - return std.os.getFdPath(fd.native(), buf) catch |err| { - if (err == error.FileNotFound and !needs_proc_self_workaround) { - needs_proc_self_workaround = true; - return getFdPathViaCWD(fd.native(), buf); - } - - return err; - }; -} - -/// TODO: move to bun.sys and add a method onto FD -pub fn getFdPathZ(fd: FD, buf: *PathBuffer) ![:0]u8 { - const fd_path = try getFdPath(fd, buf); - buf[fd_path.len] = 0; - return buf[0..fd_path.len :0]; -} - -/// TODO: move to bun.sys and add a method onto FD -pub fn getFdPathW(fd: FD, buf: *WPathBuffer) ![]u16 { - if (comptime Environment.isWindows) { - return try windows.GetFinalPathNameByHandle(fd.native(), .{}, buf); - } - - @panic("TODO unsupported platform for getFdPathW"); -} - -fn lenSliceTo(pointer: anytype, comptime end: std.meta.Elem(@TypeOf(pointer))) usize { - switch (@typeInfo(@TypeOf(pointer))) { - .pointer => |ptr_info| switch (ptr_info.size) { - .one => switch (@typeInfo(ptr_info.child)) { - .array => |array_info| { - if (array_info.sentinel_ptr) |sentinel_ptr| { - const sentinel = @as(*align(1) const array_info.child, @ptrCast(sentinel_ptr)).*; - if (sentinel == end) { - return std.mem.indexOfSentinel(array_info.child, end, pointer); - } - } - return std.mem.indexOfScalar(array_info.child, pointer, end) orelse array_info.len; - }, - else => {}, - }, - .many => if (ptr_info.sentinel_ptr) |sentinel_ptr| { - const sentinel = @as(*align(1) const ptr_info.child, @ptrCast(sentinel_ptr)).*; - // We may be looking for something other than the sentinel, - // but iterating past the sentinel would be a bug so we need - // to check for both. - var i: usize = 0; - while (pointer[i] != end and pointer[i] != sentinel) i += 1; - return i; - }, - .c => { - assert(pointer != null); - return std.mem.indexOfSentinel(ptr_info.child, end, pointer); - }, - .slice => { - if (ptr_info.sentinel_ptr) |sentinel_ptr| { - const sentinel = @as(*align(1) const ptr_info.child, @ptrCast(sentinel_ptr)).*; - if (sentinel == end) { - return std.mem.indexOfSentinel(ptr_info.child, sentinel, pointer); - } - } - return std.mem.indexOfScalar(ptr_info.child, pointer, end) orelse pointer.len; - }, - }, - else => {}, - } - @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(@TypeOf(pointer))); -} - -/// Helper for the return type of sliceTo() -fn SliceTo(comptime T: type, comptime end: std.meta.Elem(T)) type { - switch (@typeInfo(T)) { - .optional => |optional_info| { - return ?SliceTo(optional_info.child, end); - }, - .pointer => |ptr_info| { - var new_ptr_info = ptr_info; - new_ptr_info.size = .slice; - switch (ptr_info.size) { - .one => switch (@typeInfo(ptr_info.child)) { - .array => |array_info| { - new_ptr_info.child = array_info.child; - // The return type must only be sentinel terminated if we are guaranteed - // to find the value searched for, which is only the case if it matches - // the sentinel of the type passed. - if (array_info.sentinel_ptr) |sentinel_ptr| { - const sentinel = @as(*align(1) const array_info.child, @ptrCast(sentinel_ptr)).*; - if (end == sentinel) { - new_ptr_info.sentinel_ptr = &end; - } else { - new_ptr_info.sentinel_ptr = null; - } - } - }, - else => {}, - }, - .many, .slice => { - // The return type must only be sentinel terminated if we are guaranteed - // to find the value searched for, which is only the case if it matches - // the sentinel of the type passed. - if (ptr_info.sentinel_ptr) |sentinel_ptr| { - const sentinel = @as(*align(1) const ptr_info.child, @ptrCast(sentinel_ptr)).*; - if (end == sentinel) { - new_ptr_info.sentinel_ptr = &end; - } else { - new_ptr_info.sentinel_ptr = null; - } - } - }, - .c => { - new_ptr_info.sentinel_ptr = &end; - // C pointers are always allowzero, but we don't want the return type to be. - assert(new_ptr_info.is_allowzero); - new_ptr_info.is_allowzero = false; - }, - } - return @Type(.{ .pointer = new_ptr_info }); - }, - else => {}, - } - @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T)); -} - -/// Takes an array, a pointer to an array, a sentinel-terminated pointer, or a slice and -/// iterates searching for the first occurrence of `end`, returning the scanned slice. -/// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned. -/// If the pointer type is sentinel terminated and `end` matches that terminator, the -/// resulting slice is also sentinel terminated. -/// Pointer properties such as mutability and alignment are preserved. -/// C pointers are assumed to be non-null. -pub fn sliceTo(pointer: anytype, comptime end: std.meta.Elem(@TypeOf(pointer))) SliceTo(@TypeOf(pointer), end) { - if (@typeInfo(@TypeOf(pointer)) == .optional) { - const non_null = pointer orelse return null; - return sliceTo(non_null, end); - } - const Result = SliceTo(@TypeOf(pointer), end); - const length = lenSliceTo(pointer, end); - const ptr_info = @typeInfo(Result).pointer; - if (ptr_info.sentinel_ptr) |s_ptr| { - const s = @as(*align(1) const ptr_info.child, @ptrCast(s_ptr)).*; - return pointer[0..length :s]; - } else { - return pointer[0..length]; - } -} - -pub const Semver = @import("./semver/semver.zig"); -pub const ImportRecord = @import("./options_types/import_record.zig").ImportRecord; -pub const ImportKind = @import("./options_types/import_record.zig").ImportKind; - -pub const Watcher = @import("./watcher/Watcher.zig"); - -pub fn concat(comptime T: type, dest: []T, src: []const []const T) void { - var remain = dest; - for (src) |group| { - bun.copy(T, remain[0..group.len], group); - remain = remain[group.len..]; - } -} - -pub const renamer = @import("./js_printer/renamer.zig"); - -pub const SourceMap = @import("./sourcemap/sourcemap.zig"); - -/// Attempt to coerce some value into a byte slice. -pub fn asByteSlice(buffer: anytype) []const u8 { - return switch (@TypeOf(buffer)) { - [*:0]u8, [*:0]const u8 => buffer[0..len(buffer)], - [*c]const u8, [*c]u8 => span(buffer), - - else => buffer, // attempt to coerce to []const u8 - }; -} - -comptime { - _ = @import("./runtime/node/buffer.zig").BufferVectorized.fill; - _ = @import("./runtime/cli/upgrade_command.zig").Version; - _ = @import("./jsc/resolve_path_jsc.zig"); - _ = @import("./jsc/resolver_jsc.zig"); -} - -pub fn DebugOnlyDisabler(comptime Type: type) type { - return struct { - const T = Type; - threadlocal var disable_create_in_debug: if (Environment.isDebug) usize else u0 = 0; - pub inline fn disable() void { - if (comptime !Environment.isDebug) return; - disable_create_in_debug += 1; - } - - pub inline fn enable() void { - if (comptime !Environment.isDebug) return; - disable_create_in_debug -= 1; - } - - pub inline fn assert() void { - if (comptime !Environment.isDebug) return; - if (disable_create_in_debug > 0) { - Output.panic(comptime "[" ++ @typeName(T) ++ "] called while disabled (did you forget to call enable?)", .{}); - } - } - }; -} - -const FailingAllocator = struct { - fn alloc(_: *anyopaque, _: usize, _: u8, _: usize) ?[*]u8 { - if (comptime Environment.allow_assert) { - unreachablePanic("FailingAllocator should never be reached. This means some memory was not defined", .{}); - } - return null; - } - - fn resize(_: *anyopaque, _: []u8, _: u8, _: usize, _: usize) bool { - if (comptime Environment.allow_assert) { - unreachablePanic("FailingAllocator should never be reached. This means some memory was not defined", .{}); - } - return false; - } - - fn free( - _: *anyopaque, - _: []u8, - _: u8, - _: usize, - ) void { - unreachable; - } -}; - -/// When we want to avoid initializing a value as undefined, we can use this allocator -pub const failing_allocator = std.mem.Allocator{ .ptr = undefined, .vtable = &.{ - .alloc = FailingAllocator.alloc, - .resize = FailingAllocator.resize, - .free = FailingAllocator.free, -} }; - -var __reload_in_progress__ = std.atomic.Value(bool).init(false); -threadlocal var __reload_in_progress__on_current_thread = false; -pub fn isProcessReloadInProgressOnAnotherThread() bool { - return __reload_in_progress__.load(.monotonic) and !__reload_in_progress__on_current_thread; -} - -pub noinline fn maybeHandlePanicDuringProcessReload() void { - if (isProcessReloadInProgressOnAnotherThread()) { - Output.flush(); - if (comptime Environment.isDebug) { - Output.debugWarn("panic() called during process reload, ignoring\n", .{}); - } - - exitThread(); - } - - // This shouldn't be reachable, but it can technically be because - // pthread_exit is a request and not guaranteed. - if (isProcessReloadInProgressOnAnotherThread()) { - while (true) { - std.atomic.spinLoopHint(); - - if (comptime Environment.isPosix) { - std.posix.nanosleep(1, 0); - } - } - } -} - -extern "c" fn on_before_reload_process_linux() void; - -/// Reload Bun's process. This clones envp, argv, and gets the current -/// executable path. -/// -/// On posix, this overwrites the current process with the new process using -/// `execve`. On Windows, we dont have this API, instead relying on a dummy -/// parent process that we can signal via a special exit code. -/// -/// Must be able to allocate memory. `malloc` is not signal safe, but it's -/// best-effort. Not much we can do if it fails. -/// -/// Note that this function is called during the crash handler, in which it is -/// passed true to `may_return`. If failure occurs, one line of standard error -/// is printed and then this returns void. If `may_return == false`, then a -/// panic will occur on failure. The crash handler will not schedule two reloads -/// at once. -pub fn reloadProcess( - allocator: std.mem.Allocator, - clear_terminal: bool, - comptime may_return: bool, -) if (may_return) void else noreturn { - __reload_in_progress__.store(true, .monotonic); - __reload_in_progress__on_current_thread = true; - - if (clear_terminal) { - Output.flush(); - Output.disableBuffering(); - Output.resetTerminalAll(); - } - - Output.Source.Stdio.restore(); - - if (comptime Environment.isWindows) { - // on windows we assume that we have a parent process that is monitoring us and will restart us if we exit with a magic exit code - // see becomeWatcherManager - const rc = c.TerminateProcess(c.GetCurrentProcess(), windows.watcher_reload_exit); - if (rc == 0) { - const err = bun.windows.GetLastError(); - if (may_return) { - Output.errGeneric("Failed to reload process: {s}", .{@tagName(err)}); - return; - } - Output.panic("Error while reloading process: {s}", .{@tagName(err)}); - } else { - if (may_return) { - Output.errGeneric("Failed to reload process", .{}); - return; - } - Output.panic("Unexpected error while reloading process\n", .{}); - } - } - - const dupe_argv = allocator.allocSentinel(?[*:0]const u8, bun.argv.len, null) catch unreachable; - for (bun.argv, dupe_argv) |src, *dest| { - dest.* = (allocator.dupeZ(u8, src) catch unreachable).ptr; - } - - const environ_slice = std.mem.span(std.c.environ); - const environ = allocator.allocSentinel(?[*:0]const u8, environ_slice.len, null) catch unreachable; - for (environ_slice, environ) |src, *dest| { - if (src == null) { - dest.* = null; - } else { - dest.* = (allocator.dupeZ(u8, sliceTo(src.?, 0)) catch unreachable).ptr; - } - } - - // we must clone selfExePath incase the argv[0] was not an absolute path (what appears in the terminal) - const exec_path = (bun.selfExePath() catch unreachable).ptr; - - // we clone argv so that the memory address isn't the same as the libc one - const newargv = @as([*:null]?[*:0]const u8, @ptrCast(dupe_argv.ptr)); - - // we clone envp so that the memory address of environment variables isn't the same as the libc one - const envp = @as([*:null]?[*:0]const u8, @ptrCast(environ.ptr)); - - // macOS doesn't have CLOEXEC, so we must go through posix_spawn - if (comptime Environment.isMac) { - var actions = spawn.Actions.init() catch unreachable; - actions.inherit(.stdin()) catch unreachable; - actions.inherit(.stdout()) catch unreachable; - actions.inherit(.stderr()) catch unreachable; - - var attrs = spawn.Attr.init() catch unreachable; - attrs.resetSignals() catch {}; - - attrs.set( - c.POSIX_SPAWN_CLOEXEC_DEFAULT | - // Apple Extension: If this bit is set, rather - // than returning to the caller, posix_spawn(2) - // and posix_spawnp(2) will behave as a more - // featureful execve(2). - c.POSIX_SPAWN_SETEXEC | - c.POSIX_SPAWN_SETSIGDEF | c.POSIX_SPAWN_SETSIGMASK, - ) catch unreachable; - switch (spawn.spawnZ(exec_path, actions, attrs, @as([*:null]?[*:0]const u8, @ptrCast(newargv)), @as([*:null]?[*:0]const u8, @ptrCast(envp)))) { - .err => |err| { - if (may_return) { - Output.errGeneric("Failed to reload process: {s}", .{@tagName(err.getErrno())}); - return; - } - Output.panic("Unexpected error while reloading: {d} {s}", .{ err.errno, @tagName(err.getErrno()) }); - }, - .result => |_| { - if (may_return) { - Output.errGeneric("Failed to reload process", .{}); - return; - } - Output.panic("Unexpected error while reloading: posix_spawn returned a result", .{}); - }, - } - } else if (comptime Environment.isPosix) { - if (comptime Environment.isLinux or Environment.isFreeBSD) on_before_reload_process_linux(); - const err = std.posix.execveZ( - exec_path, - newargv, - envp, - ); - if (may_return) { - Output.errGeneric("Failed to reload process: {s}", .{@errorName(err)}); - return; - } - Output.panic("Unexpected error while reloading: {s}", .{@errorName(err)}); - } else { - @compileError("unsupported platform for reloadProcess"); - } -} - -pub var auto_reload_on_crash = false; - -pub const options = @import("./bundler/options.zig"); -pub const StringSet = struct { - map: Map, - - pub const Map = StringArrayHashMap(void); - - pub fn clone(self: *const StringSet) !StringSet { - var new_map = Map.init(self.map.allocator); - try new_map.ensureTotalCapacity(self.map.count()); - for (self.map.keys()) |key| { - new_map.putAssumeCapacity(try self.map.allocator.dupe(u8, key), {}); - } - return StringSet{ - .map = new_map, - }; - } - - pub fn init(allocator: std.mem.Allocator) StringSet { - return StringSet{ - .map = Map.init(allocator), - }; - } - - /// Initialize an empty StringSet at comptime (for use as a static constant). - /// WARNING: The resulting set must not be mutated. Any attempt to call insert(), - /// clone(), or other allocating methods will result in undefined behavior. - pub fn initComptime() StringSet { - return StringSet{ - .map = Map.initContext(undefined, .{}), - }; - } - - pub fn isEmpty(self: *const StringSet) bool { - return self.count() == 0; - } - - pub fn count(self: *const StringSet) usize { - return self.map.count(); - } - - pub fn keys(self: *const StringSet) []const []const u8 { - return self.map.keys(); - } - - pub fn insert(self: *StringSet, key: []const u8) !void { - const entry = try self.map.getOrPut(key); - if (!entry.found_existing) { - entry.key_ptr.* = try self.map.allocator.dupe(u8, key); - } - } - - pub fn contains(self: *StringSet, key: []const u8) bool { - return self.map.contains(key); - } - - pub fn swapRemove(self: *StringSet, key: []const u8) bool { - return self.map.swapRemove(key); - } - - pub fn clearAndFree(self: *StringSet) void { - for (self.map.keys()) |key| { - self.map.allocator.free(key); - } - self.map.clearAndFree(); - } - - pub fn deinit(self: *StringSet) void { - for (self.map.keys()) |key| { - self.map.allocator.free(key); - } - - self.map.deinit(); - } -}; - -pub const schema = @import("./options_types/schema.zig"); - -pub const StringMap = struct { - map: Map, - dupe_keys: bool = false, - - pub const Map = StringArrayHashMap([]const u8); - - pub fn clone(self: StringMap) !StringMap { - return StringMap{ - .map = try self.map.clone(), - .dupe_keys = self.dupe_keys, - }; - } - - pub fn init(allocator: std.mem.Allocator, dupe_keys: bool) StringMap { - return StringMap{ - .map = Map.init(allocator), - .dupe_keys = dupe_keys, - }; - } - - pub fn keys(self: StringMap) []const []const u8 { - return self.map.keys(); - } - - pub fn values(self: StringMap) []const []const u8 { - return self.map.values(); - } - - pub fn count(self: StringMap) usize { - return self.map.count(); - } - - pub fn toAPI(self: StringMap) schema.api.StringMap { - return schema.api.StringMap{ - .keys = self.keys(), - .values = self.values(), - }; - } - - pub fn insert(self: *StringMap, key: []const u8, value: []const u8) !void { - const entry = try self.map.getOrPut(key); - if (!entry.found_existing) { - if (self.dupe_keys) - entry.key_ptr.* = try self.map.allocator.dupe(u8, key); - } else { - self.map.allocator.free(entry.value_ptr.*); - } - - entry.value_ptr.* = try self.map.allocator.dupe(u8, value); - } - pub const put = insert; - - pub fn get(self: *const StringMap, key: []const u8) ?[]const u8 { - return self.map.get(key); - } - - pub fn sort(self: *StringMap, sort_ctx: anytype) void { - self.map.sort(sort_ctx); - } - - pub fn deinit(self: *StringMap) void { - for (self.map.values()) |value| { - self.map.allocator.free(value); - } - - if (self.dupe_keys) { - for (self.map.keys()) |key| { - self.map.allocator.free(key); - } - } - - self.map.deinit(); - } -}; - -pub const DotEnv = @import("./dotenv/env_loader.zig"); -pub const bundle_v2 = @import("./bundler/bundle_v2.zig"); -pub const Loader = bundle_v2.Loader; -pub const BundleV2 = bundle_v2.BundleV2; -pub const ParseTask = bundle_v2.ParseTask; - -pub const threading = @import("./threading/threading.zig"); -pub const Mutex = threading.Mutex; -pub const Futex = threading.Futex; -pub const ThreadPool = threading.ThreadPool; -pub const UnboundedQueue = threading.UnboundedQueue; - -pub fn threadLocalAllocator() std.mem.Allocator { - if (comptime use_mimalloc) { - return MimallocArena.getThreadLocalDefault(); - } - - return default_allocator; -} - -pub fn HiveRef(comptime T: type, comptime capacity: u16) type { - return struct { - const HiveAllocator = HiveArray(@This(), capacity).Fallback; - ref_count: u32, - allocator: *HiveAllocator, - value: T, - - pub fn init(value: T, allocator: *HiveAllocator) !*@This() { - const this = try allocator.tryGet(); - this.* = .{ - .ref_count = 1, - .allocator = allocator, - .value = value, - }; - return this; - } - - pub fn ref(this: *@This()) *@This() { - this.ref_count += 1; - return this; - } - - pub fn unref(this: *@This()) ?*@This() { - const ref_count = this.ref_count; - this.ref_count = ref_count - 1; - if (ref_count == 1) { - if (@hasDecl(T, "deinit")) { - this.value.deinit(); - } - this.allocator.put(this); - return null; - } - return this; - } - }; -} - -pub const tracy = @import("./perf/tracy.zig"); -pub const trace = tracy.trace; - -pub fn openFileForPath(file_path: [:0]const u8) !std.fs.File { - if (Environment.isWindows) - return std.fs.cwd().openFileZ(file_path, .{}); - - const O_PATH = if (comptime Environment.isLinux) O.PATH else O.RDONLY; - const flags: u32 = O.CLOEXEC | O.NOCTTY | O_PATH; - - const fd = try std.posix.openZ(file_path, O.toPacked(flags), 0); - return std.fs.File{ - .handle = fd, - }; -} - -pub fn openDirForPath(file_path: [:0]const u8) !std.fs.Dir { - if (Environment.isWindows) - return std.fs.cwd().openDirZ(file_path, .{}); - - const O_PATH = if (comptime Environment.isLinux) O.PATH else O.RDONLY; - const flags: u32 = O.CLOEXEC | O.NOCTTY | O.DIRECTORY | O_PATH; - - const fd = try std.posix.openZ(file_path, O.toPacked(flags), 0); - return std.fs.Dir{ - .fd = fd, - }; -} - -pub const Generation = u16; - -pub const zstd = @import("./zstd/zstd.zig"); -pub const StringPointer = schema.api.StringPointer; -pub const StandaloneModuleGraph = @import("./standalone_graph/StandaloneModuleGraph.zig").StandaloneModuleGraph; - -pub const string = @import("./string/string.zig"); -pub const String = string.String; -pub const ZigString = jsc.ZigString; -pub const StringJoiner = string.StringJoiner; -pub const SliceWithUnderlyingString = string.SliceWithUnderlyingString; -pub const PathString = string.PathString; -pub const HashedString = string.HashedString; -pub const MutableString = string.MutableString; -pub const StringBuilder = string.StringBuilder; - -/// Utilities for immutable strings -pub const strings = string.immutable; -pub const CodePoint = strings.CodePoint; - -pub const WTF = struct { - /// The String type from WebKit's WTF library. - pub const StringImpl = string.WTFStringImpl; - pub const _StringImplStruct = string.WTFStringImplStruct; -}; - -pub const Wyhash11 = @import("./wyhash/wyhash.zig").Wyhash11; - -const TODO_LOG = Output.scoped(.TODO, .visible); -pub inline fn todo(src: std.builtin.SourceLocation, value: anytype) @TypeOf(value) { - if (comptime Environment.allow_assert) { - TODO_LOG("{s}() at {s}:{d}:{d}", .{ src.fn_name, src.file, src.line, src.column }); - } - - return value; -} - -pub const HOST_NAME_MAX = if (Environment.isWindows) - // On Windows the maximum length, in bytes, of the string returned in the buffer pointed to by the name parameter is dependent on the namespace provider, but this string must be 256 bytes or less. - // So if a buffer of 256 bytes is passed in the name parameter and the namelen parameter is set to 256, the buffer size will always be adequate. - // https://learn.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-gethostname - 256 -else - std.posix.HOST_NAME_MAX; - -const WindowsStat = extern struct { - dev: u32, - ino: u32, - nlink: usize, - - mode: Mode, - uid: u32, - gid: u32, - rdev: u32, - size: u32, - blksize: isize, - blocks: i64, - - atim: std.c.timespec, - mtim: std.c.timespec, - ctim: std.c.timespec, - - pub fn birthtime(_: *const WindowsStat) std.c.timespec { - return std.c.timespec{ .tv_nsec = 0, .tv_sec = 0 }; - } - - pub fn mtime(this: *const WindowsStat) std.c.timespec { - return this.mtim; - } - - pub fn ctime(this: *const WindowsStat) std.c.timespec { - return this.ctim; - } - - pub fn atime(this: *const WindowsStat) std.c.timespec { - return this.atim; - } -}; - -pub const Stat = if (Environment.isWindows) windows.libuv.uv_stat_t else std.posix.Stat; -pub const StatFS = switch (Environment.os) { - .mac, .linux, .freebsd => bun.c.struct_statfs, - .windows => windows.libuv.uv_statfs_t, - .wasm => unreachable, -}; - -pub var argv: [][:0]const u8 = &[_][:0]const u8{}; -/// Number of arguments injected by BUN_OPTIONS environment variable. -/// Used by standalone executables to include these in the parsed options window. -pub var bun_options_argc: usize = 0; - -pub fn appendOptionsEnv(env: []const u8, comptime ArgType: type, args: *std.array_list.Managed(ArgType)) !void { - var i: usize = 0; - var offset_in_args: usize = 1; - while (i < env.len) { - // skip whitespace - while (i < env.len and std.ascii.isWhitespace(env[i])) : (i += 1) {} - if (i >= env.len) break; - - // Handle all command-line arguments with quotes preserved - const start = i; - var j = i; - - // Check if this is an option (starts with --) - const is_option = j + 2 <= env.len and env[j] == '-' and env[j + 1] == '-'; - - if (is_option) { - // Find the end of the option flag (--flag) - while (j < env.len and !std.ascii.isWhitespace(env[j]) and env[j] != '=') : (j += 1) {} - - const end_of_flag = j; - var found_equals = false; - - // Check for equals sign - if (j < env.len and env[j] == '=') { - found_equals = true; - j += 1; // Move past the equals sign - } else if (j < env.len and std.ascii.isWhitespace(env[j])) { - j += 1; // Move past the space - // Skip any additional whitespace - while (j < env.len and std.ascii.isWhitespace(env[j])) : (j += 1) {} - } - - // Handle quoted values - if (j < env.len and (env[j] == '\'' or env[j] == '"')) { - const quote_char = env[j]; - j += 1; // Move past opening quote - - // Find the closing quote - while (j < env.len and env[j] != quote_char) : (j += 1) {} - if (j < env.len) j += 1; // Move past closing quote - } else if (found_equals) { - // If we had --flag=value (no quotes), find next whitespace - while (j < env.len and !std.ascii.isWhitespace(env[j])) : (j += 1) {} - } else { - // No value found after flag (e.g., `--flag1 --flag2`). - // Reset j to end of flag name so we don't include trailing whitespace. - j = end_of_flag; - } - - // Copy the entire argument including quotes - const arg_len = j - start; - - const arg = switch (ArgType) { - bun.String => bun.String.cloneUTF8(env[start..j]), - [:0]const u8 => arg: { - const arg = try bun.default_allocator.allocSentinel(u8, arg_len, 0); - @memcpy(arg, env[start..j]); - break :arg arg; - }, - else => @compileError("unexpected arg type"), - }; - - try args.insert(offset_in_args, arg); - offset_in_args += 1; - - i = j; - continue; - } - - // Non-option arguments or standalone values - var buf = std.array_list.Managed(u8).init(bun.default_allocator); - - var in_single = false; - var in_double = false; - var escape = false; - while (i < env.len) : (i += 1) { - const ch = env[i]; - if (escape) { - try buf.append(ch); - escape = false; - continue; - } - - if (ch == '\\') { - escape = true; - continue; - } - - if (in_single) { - if (ch == '\'') { - in_single = false; - } else { - try buf.append(ch); - } - continue; - } - - if (in_double) { - if (ch == '"') { - in_double = false; - } else { - try buf.append(ch); - } - continue; - } - - if (ch == '\'') { - in_single = true; - } else if (ch == '"') { - in_double = true; - } else if (std.ascii.isWhitespace(ch)) { - break; - } else { - try buf.append(ch); - } - } - - switch (ArgType) { - bun.String => { - defer buf.deinit(); - try args.insert(offset_in_args, bun.String.cloneUTF8(buf.items)); - }, - [:0]const u8 => { - try buf.append(0); - const owned = try buf.toOwnedSlice(); - try args.insert(offset_in_args, owned[0 .. owned.len - 1 :0]); - }, - else => @compileError("unexpected arg type"), - } - - offset_in_args += 1; - } -} - -pub fn initArgv() !void { - if (comptime Environment.isPosix) { - argv = try bun.default_allocator.alloc([:0]const u8, std.os.argv.len); - for (0..argv.len) |i| { - argv[i] = std.mem.sliceTo(std.os.argv[i], 0); - } - } else if (comptime Environment.isWindows) { - // Zig's implementation of `std.process.argsAlloc()`on Windows platforms - // is not reliable, specifically the way it splits the command line string. - // - // For example, an arg like "foo\nbar" will be - // erroneously split into two arguments: "foo" and "bar". - // - // To work around this, we can simply call the Windows API functions - // that do this for us. - // - // Updates in Zig v0.12 related to Windows cmd line parsing may fix this, - // see (here: https://ziglang.org/download/0.12.0/release-notes.html#Windows-Command-Line-Argument-Parsing), - // so this may only need to be a temporary workaround. - const cmdline_ptr = bun.windows.GetCommandLineW(); - var length: c_int = 0; - - // As per the documentation: - // > The lifetime of the returned value is managed by the system, - // applications should not free or modify this value. - const argvu16_ptr = windows.CommandLineToArgvW(cmdline_ptr, &length) orelse { - switch (sys.getErrno({})) { - // may be returned if can't alloc enough space for the str - .NOMEM => return error.OutOfMemory, - // may be returned if it's invalid - .INVAL => return error.InvalidArgument, - // TODO: anything else? - else => return error.Unknown, - } - }; - - const argvu16 = argvu16_ptr[0..@intCast(length)]; - const out_argv = try bun.default_allocator.alloc([:0]const u8, @intCast(length)); - var string_builder = StringBuilder{}; - - for (argvu16) |argraw| { - const arg = std.mem.span(argraw); - string_builder.count16Z(arg); - } - - try string_builder.allocate(bun.default_allocator); - - for (argvu16, out_argv) |argraw, *out| { - const arg = std.mem.span(argraw); - - // Command line is expected to be valid UTF-16le - // ...but sometimes, it's not valid. https://github.com/oven-sh/bun/issues/11610 - out.* = string_builder.append16(arg, default_allocator) orelse @panic("Failed to allocate memory for argv"); - } - - argv = out_argv; - } else { - argv = try std.process.argsAlloc(bun.default_allocator); - } - - if (bun.env_var.BUN_OPTIONS.get()) |opts| { - const original_len = argv.len; - var argv_list = std.array_list.Managed([:0]const u8).fromOwnedSlice(bun.default_allocator, argv); - try appendOptionsEnv(opts, [:0]const u8, &argv_list); - argv = argv_list.items; - bun_options_argc = argv.len - original_len; - } -} - -pub const spawn = @import("./runtime/api/bun/spawn.zig").PosixSpawn; - -pub fn isRegularFile(mode: anytype) bool { - return S.ISREG(@intCast(mode)); -} - -pub const LazyBoolValue = enum { - unknown, - no, - yes, -}; -/// Create a lazily computed boolean value. -/// Getter must be a function that takes a pointer to the parent struct and returns a boolean. -/// Parent must be a type which contains the field we are getting. -pub fn LazyBool( - comptime Getter: anytype, - comptime Parent: type, - comptime field: []const u8, -) type { - return struct { - value: LazyBoolValue = .unknown, - - pub fn get(self: *@This()) bool { - if (self.value == .unknown) { - const parent: *Parent = @alignCast(@fieldParentPtr(field, self)); - self.value = switch (Getter(parent)) { - true => .yes, - false => .no, - }; - } - - return self.value == .yes; - } - }; -} - -pub fn serializable(input: anytype) @TypeOf(input) { - const T = @TypeOf(input); - comptime { - if (trait.isExternContainer(T)) { - if (@typeInfo(T) == .@"union") { - @compileError("Extern unions must be serialized with serializableInto"); - } - } - } - var zeroed: [@sizeOf(T)]u8 align(@alignOf(T)) = std.mem.zeroes([@sizeOf(T)]u8); - const result: *T = @ptrCast(&zeroed); - - inline for (comptime std.meta.fieldNames(T)) |field_name| { - @field(result, field_name) = @field(input, field_name); - } - - return result.*; -} - -pub inline fn serializableInto(comptime T: type, init: anytype) T { - var zeroed: [@sizeOf(T)]u8 align(@alignOf(T)) = std.mem.zeroes([@sizeOf(T)]u8); - const result: *T = @ptrCast(&zeroed); - - inline for (comptime std.meta.fieldNames(@TypeOf(init))) |field_name| { - @field(result, field_name) = @field(init, field_name); - } - - return result.*; -} - -/// Like std.fs.Dir.makePath except instead of infinite looping on dangling -/// symlink, it deletes the symlink and tries again. -pub fn makePath(dir: std.fs.Dir, sub_path: []const u8) !void { - var it = try std.fs.path.componentIterator(sub_path); - var component = it.last() orelse return; - while (true) { - dir.makeDir(component.path) catch |err| switch (err) { - error.PathAlreadyExists => { - var path_buf2: [MAX_PATH_BYTES * 2]u8 = undefined; - copy(u8, &path_buf2, component.path); - - path_buf2[component.path.len] = 0; - const path_to_use = path_buf2[0..component.path.len :0]; - const result = try sys.lstat(path_to_use).unwrap(); - const is_dir = S.ISDIR(@intCast(result.mode)); - // dangling symlink - if (!is_dir) { - dir.deleteTree(component.path) catch {}; - continue; - } - }, - error.FileNotFound => |e| { - component = it.previous() orelse return e; - continue; - }, - else => |e| return e, - }; - component = it.next() orelse return; - } -} - -/// Like std.fs.Dir.makePath except instead of infinite looping on dangling -/// symlink, it deletes the symlink and tries again. -pub fn makePathW(dir: std.fs.Dir, sub_path: []const u16) !void { - // was going to copy/paste makePath and use all W versions but they didn't all exist - // and this buffer was needed anyway - var buf: PathBuffer = undefined; - const buf_len = simdutf.convert.utf16.to.utf8.le(sub_path, &buf); - return makePath(dir, buf[0..buf_len]); -} - -pub const Async = @import("async"); - -/// This is a helper for writing path string literals that are compatible with Windows. -/// Returns the string as-is on linux, on windows replace `/` with `\` -pub inline fn pathLiteral(comptime literal: anytype) *const [literal.len:0]u8 { - if (!Environment.isWindows) return @ptrCast(literal); - return comptime { - var buf: [literal.len:0]u8 = undefined; - for (literal, 0..) |char, i| { - buf[i] = if (char == '/') '\\' else char; - assert(buf[i] != 0 and buf[i] < 128); - } - buf[buf.len] = 0; - const final = buf[0..buf.len :0].*; - return &final; - }; -} - -/// Same as `pathLiteral`, but the character type is chosen from platform. -pub inline fn OSPathLiteral(comptime literal: anytype) *const [literal.len:0]OSPathChar { - if (!Environment.isWindows) return @ptrCast(literal); - return comptime { - var buf: [literal.len:0]OSPathChar = undefined; - for (literal, 0..) |char, i| { - buf[i] = if (char == '/') '\\' else char; - assert(buf[i] != 0 and buf[i] < 128); - } - buf[buf.len] = 0; - const final = buf[0..buf.len :0].*; - return &final; - }; -} - -pub const MakePath = struct { - const w = std.os.windows; - - // TODO(@paperclover): upstream making this public into zig std - // there is zero reason this must be copied - // - /// Calls makeOpenDirAccessMaskW iteratively to make an entire path - /// (i.e. creating any parent directories that do not exist). - /// Opens the dir if the path already exists and is a directory. - /// This function is not atomic, and if it returns an error, the file system may - /// have been modified regardless. - fn makeOpenPathAccessMaskW(self: std.fs.Dir, comptime T: type, sub_path: []const T, access_mask: u32, no_follow: bool) !std.fs.Dir { - const Iterator = std.fs.path.ComponentIterator(.windows, T); - var it = try Iterator.init(sub_path); - // If there are no components in the path, then create a dummy component with the full path. - var component = it.last() orelse Iterator.Component{ - .name = &.{}, - .path = sub_path, - }; - - while (true) { - const sub_path_w = if (comptime T == u16) - try w.wToPrefixedFileW(self.fd, - // TODO: report this bug - // they always copy it - // it doesn't need to be [:0]const u16 - @ptrCast(component.path)) - else - try w.sliceToPrefixedFileW(self.fd, component.path); - var result = makeOpenDirAccessMaskW(self, sub_path_w.span().ptr, access_mask, .{ - .no_follow = no_follow, - .create_disposition = w.FILE_OPEN_IF, - }) catch |err| switch (err) { - error.FileNotFound => |e| { - component = it.previous() orelse return e; - continue; - }, - else => |e| return e, - }; - - component = it.next() orelse return result; - // Don't leak the intermediate file handles - result.close(); - } - } - const MakeOpenDirAccessMaskWOptions = struct { - no_follow: bool, - create_disposition: u32, - }; - - fn makeOpenDirAccessMaskW(self: std.fs.Dir, sub_path_w: [*:0]const u16, access_mask: u32, flags: MakeOpenDirAccessMaskWOptions) !std.fs.Dir { - var result = std.fs.Dir{ - .fd = undefined, - }; - - const path_len_bytes = @as(u16, @intCast(std.mem.sliceTo(sub_path_w, 0).len * 2)); - var nt_name = w.UNICODE_STRING{ - .Length = path_len_bytes, - .MaximumLength = path_len_bytes, - .Buffer = @constCast(sub_path_w), - }; - var attr = w.OBJECT_ATTRIBUTES{ - .Length = @sizeOf(w.OBJECT_ATTRIBUTES), - .RootDirectory = if (std.fs.path.isAbsoluteWindowsW(sub_path_w)) null else self.fd, - .Attributes = 0, // Note we do not use OBJ_CASE_INSENSITIVE here. - .ObjectName = &nt_name, - .SecurityDescriptor = null, - .SecurityQualityOfService = null, - }; - const open_reparse_point: w.DWORD = if (flags.no_follow) w.FILE_OPEN_REPARSE_POINT else 0x0; - var status: w.IO_STATUS_BLOCK = undefined; - const rc = w.ntdll.NtCreateFile( - &result.fd, - access_mask, - &attr, - &status, - null, - w.FILE_ATTRIBUTE_NORMAL, - w.FILE_SHARE_READ | w.FILE_SHARE_WRITE | w.FILE_SHARE_DELETE, - flags.create_disposition, - w.FILE_DIRECTORY_FILE | w.FILE_SYNCHRONOUS_IO_NONALERT | w.FILE_OPEN_FOR_BACKUP_INTENT | w.FILE_WRITE_THROUGH | open_reparse_point, - null, - 0, - ); - - switch (rc) { - .SUCCESS => return result, - .OBJECT_NAME_INVALID => return error.BadPathName, - .OBJECT_NAME_NOT_FOUND => return error.FileNotFound, - .OBJECT_PATH_NOT_FOUND => return error.FileNotFound, - .NOT_A_DIRECTORY => return error.NotDir, - // This can happen if the directory has 'List folder contents' permission set to 'Deny' - // and the directory is trying to be opened for iteration. - .ACCESS_DENIED => return error.AccessDenied, - .INVALID_PARAMETER => return error.BadPathName, - .SHARING_VIOLATION => return error.SharingViolation, - else => return w.unexpectedStatus(rc), - } - } - - pub fn makeOpenPath(self: std.fs.Dir, sub_path: anytype, opts: std.fs.Dir.OpenOptions) !std.fs.Dir { - if (comptime Environment.isWindows) { - return makeOpenPathAccessMaskW( - self, - std.meta.Elem(@TypeOf(sub_path)), - sub_path, - w.STANDARD_RIGHTS_READ | - w.FILE_READ_ATTRIBUTES | - w.FILE_READ_EA | - w.SYNCHRONIZE | - w.FILE_TRAVERSE, - false, - ); - } - - return self.makeOpenPath(sub_path, opts); - } - - /// copy/paste of `std.fs.Dir.makePath` and related functions and modified to support u16 slices. - /// inside `MakePath` scope to make deleting later easier. - /// TODO(dylan-conway) delete `MakePath` - pub fn makePath(comptime T: type, self: std.fs.Dir, sub_path: []const T) !void { - if (Environment.isWindows) { - var dir = try makeOpenPath(self, sub_path, .{}); - dir.close(); - return; - } - - var it = try componentIterator(T, sub_path); - var component = it.last() orelse return; - while (true) { - std.fs.Dir.makeDir(self, component.path) catch |err| switch (err) { - error.PathAlreadyExists => { - // TODO stat the file and return an error if it's not a directory - // this is important because otherwise a dangling symlink - // could cause an infinite loop - }, - error.FileNotFound => |e| { - component = it.previous() orelse return e; - continue; - }, - else => |e| return e, - }; - component = it.next() orelse return; - } - } - - fn componentIterator(comptime T: type, path_: []const T) !std.fs.path.ComponentIterator(switch (builtin.target.os.tag) { - .windows => .windows, - .uefi => .uefi, - else => .posix, - }, T) { - return std.fs.path.ComponentIterator(switch (builtin.target.os.tag) { - .windows => .windows, - .uefi => .uefi, - else => .posix, - }, T).init(path_); - } -}; - -pub const Dirname = struct { - /// copy/paste of `std.fs.path.dirname` and related functions and modified to support u16 slices. - /// inside `Dirname` scope to make deleting later easier. - /// TODO(dylan-conway) delete `Dirname` - pub fn dirname(comptime T: type, path_: []const T) ?[]const T { - if (builtin.target.os.tag == .windows) { - return dirnameWindows(T, path_); - } else { - return std.fs.path.dirnamePosix(path_); - } - } - - fn dirnameWindows(comptime T: type, path_: []const T) ?[]const T { - if (path_.len == 0) - return null; - - const root_slice = diskDesignatorWindows(T, path_); - if (path_.len == root_slice.len) - return null; - - const have_root_slash = path_.len > root_slice.len and (path_[root_slice.len] == '/' or path_[root_slice.len] == '\\'); - - var end_index: usize = path_.len - 1; - - while (path_[end_index] == '/' or path_[end_index] == '\\') { - if (end_index == 0) - return null; - end_index -= 1; - } - - while (path_[end_index] != '/' and path_[end_index] != '\\') { - if (end_index == 0) - return null; - end_index -= 1; - } - - if (have_root_slash and end_index == root_slice.len) { - end_index += 1; - } - - if (end_index == 0) - return null; - - return path_[0..end_index]; - } - - fn diskDesignatorWindows(comptime T: type, path_: []const T) []const T { - return windowsParsePath(T, path_).disk_designator; - } - - fn windowsParsePath(comptime T: type, path_: []const T) WindowsPath(T) { - const WindowsPath_ = WindowsPath(T); - if (path_.len >= 2 and path_[1] == ':') { - return WindowsPath_{ - .is_abs = if (comptime T == u16) std.fs.path.isAbsoluteWindowsWTF16(path_) else std.fs.path.isAbsolute(path_), - .kind = WindowsPath_.Kind.Drive, - .disk_designator = path_[0..2], - }; - } - if (path_.len >= 1 and (path_[0] == '/' or path_[0] == '\\') and - (path_.len == 1 or (path_[1] != '/' and path_[1] != '\\'))) - { - return WindowsPath_{ - .is_abs = true, - .kind = WindowsPath_.Kind.None, - .disk_designator = path_[0..0], - }; - } - const relative_path = WindowsPath_{ - .kind = WindowsPath_.Kind.None, - .disk_designator = &[_]T{}, - .is_abs = false, - }; - if (path_.len < "//a/b".len) { - return relative_path; - } - - inline for ("/\\") |this_sep| { - const two_sep = [_]T{ this_sep, this_sep }; - if (std.mem.startsWith(T, path_, &two_sep)) { - if (path_[2] == this_sep) { - return relative_path; - } - - var it = std.mem.tokenizeScalar(T, path_, this_sep); - _ = (it.next() orelse return relative_path); - _ = (it.next() orelse return relative_path); - return WindowsPath_{ - .is_abs = if (T == u16) std.fs.path.isAbsoluteWindowsWTF16(path_) else std.fs.path.isAbsolute(path_), - .kind = WindowsPath_.Kind.NetworkShare, - .disk_designator = path_[0..it.index], - }; - } - } - return relative_path; - } - - fn WindowsPath(comptime T: type) type { - return struct { - is_abs: bool, - kind: Kind, - disk_designator: []const T, - - pub const Kind = enum { - None, - Drive, - NetworkShare, - }; - }; - } -}; - -pub noinline fn outOfMemory() noreturn { - @branchHint(.cold); - crash_handler.crashHandler(.out_of_memory, null, @returnAddress()); -} - -pub const handleOom = @import("./crash_handler/handle_oom.zig").handleOom; - -/// Like `std.heap.StackFallbackAllocator` but takes a runtime-provided buffer -/// instead of a comptime-sized inline array. Use this when the "stack" buffer -/// is heap-cached (e.g. in RareData) and you want the same try-fixed-then-fallback -/// semantics without putting a large buffer on the actual call stack. -pub const StackFallbackAllocator = struct { - fixed: std.heap.FixedBufferAllocator, - fallback: std.mem.Allocator, - - pub fn init(buf: []u8, fallback: std.mem.Allocator) StackFallbackAllocator { - return .{ - .fixed = std.heap.FixedBufferAllocator.init(buf), - .fallback = fallback, - }; - } - - pub fn get(self: *StackFallbackAllocator) std.mem.Allocator { - return .{ - .ptr = self, - .vtable = &.{ - .alloc = alloc, - .resize = resize, - .remap = remap, - .free = free, - }, - }; - } - - fn alloc(ctx: *anyopaque, n: usize, alignment: std.mem.Alignment, ra: usize) ?[*]u8 { - const self: *StackFallbackAllocator = @ptrCast(@alignCast(ctx)); - return std.heap.FixedBufferAllocator.alloc(&self.fixed, n, alignment, ra) orelse - self.fallback.rawAlloc(n, alignment, ra); - } - - fn resize(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, new_len: usize, ra: usize) bool { - const self: *StackFallbackAllocator = @ptrCast(@alignCast(ctx)); - if (self.fixed.ownsPtr(buf.ptr)) { - return std.heap.FixedBufferAllocator.resize(&self.fixed, buf, alignment, new_len, ra); - } - return self.fallback.rawResize(buf, alignment, new_len, ra); - } - - fn remap(ctx: *anyopaque, mem: []u8, alignment: std.mem.Alignment, new_len: usize, ra: usize) ?[*]u8 { - const self: *StackFallbackAllocator = @ptrCast(@alignCast(ctx)); - if (self.fixed.ownsPtr(mem.ptr)) { - return std.heap.FixedBufferAllocator.remap(&self.fixed, mem, alignment, new_len, ra); - } - return self.fallback.rawRemap(mem, alignment, new_len, ra); - } - - fn free(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, ra: usize) void { - const self: *StackFallbackAllocator = @ptrCast(@alignCast(ctx)); - if (self.fixed.ownsPtr(buf.ptr)) { - return std.heap.FixedBufferAllocator.free(&self.fixed, buf, alignment, ra); - } - return self.fallback.rawFree(buf, alignment, ra); - } -}; - -pub fn todoPanic( - src: std.builtin.SourceLocation, - comptime format: []const u8, - args: anytype, -) noreturn { - @branchHint(.cold); - analytics.Features.todo_panic = 1; - Output.panic("TODO: " ++ format ++ " ({s}:{d})", args ++ .{ src.file, src.line }); -} - -/// Wrapper around allocator.create(T) that safely initializes the pointer. Prefer this over -/// `std.mem.Allocator.create`, but prefer using `bun.new` over `create(default_allocator, T, t)` -pub fn create(allocator: std.mem.Allocator, comptime T: type, t: T) *T { - const pointer = allocator.create(T) catch outOfMemory(); - pointer.* = t; - return pointer; -} - -pub const heap_breakdown = @import("./bun_alloc/heap_breakdown.zig"); - -/// Globally-allocate a value on the heap. Must free with `bun.destroy`. -/// Prefer this over `default_allocator.create` -/// -/// By using this over the default allocator, you gain access to: -/// - Automatic named heaps on macOS. -/// - Additional assertions when freeing memory. -/// -/// On macOS, you can use `Bun.unsafe.mimallocDump()` to dump the heap. -pub inline fn new(comptime T: type, init: T) *T { - return handleOom(tryNew(T, init)); -} - -/// Error-returning version of `new`. -pub inline fn tryNew(comptime T: type, init: T) OOM!*T { - const pointer = if (heap_breakdown.enabled) - try heap_breakdown.getZoneT(T).tryCreate(T, init) - else pointer: { - const pointer = try default_allocator.create(T); - pointer.* = init; - break :pointer pointer; - }; - - if (comptime Environment.allow_assert) { - const logAlloc = Output.scoped(.alloc, .visibleIf(meta.hasDecl(T, "log_allocations"))); - logAlloc("new({s}) = {*}", .{ meta.typeName(T), pointer }); - } - return pointer; -} - -/// Free a globally-allocated a value from `bun.new()`. -/// For single-item heap pointers, prefer bun.new/destroy over default_allocator -/// -/// Destruction performs additional safety checks: -/// - Generic assertions can be added to T.assertBeforeDestroy() -/// - Automatic integration with `RefCount` -pub inline fn destroy(pointer: anytype) void { - const T = std.meta.Child(@TypeOf(pointer)); - - if (Environment.allow_assert) { - const logAlloc = Output.scoped(.alloc, .visibleIf(meta.hasDecl(T, "log_allocations"))); - logAlloc("destroy({s}) = {*}", .{ meta.typeName(T), pointer }); - - // If this type implements a RefCount, make sure it is zero. - ptr.ref_count.maybeAssertNoRefs(T, pointer); - - if (comptime std.meta.hasFn(T, "assertBeforeDestroy")) { - pointer.assertBeforeDestroy(); - } - } - - if (comptime heap_breakdown.enabled) { - heap_breakdown.getZoneT(T).destroy(T, pointer); - } else { - default_allocator.destroy(pointer); - } -} - -pub inline fn dupe(comptime T: type, t: *T) *T { - return new(T, t.*); -} - -/// Implements `fn new` for a type. -/// Pair with `TrivialDeinit` if the type contains no pointers. -pub fn TrivialNew(comptime T: type) fn (T) *T { - return struct { - pub fn new(t: T) *T { - return bun.new(T, t); - } - }.new; -} - -/// Implements `fn deinit` for a type. -/// Pair with `TrivialNew` if the type contains no pointers. -pub fn TrivialDeinit(comptime T: type) fn (*T) void { - return struct { - pub fn deinit(self: *T) void { - // TODO: assert that the structure contains no pointers. - // - // // Assert the structure contains no pointers. If there are - // // pointers, you must implement `deinit` manually, ideally - // // explaining why those pointers should or should not be freed. - // const fields = switch (@typeInfo(T)) { - // .@"struct", .@"union" => |i| i.fields, - // else => @compileError("please implement `deinit` manually"), - // }; - - bun.destroy(self); - } - }.deinit; -} - -pub fn exitThread() noreturn { - const exiter = struct { - pub extern "c" fn pthread_exit(?*anyopaque) noreturn; - pub extern "kernel32" fn ExitThread(windows.DWORD) noreturn; - }; - - if (comptime Environment.isWindows) { - exiter.ExitThread(0); - } else if (comptime Environment.isPosix) { - exiter.pthread_exit(null); - } else { - @compileError("Unsupported platform"); - } -} - -pub fn deleteAllPoolsForThreadExit() void { - const pools_to_delete = .{ - jsc.WebCore.ByteListPool, - bun.w_path_buffer_pool, - bun.path_buffer_pool, - jsc.ConsoleObject.Formatter.Visited.Pool, - bun.js_parser.StringVoidMap.Pool, - }; - inline for (pools_to_delete) |pool| { - pool.deleteAll(); - } - freeAllThreadlocalBuffers(); -} - -pub const Tmpfile = @import("./sys/tmp.zig").Tmpfile; - -pub const io = @import("./io/io.zig"); - -const errno_map = errno_map: { - var max_value = 0; - for (std.enums.values(sys.SystemErrno)) |v| - max_value = @max(max_value, @intFromEnum(v)); - - var map: [max_value + 1]anyerror = undefined; - @memset(&map, error.Unexpected); - for (std.enums.values(sys.SystemErrno)) |v| - map[@intFromEnum(v)] = @field(anyerror, @tagName(v)); - - break :errno_map map; -}; - -pub fn errnoToZigErr(err: anytype) anyerror { - var num = if (@typeInfo(@TypeOf(err)) == .@"enum") - @intFromEnum(err) - else - err; - - if (Environment.allow_assert) { - assert(num != 0); - } - - if (Environment.os == .windows) { - // uv errors are negative, normalizing it will make this more resilient - num = @abs(num); - } else { - if (Environment.allow_assert) { - assert(num > 0); - } - } - - if (num > 0 and num < errno_map.len) - return errno_map[num]; - - return error.Unexpected; -} - -pub const brotli = @import("./brotli/brotli.zig"); - -pub fn iterateDir(dir: FD) DirIterator.Iterator { - return DirIterator.iterate(dir, .u8).iter; -} - -fn ReinterpretSliceType(comptime T: type, comptime slice: type) type { - const is_const = @typeInfo(slice).pointer.is_const; - return if (is_const) []const T else []T; -} - -/// Zig has a todo for @ptrCast changing the `.len`. This is the workaround -pub fn reinterpretSlice(comptime T: type, slice: anytype) ReinterpretSliceType(T, @TypeOf(slice)) { - const is_const = @typeInfo(@TypeOf(slice)).pointer.is_const; - const bytes = std.mem.sliceAsBytes(slice); - const new_ptr = @as(if (is_const) [*]const T else [*]T, @ptrCast(@alignCast(bytes.ptr))); - return new_ptr[0..@divTrunc(bytes.len, @sizeOf(T))]; -} - -pub inline fn resolveSourcePath( - comptime root: enum { codegen, src }, - comptime sub_path: []const u8, -) []const u8 { - return comptime path: { - @setEvalBranchQuota(2000000); - var buf: bun.PathBuffer = undefined; - var fba = std.heap.FixedBufferAllocator.init(&buf); - const resolved = (std.fs.path.resolve(fba.allocator(), &.{ - switch (root) { - .codegen, - => Environment.codegen_path, - .src, - => Environment.base_path ++ "/src", - }, - sub_path, - }) catch - @compileError("unreachable"))[0..].*; - break :path &resolved; - }; -} - -const RuntimeEmbedRoot = enum { - /// Relative to `/codegen`. - codegen, - /// Relative to `src` - src, - /// Reallocates the slice at every call. Avoid this if possible. An example - /// using this reasonably is referencing incremental_visualizer.html, which - /// is reloaded from disk for each request, but more importantly allows - /// maintaining the DevServer state while hacking on the visualizer. - src_eager, - /// Avoid this if possible. See `.src_eager`. - codegen_eager, -}; - -/// Load a file at runtime. This is only to be used in debug builds, -/// specifically when `Environment.codegen_embed` is false. This allows quick -/// iteration on files, as this skips the Zig compiler. Once Zig gains good -/// incremental support, the non-eager cases can be deleted. -pub fn runtimeEmbedFile( - comptime root: RuntimeEmbedRoot, - comptime sub_path: []const u8, -) [:0]const u8 { - comptime assert(Environment.isDebug); - comptime assert(!Environment.codegen_embed); - - const abs_path = switch (root) { - .codegen, .codegen_eager => resolveSourcePath(.codegen, sub_path), - .src, .src_eager => resolveSourcePath(.src, sub_path), - }; - - const static = struct { - var once = bun.once(load); - - fn load() [:0]const u8 { - return std.fs.cwd().readFileAllocOptions( - default_allocator, - abs_path, - std.math.maxInt(usize), - null, - .fromByteUnits(@alignOf(u8)), - '\x00', - ) catch |e| { - Output.panic( - \\Failed to load '{s}': {} - \\ - \\To improve iteration speed, some files are not embedded but - \\loaded at runtime, at the cost of making the binary non-portable. - \\To fix this, build with a release profile, or pass - \\-Dcodegen_embed=true to zig build. - , .{ abs_path, e }); - }; - } - }; - - if ((root == .src_eager or root == .codegen_eager) and static.once.done) { - static.once.done = false; - default_allocator.free(static.once.payload); - } - - return static.once.call(.{}); -} - -pub inline fn markWindowsOnly() if (Environment.isWindows) void else noreturn { - if (Environment.isWindows) { - return; - } - - if (@inComptime()) { - @compileError("This function is only available on Windows"); - } - - @panic("Assertion failure: this function should only be accessible on Windows."); -} - -pub inline fn markPosixOnly() if (Environment.isPosix) void else noreturn { - if (Environment.isPosix) { - return; - } - - if (@inComptime()) { - @compileError("This function is only available on POSIX"); - } - - @panic("Assertion failure: this function should only be accessible on POSIX."); -} - -pub fn linuxKernelVersion() Semver.Version { - if (comptime !Environment.isLinux) @compileError("linuxKernelVersion() is only available on Linux"); - return analytics.GenerateHeader.GeneratePlatform.kernelVersion(); -} - -pub fn selfExePath() ![:0]u8 { - const memo = struct { - var set = false; - // TODO open zig issue to make 'std.fs.selfExePath' return [:0]u8 directly - // note: this doesn't use MAX_PATH_BYTES because on windows that's 32767*3+1 yet normal paths are 255. - // should this fail it will still do so gracefully. 4096 is MAX_PATH_BYTES on posix. - var value: [ - 4096 + 1 // + 1 for the null terminator - ]u8 = undefined; - var len: usize = 0; - var lock: Mutex = .{}; - - pub fn load() ![:0]u8 { - const init = try std.fs.selfExePath(&value); - @This().len = init.len; - value[@This().len] = 0; - set = true; - return value[0..@This().len :0]; - } - }; - - // try without a lock - if (memo.set) return memo.value[0..memo.len :0]; - - // make it thread-safe - memo.lock.lock(); - defer memo.lock.unlock(); - // two calls could happen concurrently, so we must check again - if (memo.set) return memo.value[0..memo.len :0]; - return memo.load(); -} -pub const exe_suffix = if (Environment.isWindows) ".exe" else ""; - -pub const spawnSync = @This().spawn.sync.spawn; - -pub fn SliceIterator(comptime T: type) type { - return struct { - items: []const T, - index: usize = 0, - - pub fn init(items: []const T) @This() { - return .{ .items = items }; - } - - pub fn next(this: *@This()) ?T { - if (this.index >= this.items.len) return null; - defer this.index += 1; - return this.items[this.index]; - } - }; -} - -// TODO: migrate -pub const ArenaAllocator = std.heap.ArenaAllocator; - -pub const crash_handler = @import("./crash_handler/crash_handler.zig"); -pub const handleErrorReturnTrace = crash_handler.handleErrorReturnTrace; - -const assertion_failure_msg = "Internal assertion failure"; -noinline fn assertionFailure() noreturn { - if (@inComptime()) { - @compileError("assertion failure"); - } else { - @branchHint(.cold); - Output.panic(assertion_failure_msg, .{}); - } -} - -noinline fn assertionFailureAtLocation(src: std.builtin.SourceLocation) noreturn { - if (@inComptime()) { - @compileError(std.fmt.comptimePrint("assertion failure", .{})); - } else { - @branchHint(.cold); - Output.panic(assertion_failure_msg ++ " at {s}:{d}:{d}", .{ src.file, src.line, src.column }); - } -} - -noinline fn assertionFailureWithMsg(comptime msg: []const u8, args: anytype) noreturn { - if (@inComptime()) { - @compileError(std.fmt.comptimePrint("assertion failure: " ++ msg, args)); - } else { - @branchHint(.cold); - Output.panic(assertion_failure_msg ++ ": " ++ msg, args); - } -} - -/// Like `assert`, but checks only run in debug builds. -/// -/// Please wrap expensive checks in an `if` statement. -/// ```zig -/// if (comptime bun.Environment.isDebug) { -/// const expensive = doExpensiveCheck(); -/// bun.debugAssert(expensive); -/// } -/// ``` -pub fn debugAssert(cheap_value_only_plz: bool) callconv(callconv_inline) void { - if (comptime !Environment.isDebug) { - return; - } - - if (!cheap_value_only_plz) { - unreachable; // ASSERTION FAILURE - } -} - -/// Asserts that some condition holds. Assertions are stripped in release builds. -/// -/// Please use `assertf` in new code. -/// -/// Be careful what expressions you pass to this function; if the compiler cannot -/// determine that `ok` has no side effects, the argument expression may not be removed -/// from the binary. This includes calls to extern functions. -/// -/// Wrap expensive checks in an `if` statement. -/// ```zig -/// if (comptime bun.Environment.allow_assert) { -/// const expensive = doExpensiveCheck(); -/// bun.assert(expensive); -/// } -/// ``` -/// -/// Use `releaseAssert` for assertions that should not be stripped in release builds. -pub fn assert(ok: bool) callconv(callconv_inline) void { - if (comptime !Environment.allow_assert) { - return; - } - - if (!ok) { - if (comptime Environment.isDebug) - unreachable; // ASSERTION FAILURE - assertionFailure(); - } -} - -/// Asserts that some condition holds. Assertions are stripped in release builds. -/// -/// Please note that messages will be shown to users in crash reports. -/// -/// Be careful what expressions you pass to this function; if the compiler cannot -/// determine that `ok` has no side effects, the argument expression may not be removed -/// from the binary. This includes calls to extern functions. -/// -/// Wrap expensive checks in an `if` statement. -/// ```zig -/// if (comptime bun.Environment.allow_assert) { -/// const expensive = doExpensiveCheck(); -/// bun.assert(expensive, "Something happened: {}", .{ expensive }); -/// } -/// ``` -/// -/// Use `releaseAssert` for assertions that should not be stripped in release builds. -pub fn assertf(ok: bool, comptime format: []const u8, args: anytype) callconv(callconv_inline) void { - if (comptime !Environment.allow_assert) { - return; - } - - if (!ok) { - assertionFailureWithMsg(format, args); - } -} - -/// Asserts that some condition holds. These assertions are not stripped -/// in any build mode. Use `assert` to have assertions stripped in release -/// builds. -pub fn releaseAssert(ok: bool, comptime msg: []const u8, args: anytype) callconv(callconv_inline) void { - if (!ok) { - @branchHint(.cold); - Output.panic(assertion_failure_msg ++ ": " ++ msg, args); - } -} - -pub fn assertWithLocation(value: bool, src: std.builtin.SourceLocation) callconv(callconv_inline) void { - if (comptime !Environment.allow_assert) { - return; - } - - if (!value) { - if (comptime Environment.isDebug) - unreachable; // ASSERTION FAILURE - assertionFailureAtLocation(src); - } -} - -/// This has no effect on the real code but capturing 'a' and 'b' into -/// parameters makes assertion failures much easier inspect in a debugger. -pub inline fn assert_eql(a: anytype, b: anytype) void { - if (a == b) return; - if (@inComptime()) { - @compileError(std.fmt.comptimePrint("Assertion failure: {f} != {f}", .{ a, b })); - } - if (!Environment.allow_assert) return; - // Output.panic("Assertion failure: " ++ bun.deprecated.autoFormatLabelFallback(@TypeOf(a), "{f}") ++ " != " ++ bun.deprecated.autoFormatLabelFallback(@TypeOf(b), "{f}"), .{ a, b }); - // TODO - Output.panic("Assertion failure.", .{}); -} - -/// This has no effect on the real code but capturing 'a' and 'b' into -/// parameters makes assertion failures much easier inspect in a debugger. -pub fn assert_neql(a: anytype, b: anytype) callconv(callconv_inline) void { - return assert(a != b); -} - -pub fn unsafeAssert(condition: bool) callconv(callconv_inline) void { - if (!condition) - unreachable; // ASSERTION FAILURE -} - -pub const dns = @import("./dns/dns.zig"); - -pub const hw_timer = @import("./perf/hw_timer.zig"); - -pub fn getRoughTickCount(comptime mock_mode: timespec.MockMode) timespec { - if (mock_mode == .allow_mocked_time) { - if (bun.jsc.Jest.bun_test.FakeTimers.current_time.getTimespecNow()) |fake_time| { - return fake_time; - } - } - - const ns_value = hw_timer.nowNs(); - return timespec{ - .sec = @intCast(ns_value / std.time.ns_per_s), - .nsec = @intCast(ns_value % std.time.ns_per_s), - }; -} - -/// Monotonic milliseconds. Values are only meaningful relative to other calls. -pub fn getRoughTickCountMs(comptime mock_mode: timespec.MockMode) u64 { - if (mock_mode == .allow_mocked_time) { - if (bun.jsc.Jest.bun_test.FakeTimers.current_time.getTimespecNow()) |fake_time| { - return fake_time.ns() / std.time.ns_per_ms; - } - } - return hw_timer.nowMs(); -} - -pub const MaybeMockedTimespec = struct { - mocked: u64, - timespec: timespec, - - pub const epoch = MaybeMockedTimespec{ .mocked = 0, .timespec = .epoch }; - - pub fn eql(this: *const MaybeMockedTimespec, other: *const MaybeMockedTimespec) bool { - return this.mocked == other.mocked and this.timespec.eql(&other.timespec); - } -}; - -pub const timespec = extern struct { - sec: i64, - nsec: i64, - - pub const epoch: timespec = .{ .sec = 0, .nsec = 0 }; - - pub const MockMode = enum { - allow_mocked_time, - force_real_time, - }; - - pub fn eql(this: *const timespec, other: *const timespec) bool { - return this.sec == other.sec and this.nsec == other.nsec; - } - - // TODO: this is wrong! - pub fn duration(this: *const timespec, other: *const timespec) timespec { - // Mimick C wrapping behavior. - var sec_diff = this.sec -% other.sec; - var nsec_diff = this.nsec -% other.nsec; - - if (nsec_diff < 0) { - sec_diff -%= 1; - nsec_diff +%= std.time.ns_per_s; - } - - return timespec{ - .sec = sec_diff, - .nsec = nsec_diff, - }; - } - - pub fn order(a: *const timespec, b: *const timespec) std.math.Order { - const sec_order = std.math.order(a.sec, b.sec); - if (sec_order != .eq) return sec_order; - return std.math.order(a.nsec, b.nsec); - } - - /// Returns the nanoseconds of this timer. Note that maxInt(u64) ns is - /// 584 years so if we get any overflows we just use maxInt(u64). If - /// any software is running in 584 years waiting on this timer... - /// shame on me I guess... but I'll be dead. - pub fn ns(this: *const timespec) u64 { - if (this.sec <= 0) { - return @max(this.nsec, 0); - } - - assert(this.sec >= 0); - assert(this.nsec >= 0); - const s_ns = std.math.mul( - u64, - @as(u64, @intCast(@max(this.sec, 0))), - std.time.ns_per_s, - ) catch return std.math.maxInt(u64); - - return std.math.add(u64, s_ns, @as(u64, @intCast(@max(this.nsec, 0)))) catch - return std.math.maxInt(i64); - } - - pub fn nsSigned(this: *const timespec) i64 { - const ns_per_sec = this.sec *% std.time.ns_per_s; - const ns_from_nsec = @divFloor(this.nsec, 1_000_000); - return ns_per_sec +% ns_from_nsec; - } - - pub fn ms(this: *const timespec) i64 { - const ms_from_sec = this.sec *% 1000; - const ms_from_nsec = @divFloor(this.nsec, 1_000_000); - return ms_from_sec +% ms_from_nsec; - } - - pub fn msUnsigned(this: *const timespec) u64 { - return this.ns() / std.time.ns_per_ms; - } - - pub fn greater(a: *const timespec, b: *const timespec) bool { - return a.order(b) == .gt; - } - - pub fn now(comptime mock_mode: MockMode) timespec { - return getRoughTickCount(mock_mode); - } - - pub fn sinceNow(start: *const timespec, comptime mock_mode: MockMode) u64 { - return now(mock_mode).duration(start).ns(); - } - - pub fn addMs(this: *const timespec, interval: i64) timespec { - const sec_inc = @divTrunc(interval, std.time.ms_per_s); - const nsec_inc = @rem(interval, std.time.ms_per_s) * std.time.ns_per_ms; - - var new_timespec = this.*; - - new_timespec.sec +%= sec_inc; - new_timespec.nsec +%= nsec_inc; - - if (new_timespec.nsec >= std.time.ns_per_s) { - new_timespec.sec +%= 1; - new_timespec.nsec -%= std.time.ns_per_s; - } - - return new_timespec; - } - pub fn addMsFloat(this: *const timespec, interval_ms: f64) timespec { - const ns_per_ms_f = @as(f64, @floatFromInt(std.time.ns_per_ms)); // 1_000_000 - - // Start from the current time - var new_timespec = this.*; - - // Split into whole ms and sub-ms remainder (matches sinon/fake-timers logic) - // Use modulo to extract fractional milliseconds as nanoseconds - const ms_whole_f = @floor(interval_ms); - const ms_inc: i64 = std.math.lossyCast(i64, ms_whole_f); - - // nanoRemainder: floor((msFloat * 1e6) % 1e6) - const ns_total_f = interval_ms * ns_per_ms_f; - const ns_remainder_f = @mod(ns_total_f, ns_per_ms_f); - const nsec_inc: i64 = @intFromFloat(@floor(ns_remainder_f)); - - // Convert milliseconds to seconds - const sec_inc = @divTrunc(ms_inc, std.time.ms_per_s); - const ms_remainder = @mod(ms_inc, std.time.ms_per_s); - - new_timespec.sec +%= sec_inc; - new_timespec.nsec +%= ms_remainder * std.time.ns_per_ms + nsec_inc; - - // Normalize nsec into [0, ns_per_s) - if (new_timespec.nsec >= std.time.ns_per_s) { - new_timespec.sec +%= 1; - new_timespec.nsec -%= std.time.ns_per_s; - } else if (new_timespec.nsec < 0) { - new_timespec.sec -%= 1; - new_timespec.nsec +%= std.time.ns_per_s; - } - - return new_timespec; - } - - pub fn msFromNow(comptime mock_mode: MockMode, interval: i64) timespec { - return now(mock_mode).addMs(interval); - } - - pub fn min(a: timespec, b: timespec) timespec { - return if (a.order(&b) == .lt) a else b; - } - pub fn max(a: timespec, b: timespec) timespec { - return if (a.order(&b) == .gt) a else b; - } - pub fn orderIgnoreEpoch(a: timespec, b: timespec) std.math.Order { - if (a.eql(&b)) return .eq; - if (a.eql(&.epoch)) return .gt; - if (b.eql(&.epoch)) return .lt; - return a.order(&b); - } - pub fn minIgnoreEpoch(a: timespec, b: timespec) timespec { - return if (a.orderIgnoreEpoch(b) == .lt) a else b; - } -}; - -pub const UUID = @import("./jsc/uuid.zig"); - -/// An abstract number of element in a sequence. The sequence has a first element. -/// This type should be used instead of integer because 2 contradicting traditions can -/// call a first element '0' or '1' which makes integer type ambiguous. -pub fn OrdinalT(comptime Int: type) type { - return enum(Int) { - invalid = switch (@typeInfo(Int).int.signedness) { - .unsigned => std.math.maxInt(Int), - .signed => -1, - }, - start = 0, - _, - - pub inline fn fromZeroBased(int: Int) @This() { - assert(int >= 0); - assert(int != std.math.maxInt(Int)); - return @enumFromInt(int); - } - - pub inline fn fromOneBased(int: Int) @This() { - assert(int > 0); - return @enumFromInt(int - 1); - } - - pub inline fn zeroBased(ord: @This()) Int { - return @intFromEnum(ord); - } - - pub inline fn oneBased(ord: @This()) Int { - return @intFromEnum(ord) + 1; - } - - /// Add two ordinal numbers together. Both are converted to zero-based before addition. - pub inline fn add(ord: @This(), b: @This()) @This() { - return fromZeroBased(ord.zeroBased() + b.zeroBased()); - } - - /// Add a scalar value to an ordinal number - pub inline fn addScalar(ord: @This(), inc: Int) @This() { - return fromZeroBased(ord.zeroBased() + inc); - } - - pub inline fn isValid(ord: @This()) bool { - return ord.zeroBased() >= 0; - } - }; -} - -/// ABI-equivalent of WTF::OrdinalNumber -pub const Ordinal = OrdinalT(c_int); - -pub fn memmove(output: []u8, input: []const u8) void { - if (output.len == 0) { - return; - } - - if (comptime Environment.allow_assert) { - assert(output.len >= input.len); - } - - if (Environment.isNative and !@inComptime()) { - _ = c.memmove(output.ptr, input.ptr, input.len); - } else { - for (input, output) |input_byte, *out| { - out.* = input_byte; - } - } -} - -pub const hmac = @import("./sha_hmac/hmac.zig"); -pub const libdeflate = @import("./libdeflate_sys/libdeflate.zig"); - -pub const bake = @import("./runtime/bake/bake.zig"); - -/// like std.enums.tagName, except it doesn't lose the sentinel value. -pub fn tagName(comptime Enum: type, value: Enum) ?[:0]const u8 { - return inline for (@typeInfo(Enum).@"enum".fields) |f| { - if (@intFromEnum(value) == f.value) break f.name; - } else null; -} - -pub fn getTotalMemorySize() usize { - return cpp.Bun__ramSize(); -} - -pub const bytecode_extension = ".jsc"; - -/// An typed index into an array or other structure. -/// maxInt is reserved for an empty state. -/// -/// const Thing = struct {}; -/// const Index = bun.GenericIndex(u32, Thing) -/// -/// The second argument prevents Zig from memoizing the -/// call, which would otherwise make all indexes -/// equal to each other. -pub fn GenericIndex(backing_int: type, uid: anytype) type { - const null_value = std.math.maxInt(backing_int); - return enum(backing_int) { - _, - const Index = @This(); - comptime { - _ = uid; - } - - /// Prefer this over @enumFromInt to assert the int is in range - pub inline fn init(int: backing_int) Index { - bun.assert(int != null_value); // would be confused for null - return @enumFromInt(int); - } - - /// Prefer this over @intFromEnum because of type confusion with `.Optional` - pub inline fn get(i: @This()) backing_int { - bun.assert(@intFromEnum(i) != null_value); // memory corruption - return @intFromEnum(i); - } - - pub inline fn toOptional(oi: @This()) Optional { - return @enumFromInt(oi.get()); - } - - pub fn sortFnAsc(_: void, a: @This(), b: @This()) bool { - return a.get() < b.get(); - } - - pub fn sortFnDesc(_: void, a: @This(), b: @This()) bool { - return a.get() < b.get(); - } - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - return writer.print("{d}", .{@intFromEnum(this)}); - } - - pub const Optional = enum(backing_int) { - none = std.math.maxInt(backing_int), - _, - - /// Signatures: - /// - `init(maybe: ?Index) Optional` - /// - `init(maybe: ?backing_int) Optional` - pub inline fn init(maybe: anytype) Optional { - comptime var t = @typeInfo(@TypeOf(maybe)); - if (t == .optional) t = @typeInfo(t.optional.child); - if (t == .int or t == .comptime_int) - return if (@as(?backing_int, maybe)) |i| Index.init(i).toOptional() else .none; - return if (@as(?Index, maybe)) |i| i.toOptional() else .none; - } - - pub inline fn unwrap(oi: Optional) ?Index { - return if (oi == .none) null else @enumFromInt(@intFromEnum(oi)); - } - - pub inline fn unwrapGet(oi: Optional) ?backing_int { - return if (oi == .none) null else @intFromEnum(oi); - } - }; - }; -} - -comptime { - // Must be nominal - assert(GenericIndex(u32, opaque {}) != GenericIndex(u32, opaque {})); -} - -pub fn splitAtMut(comptime T: type, slice: []T, mid: usize) struct { []T, []T } { - bun.assert(mid <= slice.len); - - return .{ slice[0..mid], slice[mid..] }; -} - -/// Reverse of the slice index operator. -/// Given `&slice[index] == item`, returns the `index` needed. -/// The item must be in the slice. -pub fn indexOfPointerInSlice(comptime T: type, slice: []const T, item: *const T) usize { - bun.assert(isSliceInBufferT(T, item[0..1], slice)); - const offset = @intFromPtr(item) - @intFromPtr(slice.ptr); - const index = @divExact(offset, @sizeOf(T)); - return index; -} - -pub fn getThreadCount() u16 { - const max_threads = 1024; - const min_threads = 2; - const ThreadCount = struct { - pub var cached_thread_count: u16 = 0; - var cached_thread_count_once = std.once(getThreadCountOnce); - fn getThreadCountFromUser() ?u16 { - inline for (.{ "UV_THREADPOOL_SIZE", "GOMAXPROCS" }) |envname| { - if (getenvZ(envname)) |env| { - if (std.fmt.parseInt(u16, env, 10) catch null) |parsed| { - if (parsed >= min_threads) { - if (bun.logger.Log.default_log_level.atLeast(.debug)) { - Output.note("Using {d} threads from {s}={d}", .{ parsed, envname, parsed }); - Output.flush(); - } - return @min(parsed, max_threads); - } - } - } - } - - return null; - } - fn getThreadCountOnce() void { - cached_thread_count = @min(max_threads, @max(min_threads, getThreadCountFromUser() orelse jsc.wtf.numberOfProcessorCores())); - } - }; - ThreadCount.cached_thread_count_once.call(); - return ThreadCount.cached_thread_count; -} - -/// Copied from zig std. Modified to accept arguments. -pub fn once(comptime f: anytype) Once(f) { - return Once(f){}; -} - -/// Copied from zig std. Modified to accept arguments. -/// -/// An object that executes the function `f` just once. -/// It is undefined behavior if `f` re-enters the same Once instance. -pub fn Once(comptime f: anytype) type { - return struct { - const Return = @typeInfo(@TypeOf(f)).@"fn".return_type.?; - - done: bool = false, - payload: Return = undefined, - mutex: bun.Mutex = .{}, - - /// Call the function `f`. - /// If `call` is invoked multiple times `f` will be executed only the - /// first time. - /// The invocations are thread-safe. - pub fn call(self: *@This(), args: std.meta.ArgsTuple(@TypeOf(f))) Return { - if (@atomicLoad(bool, &self.done, .acquire)) - return self.payload; - - return self.callSlow(args); - } - - fn callSlow(self: *@This(), args: std.meta.ArgsTuple(@TypeOf(f))) Return { - @branchHint(.cold); - - self.mutex.lock(); - defer self.mutex.unlock(); - - // The first thread to acquire the mutex gets to run the initializer - if (!self.done) { - self.payload = @call(.auto, f, args); - @atomicStore(bool, &self.done, true, .release); - } - - return self.payload; - } - }; -} - -/// `val` must be a pointer to an optional type (e.g. `*?T`) -/// -/// This function takes the value out of the optional, replacing it with null, and returns the value. -pub inline fn take(val: anytype) ?@typeInfo(@typeInfo(@TypeOf(val)).pointer.child).optional.child { - if (val.*) |v| { - val.* = null; - return v; - } - return null; -} - -/// `val` must be a pointer to an optional type (e.g. `*?T`) -/// -/// This function deinitializes the value and sets the optional to null. -pub inline fn clear(val: anytype, allocator: std.mem.Allocator) void { - if (val.*) |*v| { - if (@hasDecl(@TypeOf(v.*), "deinit")) { - v.deinit(allocator); - } - val.* = null; - } -} - -pub inline fn move(val: anytype) switch (@typeInfo(@TypeOf(val))) { - .pointer => |p| p.child, - else => @compileError("unexpected move type"), -} { - const tmp = val.*; - @constCast(val).* = undefined; - return tmp; -} - -pub inline fn wrappingNegation(val: anytype) @TypeOf(val) { - return 0 -% val; -} - -fn assertNoPointers(T: type) void { - switch (@typeInfo(T)) { - .pointer => @compileError("no pointers!"), - inline .@"struct", .@"union" => |s| for (s.fields) |field| { - assertNoPointers(field.type); - }, - .array => |a| assertNoPointers(a.child), - else => {}, - } -} - -pub inline fn writeAnyToHasher(hasher: anytype, thing: anytype) void { - comptime assertNoPointers(@TypeOf(thing)); // catch silly mistakes - hasher.update(std.mem.asBytes(&thing)); -} - -pub const perf = @import("./perf/perf.zig"); -pub inline fn isComptimeKnown(x: anytype) bool { - return comptime @typeInfo(@TypeOf(.{x})).@"struct".fields[0].is_comptime; -} - -pub inline fn itemOrNull(comptime T: type, slice: []const T, index: usize) ?T { - return if (index < slice.len) slice[index] else null; -} - -pub const Maybe = jsc.Node.Maybe; - -/// To handle stack overflows: -/// 1. StackCheck.init() -/// 2. .isSafeToRecurse() -pub const StackCheck = struct { - cached_stack_end: usize = 0, - - pub fn configureThread() void { - cpp.Bun__StackCheck__initialize(); - } - - fn getStackEnd() usize { - return @intFromPtr(cpp.Bun__StackCheck__getMaxStack()); - } - - pub fn init() StackCheck { - return StackCheck{ .cached_stack_end = getStackEnd() }; - } - - pub fn update(this: *StackCheck) void { - this.cached_stack_end = getStackEnd(); - } - - /// Is there at least 128 KB of stack space available? - pub fn isSafeToRecurse(this: StackCheck) bool { - const stack_ptr: usize = @frameAddress(); - const remaining_stack = stack_ptr -| this.cached_stack_end; - return remaining_stack > 1024 * if (Environment.isWindows) 256 else 128; - } -}; - -// Workaround for lack of branch hints. -pub noinline fn throwStackOverflow() StackOverflow!void { - @branchHint(.cold); - return error.StackOverflow; -} -pub const StackOverflow = error{StackOverflow}; - -pub const S3 = @import("./runtime/webcore/s3/client.zig"); - -/// Memory is typically not decommitted immediately when freed. -/// Sensitive information that's kept in memory can be read in various ways until the OS -/// decommits it or the memory allocator reuses it for a new allocation. -/// So if we're about to free something sensitive, we should zero it out first. -pub fn freeSensitive(allocator: std.mem.Allocator, slice: anytype) void { - std.crypto.secureZero(std.meta.Child(@TypeOf(slice)), @constCast(slice)); - allocator.free(slice); -} - -pub const macho = @import("./exe_format/macho.zig"); -pub const pe = @import("./exe_format/pe.zig"); -pub const elf = @import("./exe_format/elf.zig"); -pub const valkey = @import("./runtime/valkey_jsc/index.zig"); -pub const highway = @import("./highway/highway.zig"); - -pub const mach_port = if (Environment.isMac) std.c.mach_port_t else u32; - -/// Automatically generated C++ bindings for functions marked with `[[ZIG_EXPORT(...)]]` -pub const cpp = @import("cpp"); - -pub const asan = @import("./safety/asan.zig"); - -pub fn contains(item: anytype, list: *const std.ArrayListUnmanaged(@TypeOf(item))) bool { - const T = @TypeOf(item); - return switch (T) { - u8 => strings.containsChar(list.items, item), - else => std.mem.indexOfScalar(T, list.items, item) != null, - }; -} - -pub const safety = @import("./safety/safety.zig"); -pub const deprecated = @import("./bun_core/deprecated.zig"); - -// Export function to check if --use-system-ca flag is set -pub fn getUseSystemCA(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) error{ JSError, OutOfMemory }!jsc.JSValue { - _ = globalObject; - _ = callFrame; - const Arguments = @import("./runtime/cli/Arguments.zig"); - return jsc.JSValue.jsBoolean(Arguments.Bun__Node__UseSystemCA); -} - -// Claude thinks its bun.JSC when we renamed it to bun.jsc months ago. -pub const JSC = @compileError("Deprecated: Use @import(\"bun\").jsc instead"); - -pub const ConfigVersion = @import("./install/ConfigVersion.zig").ConfigVersion; - -const CopyFile = @import("./sys/copy_file.zig"); -const builtin = @import("builtin"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/bun_alloc/BufferFallbackAllocator.zig b/src/bun_alloc/BufferFallbackAllocator.zig deleted file mode 100644 index 88848425d218..000000000000 --- a/src/bun_alloc/BufferFallbackAllocator.zig +++ /dev/null @@ -1,85 +0,0 @@ -/// An allocator that attempts to allocate from a provided buffer first, -/// falling back to another allocator when the buffer is exhausted. -/// Unlike `std.heap.StackFallbackAllocator`, this does not own the buffer. -const BufferFallbackAllocator = @This(); - -#fallback_allocator: Allocator, -#fixed_buffer_allocator: FixedBufferAllocator, - -pub fn init(buffer: []u8, fallback_allocator: Allocator) BufferFallbackAllocator { - return .{ - .#fallback_allocator = fallback_allocator, - .#fixed_buffer_allocator = FixedBufferAllocator.init(buffer), - }; -} - -pub fn allocator(self: *BufferFallbackAllocator) Allocator { - return .{ - .ptr = self, - .vtable = &.{ - .alloc = alloc, - .resize = resize, - .remap = remap, - .free = free, - }, - }; -} - -fn alloc(ctx: *anyopaque, len: usize, alignment: std.mem.Alignment, ra: usize) ?[*]u8 { - const self: *BufferFallbackAllocator = @ptrCast(@alignCast(ctx)); - return FixedBufferAllocator.alloc( - &self.#fixed_buffer_allocator, - len, - alignment, - ra, - ) orelse self.#fallback_allocator.rawAlloc(len, alignment, ra); -} - -fn resize(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, new_len: usize, ra: usize) bool { - const self: *BufferFallbackAllocator = @ptrCast(@alignCast(ctx)); - if (self.#fixed_buffer_allocator.ownsPtr(buf.ptr)) { - return FixedBufferAllocator.resize( - &self.#fixed_buffer_allocator, - buf, - alignment, - new_len, - ra, - ); - } - return self.#fallback_allocator.rawResize(buf, alignment, new_len, ra); -} - -fn remap(ctx: *anyopaque, memory: []u8, alignment: std.mem.Alignment, new_len: usize, ra: usize) ?[*]u8 { - const self: *BufferFallbackAllocator = @ptrCast(@alignCast(ctx)); - if (self.#fixed_buffer_allocator.ownsPtr(memory.ptr)) { - return FixedBufferAllocator.remap( - &self.#fixed_buffer_allocator, - memory, - alignment, - new_len, - ra, - ); - } - return self.#fallback_allocator.rawRemap(memory, alignment, new_len, ra); -} - -fn free(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, ra: usize) void { - const self: *BufferFallbackAllocator = @ptrCast(@alignCast(ctx)); - if (self.#fixed_buffer_allocator.ownsPtr(buf.ptr)) { - return FixedBufferAllocator.free( - &self.#fixed_buffer_allocator, - buf, - alignment, - ra, - ); - } - return self.#fallback_allocator.rawFree(buf, alignment, ra); -} - -pub fn reset(self: *BufferFallbackAllocator) void { - self.#fixed_buffer_allocator.reset(); -} - -const std = @import("std"); -const Allocator = std.mem.Allocator; -const FixedBufferAllocator = std.heap.FixedBufferAllocator; diff --git a/src/bun_alloc/LinuxMemFdAllocator.zig b/src/bun_alloc/LinuxMemFdAllocator.zig deleted file mode 100644 index 3ee38b31533c..000000000000 --- a/src/bun_alloc/LinuxMemFdAllocator.zig +++ /dev/null @@ -1,195 +0,0 @@ -//! When cloning large amounts of data potentially multiple times, we can -//! leverage copy-on-write memory to avoid actually copying the data. To do that -//! on Linux, we need to use a memfd, which is a Linux-specific feature. -//! -//! The steps are roughly: -//! -//! 1. Create a memfd -//! 2. Write the data to the memfd -//! 3. Map the memfd into memory -//! -//! Then, to clone the data later, we can just call `mmap` again. -//! -//! The big catch is that mmap(), memfd_create(), write() all have overhead. And -//! often we will re-use virtual memory within the process. This does not reuse -//! the virtual memory. So we should only really use this for large blobs of -//! data that we expect to be cloned multiple times. Such as Blob in FormData. - -const Self = @This(); - -const RefCount = bun.ptr.ThreadSafeRefCount(@This(), "ref_count", deinit, .{}); - -pub const new = bun.TrivialNew(@This()); -pub const ref = RefCount.ref; -pub const deref = RefCount.deref; - -ref_count: RefCount, -fd: bun.FD = .invalid, -size: usize = 0, - -var memfd_counter = std.atomic.Value(usize).init(0); - -fn deinit(self: *Self) void { - self.fd.close(); - bun.destroy(self); -} - -pub fn allocator(self: *Self) std.mem.Allocator { - return .{ - .ptr = self, - .vtable = AllocatorInterface.VTable, - }; -} - -pub fn from(allocator_: std.mem.Allocator) ?*Self { - if (allocator_.vtable == AllocatorInterface.VTable) { - return @ptrCast(@alignCast(allocator_.ptr)); - } - - return null; -} - -const AllocatorInterface = struct { - fn alloc(_: *anyopaque, _: usize, _: std.mem.Alignment, _: usize) ?[*]u8 { - // it should perform no allocations or resizes - return null; - } - - fn free( - ptr: *anyopaque, - buf: []u8, - _: std.mem.Alignment, - _: usize, - ) void { - var self: *Self = @ptrCast(@alignCast(ptr)); - defer self.deref(); - bun.sys.munmap(@ptrCast(@alignCast(buf))).unwrap() catch |err| { - bun.Output.debugWarn("Failed to munmap memfd: {}", .{err}); - }; - } - - pub const VTable = &std.mem.Allocator.VTable{ - .alloc = &AllocatorInterface.alloc, - .resize = &std.mem.Allocator.noResize, - .remap = &std.mem.Allocator.noRemap, - .free = &free, - }; -}; - -pub fn alloc(self: *Self, len: usize, offset: usize, flags: std.posix.MAP) bun.sys.Maybe(bun.webcore.Blob.Store.Bytes) { - var size = len; - - // size rounded up to nearest page - size = std.mem.alignForward(usize, size, std.heap.pageSize()); - - var flags_mut = flags; - flags_mut.TYPE = .SHARED; - - switch (bun.sys.mmap( - null, - @min(size, self.size), - std.posix.PROT.READ | std.posix.PROT.WRITE, - flags_mut, - self.fd, - offset, - )) { - .result => |slice| { - return .{ - .result = bun.webcore.Blob.Store.Bytes{ - .cap = @truncate(slice.len), - .ptr = slice.ptr, - .len = @truncate(len), - .allocator = self.allocator(), - }, - }; - }, - .err => |errno| { - return .{ .err = errno }; - }, - } -} - -pub fn shouldUse(bytes: []const u8) bool { - if (comptime !bun.Environment.isLinux) { - return false; - } - - if (!bun.sys.canUseMemfd()) return false; - - if (bun.jsc.VirtualMachine.is_smol_mode) { - return bytes.len >= 1024 * 1024 * 1; - } - - // This is a net 2x - 4x slowdown to new Blob([huge]) - // so we must be careful - return bytes.len >= 1024 * 1024 * 8; -} - -pub fn create(bytes: []const u8) bun.sys.Maybe(bun.webcore.Blob.Store.Bytes) { - if (comptime !bun.Environment.isLinux) { - unreachable; - } - - var label_buf: [128]u8 = undefined; - const label = std.fmt.bufPrintZ(&label_buf, "memfd-num-{d}", .{memfd_counter.fetchAdd(1, .monotonic)}) catch ""; - - // Using huge pages was slower. - const fd = switch (bun.sys.memfd_create(label, .non_executable)) { - .err => |err| return .{ .err = bun.sys.Error.fromCode(err.getErrno(), .open) }, - .result => |fd| fd, - }; - - if (bytes.len > 0) - // Hint at the size of the file - _ = bun.sys.ftruncate(fd, @intCast(bytes.len)); - - // Dump all the bytes in there - var written: isize = 0; - - var remain = bytes; - while (remain.len > 0) { - switch (bun.sys.pwrite(fd, remain, written)) { - .err => |err| { - if (err.getErrno() == .AGAIN) { - continue; - } - - bun.Output.debugWarn("Failed to write to memfd: {f}", .{err}); - fd.close(); - return .{ .err = err }; - }, - .result => |result| { - if (result == 0) { - bun.Output.debugWarn("Failed to write to memfd: EOF", .{}); - fd.close(); - return .{ .err = bun.sys.Error.fromCode(.NOMEM, .write) }; - } - written += @intCast(result); - remain = remain[result..]; - }, - } - } - - var linux_memfd_allocator = Self.new(.{ - .fd = fd, - .ref_count = .init(), - .size = bytes.len, - }); - - switch (linux_memfd_allocator.alloc(bytes.len, 0, .{ .TYPE = .SHARED })) { - .result => |res| { - return .{ .result = res }; - }, - .err => |err| { - linux_memfd_allocator.deref(); - return .{ .err = err }; - }, - } -} - -pub fn isInstance(allocator_: std.mem.Allocator) bool { - return allocator_.vtable == AllocatorInterface.VTable; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bun_alloc/MaxHeapAllocator.zig b/src/bun_alloc/MaxHeapAllocator.zig deleted file mode 100644 index 1b7907b203d2..000000000000 --- a/src/bun_alloc/MaxHeapAllocator.zig +++ /dev/null @@ -1,58 +0,0 @@ -//! Single allocation only. - -const Self = @This(); - -array_list: std.array_list.AlignedManaged(u8, .of(std.c.max_align_t)), - -fn alloc(ptr: *anyopaque, len: usize, alignment: std.mem.Alignment, _: usize) ?[*]u8 { - bun.assert(alignment.toByteUnits() <= @alignOf(std.c.max_align_t)); - var self = bun.cast(*Self, ptr); - self.array_list.items.len = 0; - self.array_list.ensureTotalCapacity(len) catch return null; - self.array_list.items.len = len; - return self.array_list.items.ptr; -} - -fn resize(_: *anyopaque, buf: []u8, _: std.mem.Alignment, new_len: usize, _: usize) bool { - _ = new_len; - _ = buf; - @panic("not implemented"); -} - -fn free( - _: *anyopaque, - _: []u8, - _: std.mem.Alignment, - _: usize, -) void {} - -pub fn reset(self: *Self) void { - self.array_list.items.len = 0; -} - -pub fn deinit(self: *Self) void { - self.array_list.deinit(); -} - -const vtable = std.mem.Allocator.VTable{ - .alloc = &alloc, - .free = &free, - .resize = &resize, - .remap = &std.mem.Allocator.noRemap, -}; - -pub fn init(self: *Self, allocator: std.mem.Allocator) std.mem.Allocator { - self.array_list = .init(allocator); - - return std.mem.Allocator{ - .ptr = self, - .vtable = &vtable, - }; -} - -pub fn isInstance(allocator: std.mem.Allocator) bool { - return allocator.vtable == &vtable; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bun_alloc/MimallocArena.zig b/src/bun_alloc/MimallocArena.zig deleted file mode 100644 index e17d4dc39cfb..000000000000 --- a/src/bun_alloc/MimallocArena.zig +++ /dev/null @@ -1,291 +0,0 @@ -//! This type is a `GenericAllocator`; see `src/allocators.zig`. - -const Self = @This(); - -#heap: if (safety_checks) Owned(*DebugHeap) else *mimalloc.Heap, - -/// Uses the default thread-local heap. This type is zero-sized. -/// -/// This type is a `GenericAllocator`; see `src/allocators.zig`. -pub const Default = struct { - pub fn allocator(_: Default) std.mem.Allocator { - return .{ .ptr = undefined, .vtable = &global_mimalloc_vtable }; - } -}; - -/// Borrowed version of `MimallocArena`, returned by `MimallocArena.borrow`. -/// Using this type makes it clear who actually owns the `MimallocArena`, and prevents -/// `deinit` from being called twice. -/// -/// This type is a `GenericAllocator`; see `src/allocators.zig`. -pub const Borrowed = struct { - #heap: BorrowedHeap, - - pub fn allocator(self: Borrowed) std.mem.Allocator { - return .{ .ptr = self.#heap, .vtable = &heap_allocator_vtable }; - } - - /// Prefer `Default.allocator()` / `getThreadLocalDefault()` for a thread-safe - /// global allocator. This returns the process-wide main heap so that - /// `gc()` / `ownsPtr()` on the result remain meaningful. - pub fn getDefault() Borrowed { - const heap = mimalloc.mi_heap_main(); - if (comptime !safety_checks) return .{ .#heap = heap }; - const S = struct { - threadlocal var dbg: ?DebugHeap = null; - }; - if (S.dbg == null) S.dbg = .{ .inner = heap, .thread_lock = .initLocked() }; - return .{ .#heap = &S.dbg.? }; - } - - pub fn gc(self: Borrowed) void { - mimalloc.mi_heap_collect(self.getMimallocHeap(), false); - } - - pub fn helpCatchMemoryIssues(self: Borrowed) void { - if (comptime bun.FeatureFlags.help_catch_memory_issues) { - self.gc(); - bun.mimalloc.mi_collect(false); - } - } - - pub fn ownsPtr(self: Borrowed, ptr: *const anyopaque) bool { - return mimalloc.mi_heap_contains(self.getMimallocHeap(), ptr); - } - - fn fromOpaque(ptr: *anyopaque) Borrowed { - return .{ .#heap = @ptrCast(@alignCast(ptr)) }; - } - - fn getMimallocHeap(self: Borrowed) *mimalloc.Heap { - return if (comptime safety_checks) self.#heap.inner else self.#heap; - } - - fn assertThreadLock(self: Borrowed) void { - if (comptime safety_checks) self.#heap.thread_lock.assertLocked(); - } - - fn alignedAlloc(self: Borrowed, len: usize, alignment: Alignment) ?[*]u8 { - log("Malloc: {d}\n", .{len}); - - const heap = self.getMimallocHeap(); - const ptr: ?*anyopaque = if (mimalloc.mustUseAlignedAlloc(alignment)) - mimalloc.mi_heap_malloc_aligned(heap, len, alignment.toByteUnits()) - else - mimalloc.mi_heap_malloc(heap, len); - - if (comptime bun.Environment.isDebug) { - const usable = mimalloc.mi_malloc_usable_size(ptr); - if (usable < len) { - std.debug.panic("mimalloc: allocated size is too small: {d} < {d}", .{ usable, len }); - } - } - - return if (ptr) |p| - @as([*]u8, @ptrCast(p)) - else - null; - } - - pub fn downcast(std_alloc: std.mem.Allocator) Borrowed { - bun.assertf( - std_alloc.vtable == &heap_allocator_vtable, - "not an owned MimallocArena heap (vtable is {*})", - .{std_alloc.vtable}, - ); - return .fromOpaque(std_alloc.ptr); - } -}; - -const BorrowedHeap = if (safety_checks) *DebugHeap else *mimalloc.Heap; - -const DebugHeap = struct { - inner: *mimalloc.Heap, - thread_lock: bun.safety.ThreadLock, - - pub const deinit = void; -}; - -const log = bun.Output.scoped(.mimalloc, .hidden); - -pub fn allocator(self: Self) std.mem.Allocator { - return self.borrow().allocator(); -} - -pub fn borrow(self: Self) Borrowed { - return .{ .#heap = if (comptime safety_checks) self.#heap.get() else self.#heap }; -} - -/// In v3, `mi_malloc`/`mi_free` are already thread-local-fast — there is no -/// per-thread default heap to cache. Route through the global vtable. -pub fn getThreadLocalDefault() std.mem.Allocator { - if (bun.Environment.enable_asan) return bun.default_allocator; - return .{ .ptr = undefined, .vtable = &global_mimalloc_vtable }; -} - -pub fn backingAllocator(_: Self) std.mem.Allocator { - return getThreadLocalDefault(); -} - -pub fn dumpThreadStats(_: Self) void { - const dump_fn = struct { - pub fn dump(textZ: [*:0]const u8, _: ?*anyopaque) callconv(.c) void { - const text = bun.span(textZ); - bun.Output.errorWriter().writeAll(text) catch {}; - } - }.dump; - mimalloc.mi_thread_stats_print_out(dump_fn, null); - bun.Output.flush(); -} - -pub fn dumpStats(_: Self) void { - const dump_fn = struct { - pub fn dump(textZ: [*:0]const u8, _: ?*anyopaque) callconv(.c) void { - const text = bun.span(textZ); - bun.Output.errorWriter().writeAll(text) catch {}; - } - }.dump; - mimalloc.mi_stats_print_out(dump_fn, null); - bun.Output.flush(); -} - -pub fn deinit(self: *Self) void { - const mimalloc_heap = self.borrow().getMimallocHeap(); - if (comptime safety_checks) { - self.#heap.deinit(); - } - mimalloc.mi_heap_destroy(mimalloc_heap); - self.* = undefined; -} - -pub fn init() Self { - const mimalloc_heap = mimalloc.mi_heap_new() orelse bun.outOfMemory(); - if (comptime !safety_checks) return .{ .#heap = mimalloc_heap }; - const heap: Owned(*DebugHeap) = .new(.{ - .inner = mimalloc_heap, - .thread_lock = .initLocked(), - }); - return .{ .#heap = heap }; -} - -pub fn gc(self: Self) void { - self.borrow().gc(); -} - -pub fn helpCatchMemoryIssues(self: Self) void { - self.borrow().helpCatchMemoryIssues(); -} - -pub fn ownsPtr(self: Self, ptr: *const anyopaque) bool { - return self.borrow().ownsPtr(ptr); -} - -fn alignedAllocSize(ptr: [*]u8) usize { - return mimalloc.mi_malloc_usable_size(ptr); -} - -fn vtable_alloc(ptr: *anyopaque, len: usize, alignment: Alignment, _: usize) ?[*]u8 { - const self: Borrowed = .fromOpaque(ptr); - self.assertThreadLock(); - return self.alignedAlloc(len, alignment); -} - -fn vtable_resize(ptr: *anyopaque, buf: []u8, _: Alignment, new_len: usize, _: usize) bool { - const self: Borrowed = .fromOpaque(ptr); - self.assertThreadLock(); - return mimalloc.mi_expand(buf.ptr, new_len) != null; -} - -fn vtable_free( - _: *anyopaque, - buf: []u8, - alignment: Alignment, - _: usize, -) void { - // mi_free_size internally just asserts the size - // so it's faster if we don't pass that value through - // but its good to have that assertion - if (comptime bun.Environment.isDebug) { - assert(mimalloc.mi_is_in_heap_region(buf.ptr)); - if (mimalloc.mustUseAlignedAlloc(alignment)) - mimalloc.mi_free_size_aligned(buf.ptr, buf.len, alignment.toByteUnits()) - else - mimalloc.mi_free_size(buf.ptr, buf.len); - } else { - mimalloc.mi_free(buf.ptr); - } -} - -/// Attempt to expand or shrink memory, allowing relocation. -/// -/// `memory.len` must equal the length requested from the most recent -/// successful call to `alloc`, `resize`, or `remap`. `alignment` must -/// equal the same value that was passed as the `alignment` parameter to -/// the original `alloc` call. -/// -/// A non-`null` return value indicates the resize was successful. The -/// allocation may have same address, or may have been relocated. In either -/// case, the allocation now has size of `new_len`. A `null` return value -/// indicates that the resize would be equivalent to allocating new memory, -/// copying the bytes from the old memory, and then freeing the old memory. -/// In such case, it is more efficient for the caller to perform the copy. -/// -/// `new_len` must be greater than zero. -/// -/// `ret_addr` is optionally provided as the first return address of the -/// allocation call stack. If the value is `0` it means no return address -/// has been provided. -fn vtable_remap(ptr: *anyopaque, buf: []u8, alignment: Alignment, new_len: usize, _: usize) ?[*]u8 { - const self: Borrowed = .fromOpaque(ptr); - self.assertThreadLock(); - const heap = self.getMimallocHeap(); - const aligned_size = alignment.toByteUnits(); - const value = mimalloc.mi_heap_realloc_aligned(heap, buf.ptr, new_len, aligned_size); - return @ptrCast(value); -} - -fn global_vtable_alloc(_: *anyopaque, len: usize, alignment: Alignment, _: usize) ?[*]u8 { - log("Malloc: {d}\n", .{len}); - const ptr: ?*anyopaque = if (mimalloc.mustUseAlignedAlloc(alignment)) - mimalloc.mi_malloc_aligned(len, alignment.toByteUnits()) - else - mimalloc.mi_malloc(len); - return if (ptr) |p| @ptrCast(p) else null; -} - -fn global_vtable_resize(_: *anyopaque, buf: []u8, _: Alignment, new_len: usize, _: usize) bool { - return mimalloc.mi_expand(buf.ptr, new_len) != null; -} - -fn global_vtable_remap(_: *anyopaque, buf: []u8, alignment: Alignment, new_len: usize, _: usize) ?[*]u8 { - return @ptrCast(mimalloc.mi_realloc_aligned(buf.ptr, new_len, alignment.toByteUnits())); -} - -pub fn isInstance(alloc: std.mem.Allocator) bool { - return alloc.vtable == &heap_allocator_vtable or alloc.vtable == &global_mimalloc_vtable; -} - -/// VTable for owned heaps created with `mi_heap_new`. -const heap_allocator_vtable = std.mem.Allocator.VTable{ - .alloc = vtable_alloc, - .resize = vtable_resize, - .remap = vtable_remap, - .free = vtable_free, -}; - -/// VTable for the process-wide default allocator (`mi_malloc`/`mi_free`). -const global_mimalloc_vtable = std.mem.Allocator.VTable{ - .alloc = global_vtable_alloc, - .resize = global_vtable_resize, - .remap = global_vtable_remap, - .free = vtable_free, -}; - -const std = @import("std"); -const Alignment = std.mem.Alignment; - -const bun = @import("bun"); -const assert = bun.assert; -const mimalloc = bun.mimalloc; -const Owned = bun.ptr.Owned; -const safety_checks = bun.Environment.ci_assert; diff --git a/src/bun_alloc/NullableAllocator.zig b/src/bun_alloc/NullableAllocator.zig deleted file mode 100644 index e733d964149e..000000000000 --- a/src/bun_alloc/NullableAllocator.zig +++ /dev/null @@ -1,48 +0,0 @@ -//! A nullable allocator the same size as `std.mem.Allocator`. - -const NullableAllocator = @This(); - -ptr: *anyopaque = undefined, -// Utilize the null pointer optimization on the vtable instead of -// the regular `ptr` because `ptr` may be undefined. -vtable: ?*const std.mem.Allocator.VTable = null, - -pub inline fn init(allocator: ?std.mem.Allocator) NullableAllocator { - return if (allocator) |a| .{ - .ptr = a.ptr, - .vtable = a.vtable, - } else .{}; -} - -pub inline fn isNull(this: NullableAllocator) bool { - return this.vtable == null; -} - -pub inline fn isWTFAllocator(this: NullableAllocator) bool { - return bun.String.isWTFAllocator(this.get() orelse return false); -} - -pub inline fn get(this: NullableAllocator) ?std.mem.Allocator { - return if (this.vtable) |vt| std.mem.Allocator{ .ptr = this.ptr, .vtable = vt } else null; -} - -pub fn free(this: *const NullableAllocator, bytes: []const u8) void { - if (this.get()) |allocator| { - if (bun.String.isWTFAllocator(allocator)) { - // avoid calling `std.mem.Allocator.free` as it sets the memory to undefined - allocator.rawFree(@constCast(bytes), .@"1", 0); - return; - } - - allocator.free(bytes); - } -} - -comptime { - if (@sizeOf(NullableAllocator) != @sizeOf(std.mem.Allocator)) { - @compileError("Expected the sizes to be the same."); - } -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bun_alloc/allocation_scope.zig b/src/bun_alloc/allocation_scope.zig deleted file mode 100644 index 75292ee062f0..000000000000 --- a/src/bun_alloc/allocation_scope.zig +++ /dev/null @@ -1,561 +0,0 @@ -//! AllocationScope wraps another allocator, providing leak and invalid free assertions. -//! It also allows measuring how much memory a scope has allocated. - -const allocation_scope = @This(); - -/// An allocation scope with a dynamically typed parent allocator. Prefer using a concrete type, -/// like `AllocationScopeIn(bun.DefaultAllocator)`. -pub const AllocationScope = AllocationScopeIn(std.mem.Allocator); - -pub const Allocation = struct { - allocated_at: StoredTrace, - len: usize, - extra: Extra, -}; - -pub const Free = struct { - allocated_at: StoredTrace, - freed_at: StoredTrace, -}; - -pub const Extra = struct { - ptr: *anyopaque, - vtable: ?*const VTable, - - pub const none: Extra = .{ .ptr = undefined, .vtable = null }; - - pub const VTable = struct { - onAllocationLeak: *const fn (*anyopaque, data: []u8) void, - }; -}; - -pub const Stats = struct { - total_memory_allocated: usize, - num_allocations: usize, -}; - -pub const FreeError = error{ - /// Tried to free memory that wasn't allocated by this `AllocationScope`, or was already freed. - NotAllocated, -}; - -pub const enabled = bun.Environment.enableAllocScopes; -pub const max_free_tracking = 2048 - 1; - -const History = struct { - const Self = @This(); - - total_memory_allocated: usize = 0, - /// Allocated by `State.parent`. - allocations: std.AutoHashMapUnmanaged([*]const u8, Allocation) = .empty, - /// Allocated by `State.parent`. - frees: std.AutoArrayHashMapUnmanaged([*]const u8, Free) = .empty, - /// Once `frees` fills up, entries are overwritten from start to end. - free_overwrite_index: std.math.IntFittingRange(0, max_free_tracking + 1) = 0, - - /// `allocator` should be `State.parent`. - fn deinit(self: *Self, allocator: std.mem.Allocator) void { - self.allocations.deinit(allocator); - self.frees.deinit(allocator); - self.* = undefined; - } -}; - -const LockedState = struct { - const Self = @This(); - - /// Should be the same as `State.parent`. - parent: std.mem.Allocator, - history: *History, - - fn alloc(self: Self, len: usize, alignment: std.mem.Alignment, ret_addr: usize) bun.OOM![*]u8 { - const result = self.parent.rawAlloc(len, alignment, ret_addr) orelse - return error.OutOfMemory; - errdefer self.parent.rawFree(result[0..len], alignment, ret_addr); - try self.trackAllocation(result[0..len], ret_addr, .none); - return result; - } - - fn free(self: Self, buf: []u8, alignment: std.mem.Alignment, ret_addr: usize) void { - const success = if (self.trackFree(buf, ret_addr)) - true - else |err| switch (err) { - error.NotAllocated => false, - }; - if (success or bun.Environment.enable_asan) { - self.parent.rawFree(buf, alignment, ret_addr); - } - if (!success) { - // If asan did not catch the free, panic now. - std.debug.panic("Invalid free: {*}", .{buf}); - } - } - - fn assertOwned(self: Self, ptr: anytype) void { - const cast_ptr: [*]const u8 = @ptrCast(switch (@typeInfo(@TypeOf(ptr)).pointer.size) { - .c, .one, .many => ptr, - .slice => if (ptr.len > 0) ptr.ptr else return, - }); - if (!self.history.allocations.contains(cast_ptr)) { - @panic("this pointer was not owned by the allocation scope"); - } - } - - fn assertUnowned(self: Self, ptr: anytype) void { - const cast_ptr: [*]const u8 = @ptrCast(switch (@typeInfo(@TypeOf(ptr)).pointer.size) { - .c, .one, .many => ptr, - .slice => if (ptr.len > 0) ptr.ptr else return, - }); - if (self.history.allocations.getPtr(cast_ptr)) |owned| { - Output.warn("Owned pointer allocated here:"); - bun.crash_handler.dumpStackTrace( - owned.allocated_at.trace(), - trace_limits, - trace_limits, - ); - @panic("this pointer was owned by the allocation scope when it was not supposed to be"); - } - } - - fn trackAllocation(self: Self, buf: []const u8, ret_addr: usize, extra: Extra) bun.OOM!void { - const trace = StoredTrace.capture(ret_addr); - try self.history.allocations.putNoClobber(self.parent, buf.ptr, .{ - .allocated_at = trace, - .len = buf.len, - .extra = extra, - }); - self.history.total_memory_allocated += buf.len; - } - - fn trackFree(self: Self, buf: []const u8, ret_addr: usize) FreeError!void { - const entry = self.history.allocations.fetchRemove(buf.ptr) orelse { - Output.errGeneric("Invalid free, pointer {*}, len {d}", .{ buf.ptr, buf.len }); - - if (self.history.frees.getPtr(buf.ptr)) |free_entry| { - Output.printErrorln("Pointer allocated here:", .{}); - bun.crash_handler.dumpStackTrace(free_entry.allocated_at.trace(), trace_limits); - Output.printErrorln("Pointer first freed here:", .{}); - bun.crash_handler.dumpStackTrace(free_entry.freed_at.trace(), free_trace_limits); - } - - // do not panic because address sanitizer will catch this case better. - // the log message is in case there is a situation where address - // sanitizer does not catch the invalid free. - return error.NotAllocated; - }; - - self.history.total_memory_allocated -= entry.value.len; - - // Store a limited amount of free entries - if (self.history.frees.count() >= max_free_tracking) { - const i = self.history.free_overwrite_index; - self.history.free_overwrite_index = - @mod(self.history.free_overwrite_index + 1, max_free_tracking); - self.history.frees.swapRemoveAt(i); - } - - self.history.frees.put(self.parent, buf.ptr, .{ - .allocated_at = entry.value.allocated_at, - .freed_at = StoredTrace.capture(ret_addr), - }) catch |err| bun.handleOom(err); - } -}; - -const State = struct { - const Self = @This(); - - /// This field should not be modified. Therefore, it doesn't need to be protected by the mutex. - parent: std.mem.Allocator, - history: bun.threading.Guarded(History), - - fn init(parent_alloc: std.mem.Allocator) Self { - return .{ - .parent = parent_alloc, - .history = .init(.{}), - }; - } - - fn lock(self: *Self) LockedState { - return .{ - .parent = self.parent, - .history = self.history.lock(), - }; - } - - fn unlock(self: *Self) void { - self.history.unlock(); - } - - pub fn deinit(self: *Self) void { - defer self.* = undefined; - var history = self.history.intoUnprotected(); - defer history.deinit(self.parent); - - const count = history.allocations.count(); - if (count == 0) return; - Output.errGeneric("Allocation scope leaked {d} allocations ({f})", .{ - count, - bun.fmt.size(history.total_memory_allocated, .{}), - }); - - var it = history.allocations.iterator(); - var n: usize = 0; - while (it.next()) |entry| : (n += 1) { - if (n >= 10) { - Output.prettyErrorln("(only showing first 10 leaks)", .{}); - break; - } - Output.prettyErrorln( - "- {*}, len {d}, at:", - .{ entry.key_ptr.*, entry.value_ptr.len }, - ); - bun.crash_handler.dumpStackTrace( - entry.value_ptr.allocated_at.trace(), - trace_limits, - ); - const extra = entry.value_ptr.extra; - if (extra.vtable) |extra_vtable| { - extra_vtable.onAllocationLeak( - extra.ptr, - @constCast(entry.key_ptr.*[0..entry.value_ptr.len]), - ); - } - } - - Output.panic( - "Allocation scope leaked {f}", - .{bun.fmt.size(history.total_memory_allocated, .{})}, - ); - } - - fn trackExternalAllocation(self: *Self, ptr: []const u8, ret_addr: ?usize, extra: Extra) void { - const locked = self.lock(); - defer self.unlock(); - locked.trackAllocation(ptr, ret_addr orelse @returnAddress(), extra) catch |err| - bun.handleOom(err); - } - - fn trackExternalFree(self: *Self, slice: anytype, ret_addr: ?usize) FreeError!void { - const invalidType = struct { - fn invalidType() noreturn { - @compileError(std.fmt.comptimePrint( - "This function only supports []u8 or [:sentinel]u8 types, you passed in: {s}", - .{@typeName(@TypeOf(slice))}, - )); - } - }.invalidType; - - const ptr: []const u8 = switch (@typeInfo(@TypeOf(slice))) { - .pointer => |p| switch (p.size) { - .slice => brk: { - if (p.child != u8) invalidType(); - if (p.sentinel_ptr == null) break :brk slice; - // Ensure we include the sentinel value - break :brk slice[0 .. slice.len + 1]; - }, - else => invalidType(), - }, - else => invalidType(), - }; - // Empty slice usually means invalid pointer - if (ptr.len == 0) return; - const locked = self.lock(); - defer self.unlock(); - return locked.trackFree(ptr, ret_addr orelse @returnAddress()); - } - - fn setPointerExtra(self: *Self, ptr: *anyopaque, extra: Extra) void { - const locked = self.lock(); - defer self.unlock(); - const allocation = locked.history.allocations.getPtr(@ptrCast(ptr)) orelse - @panic("Pointer not owned by allocation scope"); - allocation.extra = extra; - } -}; - -/// An allocation scope that uses a specific kind of parent allocator. -/// -/// This type is a `GenericAllocator`; see `src/allocators.zig`. -pub fn AllocationScopeIn(comptime Allocator: type) type { - const BorrowedAllocator = bun.allocators.Borrowed(Allocator); - - // Borrowed version of `AllocationScope`. Access this type as `AllocationScope.Borrowed`. - const BorrowedScope = struct { - const Self = @This(); - - #parent: BorrowedAllocator, - #state: if (enabled) *State else void, - - pub fn allocator(self: Self) std.mem.Allocator { - return if (comptime enabled) - .{ .ptr = self.#state, .vtable = &vtable } - else - bun.allocators.asStd(self.#parent); - } - - pub fn parent(self: Self) BorrowedAllocator { - return self.#parent; - } - - /// Deinitializes a borrowed allocation scope. This does not deinitialize the - /// `AllocationScope` itself; only the owner of the `AllocationScope` should do that. - /// - /// This method doesn't need to be called unless `bun.allocators.Borrowed(Allocator)` has - /// a `deinit` method. - pub fn deinit(self: *Self) void { - bun.memory.deinit(&self.#parent); - self.* = undefined; - } - - pub fn stats(self: Self) Stats { - if (comptime !enabled) @compileError("AllocationScope must be enabled"); - const state = self.#state.lock(); - defer self.#state.unlock(); - return .{ - .total_memory_allocated = state.history.total_memory_allocated, - .num_allocations = state.history.allocations.count(), - }; - } - - pub fn assertOwned(self: Self, ptr: anytype) void { - if (comptime !enabled) return; - const state = self.#state.lock(); - defer self.#state.unlock(); - state.assertOwned(ptr); - } - - pub fn assertUnowned(self: Self, ptr: anytype) void { - if (comptime !enabled) return; - const state = self.#state.lock(); - defer self.#state.unlock(); - state.assertUnowned(ptr); - } - - pub fn trackExternalAllocation( - self: Self, - ptr: []const u8, - ret_addr: ?usize, - extra: Extra, - ) void { - if (comptime enabled) self.#state.trackExternalAllocation(ptr, ret_addr, extra); - } - - pub fn trackExternalFree(self: Self, slice: anytype, ret_addr: ?usize) FreeError!void { - return if (comptime enabled) self.#state.trackExternalFree(slice, ret_addr); - } - - pub fn setPointerExtra(self: Self, ptr: *anyopaque, extra: Extra) void { - if (comptime enabled) self.#state.setPointerExtra(ptr, extra); - } - - fn downcastImpl( - std_alloc: std.mem.Allocator, - parent_alloc: if (Allocator == std.mem.Allocator) - ?BorrowedAllocator - else - BorrowedAllocator, - ) Self { - const state = if (comptime enabled) blk: { - bun.assertf( - std_alloc.vtable == &vtable, - "allocator is not an allocation scope (has vtable {*})", - .{std_alloc.vtable}, - ); - const state: *State = @ptrCast(@alignCast(std_alloc.ptr)); - break :blk state; - }; - - const current_std_parent = if (comptime enabled) - state.parent - else - std_alloc; - - const new_parent = if (comptime Allocator == std.mem.Allocator) - parent_alloc orelse current_std_parent - else - parent_alloc; - - const new_std_parent = bun.allocators.asStd(new_parent); - bun.safety.alloc.assertEqFmt( - current_std_parent, - new_std_parent, - "tried to downcast allocation scope with wrong parent allocator", - .{}, - ); - return .{ .#parent = new_parent, .#state = state }; - } - - /// Converts an `std.mem.Allocator` into a borrowed allocation scope, with a given parent - /// allocator. - /// - /// Requirements: - /// - /// * `std_alloc` must have come from `AllocationScopeIn(Allocator).allocator` (or the - /// equivalent method on a `Borrowed` instance). - /// - /// * `parent_alloc` must be equivalent to the (borrowed) parent allocator of the original - /// allocation scope (that is, the return value of `AllocationScopeIn(Allocator).parent`). - /// In particular, `bun.allocators.asStd` must return the same value for each allocator. - pub fn downcastIn(std_alloc: std.mem.Allocator, parent_alloc: BorrowedAllocator) Self { - return downcastImpl(std_alloc, parent_alloc); - } - - /// Converts an `std.mem.Allocator` into a borrowed allocation scope. - /// - /// Requirements: - /// - /// * `std_alloc` must have come from `AllocationScopeIn(Allocator).allocator` (or the - /// equivalent method on a `Borrowed` instance). - /// - /// * One of the following must be true: - /// - /// 1. `Allocator` is `std.mem.Allocator`. - /// - /// 2. The parent allocator of the original allocation scope is equivalent to a - /// default-initialized borrowed `Allocator`, as returned by - /// `bun.memory.initDefault(bun.allocators.Borrowed(Allocator))`. This is the case - /// for `bun.DefaultAllocator`. - pub fn downcast(std_alloc: std.mem.Allocator) Self { - return downcastImpl(std_alloc, if (comptime Allocator == std.mem.Allocator) - null - else - bun.memory.initDefault(BorrowedAllocator)); - } - }; - - return struct { - const Self = @This(); - - #parent: Allocator, - #state: if (Self.enabled) Owned(*State) else void, - - pub const enabled = allocation_scope.enabled; - - /// Borrowed version of `AllocationScope`, returned by `AllocationScope.borrow`. - /// Using this type makes it clear who actually owns the `AllocationScope`, and prevents - /// `deinit` from being called twice. - /// - /// This type is a `GenericAllocator`; see `src/allocators.zig`. - pub const Borrowed = BorrowedScope; - - pub fn init(parent_alloc: Allocator) Self { - return .{ - .#parent = parent_alloc, - .#state = if (comptime Self.enabled) .new(.init( - bun.allocators.asStd(parent_alloc), - )), - }; - } - - pub fn initDefault() Self { - return .init(bun.memory.initDefault(Allocator)); - } - - /// Borrows this `AllocationScope`. Use this method instead of copying `self`, as that makes - /// it hard to know who owns the `AllocationScope`, and could lead to `deinit` being called - /// twice. - pub fn borrow(self: Self) Borrowed { - return .{ - .#parent = self.parent(), - .#state = if (comptime Self.enabled) self.#state.get(), - }; - } - - pub fn allocator(self: Self) std.mem.Allocator { - return self.borrow().allocator(); - } - - pub fn deinit(self: *Self) void { - bun.memory.deinit(&self.#parent); - if (comptime Self.enabled) self.#state.deinit(); - self.* = undefined; - } - - pub fn parent(self: Self) BorrowedAllocator { - return bun.allocators.borrow(self.#parent); - } - - pub fn stats(self: Self) Stats { - return self.borrow().stats(); - } - - pub fn assertOwned(self: Self, ptr: anytype) void { - self.borrow().assertOwned(ptr); - } - - pub fn assertUnowned(self: Self, ptr: anytype) void { - self.borrow().assertUnowned(ptr); - } - - /// Track an arbitrary pointer. Extra data can be stored in the allocation, which will be - /// printed when a leak is detected. - pub fn trackExternalAllocation( - self: Self, - ptr: []const u8, - ret_addr: ?usize, - extra: Extra, - ) void { - self.borrow().trackExternalAllocation(ptr, ret_addr, extra); - } - - /// Call when the pointer from `trackExternalAllocation` is freed. - pub fn trackExternalFree(self: Self, slice: anytype, ret_addr: ?usize) FreeError!void { - return self.borrow().trackExternalFree(slice, ret_addr); - } - - pub fn setPointerExtra(self: Self, ptr: *anyopaque, extra: Extra) void { - return self.borrow().setPointerExtra(ptr, extra); - } - - pub fn leakSlice(self: Self, memory: anytype) void { - if (comptime !Self.enabled) return; - _ = @typeInfo(@TypeOf(memory)).pointer; - self.trackExternalFree(memory, null) catch @panic("tried to free memory that was not allocated by the allocation scope"); - } - }; -} - -const vtable: std.mem.Allocator.VTable = .{ - .alloc = vtable_alloc, - .resize = std.mem.Allocator.noResize, - .remap = std.mem.Allocator.noRemap, - .free = vtable_free, -}; - -// Smaller traces since AllocationScope prints so many -pub const trace_limits: bun.crash_handler.WriteStackTraceLimits = .{ - .frame_count = 6, - .stop_at_jsc_llint = true, - .skip_stdlib = true, -}; - -pub const free_trace_limits: bun.crash_handler.WriteStackTraceLimits = .{ - .frame_count = 3, - .stop_at_jsc_llint = true, - .skip_stdlib = true, -}; - -fn vtable_alloc(ctx: *anyopaque, len: usize, alignment: std.mem.Alignment, ret_addr: usize) ?[*]u8 { - const raw_state: *State = @ptrCast(@alignCast(ctx)); - const state = raw_state.lock(); - defer raw_state.unlock(); - return state.alloc(len, alignment, ret_addr) catch null; -} - -fn vtable_free(ctx: *anyopaque, buf: []u8, alignment: std.mem.Alignment, ret_addr: usize) void { - const raw_state: *State = @ptrCast(@alignCast(ctx)); - const state = raw_state.lock(); - defer raw_state.unlock(); - state.free(buf, alignment, ret_addr); -} - -pub inline fn isInstance(allocator: std.mem.Allocator) bool { - return (comptime enabled) and allocator.vtable == &vtable; -} - -const std = @import("std"); - -const bun = @import("bun"); -const Output = bun.Output; -const Owned = bun.ptr.Owned; -const StoredTrace = bun.crash_handler.StoredTrace; diff --git a/src/bun_alloc/basic.zig b/src/bun_alloc/basic.zig deleted file mode 100644 index e847a0ddd3a2..000000000000 --- a/src/bun_alloc/basic.zig +++ /dev/null @@ -1,154 +0,0 @@ -const log = bun.Output.scoped(.mimalloc, .hidden); - -fn mimalloc_free( - _: *anyopaque, - buf: []u8, - alignment: Alignment, - _: usize, -) void { - if (comptime Environment.enable_logs) - log("mi_free({d})", .{buf.len}); - // mi_free_size internally just asserts the size - // so it's faster if we don't pass that value through - // but its good to have that assertion - // let's only enable it in debug mode - if (comptime Environment.isDebug) { - if (mimalloc.mustUseAlignedAlloc(alignment)) - mimalloc.mi_free_size_aligned(buf.ptr, buf.len, alignment.toByteUnits()) - else - mimalloc.mi_free_size(buf.ptr, buf.len); - } else { - mimalloc.mi_free(buf.ptr); - } -} - -const MimallocAllocator = struct { - fn alignedAlloc(len: usize, alignment: Alignment) ?[*]u8 { - if (comptime Environment.enable_logs) - log("mi_alloc({d}, {d})", .{ len, alignment.toByteUnits() }); - - const ptr: ?*anyopaque = if (mimalloc.mustUseAlignedAlloc(alignment)) - mimalloc.mi_malloc_aligned(len, alignment.toByteUnits()) - else - mimalloc.mi_malloc(len); - - if (comptime Environment.isDebug) { - if (ptr != null) { - const usable = mimalloc.mi_malloc_usable_size(ptr); - if (usable < len and ptr != null) { - std.debug.panic("mimalloc: allocated size is too small: {d} < {d}", .{ usable, len }); - } - } - } - - return @as(?[*]u8, @ptrCast(ptr)); - } - - fn alignedAllocSize(ptr: [*]u8) usize { - return mimalloc.mi_malloc_size(ptr); - } - - fn alloc_with_default_allocator(_: *anyopaque, len: usize, alignment: Alignment, _: usize) ?[*]u8 { - return alignedAlloc(len, alignment); - } - - fn resize_with_default_allocator(_: *anyopaque, buf: []u8, _: Alignment, new_len: usize, _: usize) bool { - return mimalloc.mi_expand(buf.ptr, new_len) != null; - } - - fn remap_with_default_allocator(_: *anyopaque, buf: []u8, alignment: Alignment, new_len: usize, _: usize) ?[*]u8 { - return @ptrCast(mimalloc.mi_realloc_aligned(buf.ptr, new_len, alignment.toByteUnits())); - } - - const free_with_default_allocator = mimalloc_free; -}; - -pub const c_allocator = Allocator{ - // This ptr can be anything. But since it's not nullable, we should set it to something. - .ptr = memory_allocator_tags.default_allocator_tag_ptr, - .vtable = c_allocator_vtable, -}; -const c_allocator_vtable = &Allocator.VTable{ - .alloc = &MimallocAllocator.alloc_with_default_allocator, - .resize = &MimallocAllocator.resize_with_default_allocator, - .remap = &MimallocAllocator.remap_with_default_allocator, - .free = &MimallocAllocator.free_with_default_allocator, -}; - -const ZAllocator = struct { - fn alignedAlloc(len: usize, alignment: Alignment) ?[*]u8 { - log("ZAllocator.alignedAlloc: {d}\n", .{len}); - - const ptr = if (mimalloc.mustUseAlignedAlloc(alignment)) - mimalloc.mi_zalloc_aligned(len, alignment.toByteUnits()) - else - mimalloc.mi_zalloc(len); - - if (comptime Environment.isDebug) { - if (ptr != null) { - const usable = mimalloc.mi_malloc_usable_size(ptr); - if (usable < len) { - std.debug.panic("mimalloc: allocated size is too small: {d} < {d}", .{ usable, len }); - } - } - } - - return @as(?[*]u8, @ptrCast(ptr)); - } - - fn alignedAllocSize(ptr: [*]u8) usize { - return mimalloc.mi_malloc_size(ptr); - } - - fn alloc_with_z_allocator(_: *anyopaque, len: usize, alignment: Alignment, _: usize) ?[*]u8 { - return alignedAlloc(len, alignment); - } - - fn resize_with_z_allocator(_: *anyopaque, buf: []u8, _: Alignment, new_len: usize, _: usize) bool { - if (new_len <= buf.len) { - return true; - } - - const full_len = alignedAllocSize(buf.ptr); - if (new_len <= full_len) { - return true; - } - - return false; - } - - const free_with_z_allocator = mimalloc_free; -}; - -const memory_allocator_tags = struct { - const default_allocator_tag: usize = 0xBEEFA110C; // "BEEFA110C" beef a110c i guess - pub const default_allocator_tag_ptr: *anyopaque = @ptrFromInt(default_allocator_tag); - - const z_allocator_tag: usize = 0x2a11043470123; // "z4110c4701" (Z ALLOCATOR in 1337 speak) - pub const z_allocator_tag_ptr: *anyopaque = @ptrFromInt(z_allocator_tag); -}; - -pub const z_allocator = Allocator{ - .ptr = memory_allocator_tags.z_allocator_tag_ptr, - .vtable = &z_allocator_vtable, -}; -const z_allocator_vtable = Allocator.VTable{ - .alloc = &ZAllocator.alloc_with_z_allocator, - .resize = &ZAllocator.resize_with_z_allocator, - .remap = &Allocator.noRemap, - .free = &ZAllocator.free_with_z_allocator, -}; - -/// mimalloc can free allocations without being given their size. -pub fn freeWithoutSize(ptr: ?*anyopaque) void { - mimalloc.mi_free(ptr); -} - -const Environment = @import("../bun_core/env.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const mimalloc = bun.mimalloc; - -const Alignment = std.mem.Alignment; -const Allocator = std.mem.Allocator; diff --git a/src/bun_alloc/bun_alloc.zig b/src/bun_alloc/bun_alloc.zig deleted file mode 100644 index 18be563493c5..000000000000 --- a/src/bun_alloc/bun_alloc.zig +++ /dev/null @@ -1,937 +0,0 @@ -pub const c_allocator = basic.c_allocator; -pub const z_allocator = basic.z_allocator; -pub const freeWithoutSize = basic.freeWithoutSize; -pub const mimalloc = @import("../mimalloc_sys/mimalloc.zig"); -pub const MimallocArena = @import("./MimallocArena.zig"); - -pub const allocation_scope = @import("./allocation_scope.zig"); -pub const AllocationScope = allocation_scope.AllocationScope; -pub const AllocationScopeIn = allocation_scope.AllocationScopeIn; - -pub const NullableAllocator = @import("./NullableAllocator.zig"); -pub const MaxHeapAllocator = @import("./MaxHeapAllocator.zig"); -pub const LinuxMemFdAllocator = @import("./LinuxMemFdAllocator.zig"); -pub const BufferFallbackAllocator = @import("./BufferFallbackAllocator.zig"); -pub const MaybeOwned = @import("./maybe_owned.zig").MaybeOwned; - -pub fn isSliceInBufferT(comptime T: type, slice: []const T, buffer: []const T) bool { - return (@intFromPtr(buffer.ptr) <= @intFromPtr(slice.ptr) and - (@intFromPtr(slice.ptr) + slice.len * @sizeOf(T)) <= (@intFromPtr(buffer.ptr) + buffer.len * @sizeOf(T))); -} - -/// Checks if a slice's pointer is contained within another slice. -/// If you need to make this generic, use isSliceInBufferT. -pub fn isSliceInBuffer(slice: []const u8, buffer: []const u8) bool { - return isSliceInBufferT(u8, slice, buffer); -} - -pub fn sliceRange(slice: []const u8, buffer: []const u8) ?[2]u32 { - return if (@intFromPtr(buffer.ptr) <= @intFromPtr(slice.ptr) and - (@intFromPtr(slice.ptr) + slice.len) <= (@intFromPtr(buffer.ptr) + buffer.len)) - [2]u32{ - @as(u32, @truncate(@intFromPtr(slice.ptr) - @intFromPtr(buffer.ptr))), - @as(u32, @truncate(slice.len)), - } - else - null; -} - -pub const IndexType = packed struct(u32) { - index: u31, - is_overflow: bool = false, -}; - -const HashKeyType = u64; -const IndexMapContext = struct { - pub fn hash(_: @This(), key: HashKeyType) HashKeyType { - return key; - } - - pub fn eql(_: @This(), a: HashKeyType, b: HashKeyType) bool { - return a == b; - } -}; - -pub const IndexMap = std.HashMapUnmanaged(HashKeyType, IndexType, IndexMapContext, 80); - -pub const IndexMapManaged = std.HashMap(HashKeyType, IndexType, IndexMapContext, 80); -pub const Result = struct { - hash: HashKeyType, - index: IndexType, - status: ItemStatus, - - pub fn hasCheckedIfExists(r: *const Result) bool { - return r.index.index != Unassigned.index; - } - - pub fn isOverflowing(r: *const Result, comptime count: usize) bool { - return r.index >= count; - } -}; - -pub const NotFound = IndexType{ - .index = std.math.maxInt(u31), -}; -pub const Unassigned = IndexType{ - .index = std.math.maxInt(u31) - 1, -}; - -pub const ItemStatus = enum(u3) { - unknown, - exists, - not_found, -}; - -fn OverflowGroup(comptime Block: type) type { - return struct { - const Overflow = @This(); - // 16 million files should be good enough for anyone - // ...right? - const max = 4095; - const UsedSize = std.math.IntFittingRange(0, max + 1); - const default_allocator = bun.default_allocator; - used: UsedSize, - allocated: UsedSize, - ptrs: [max]*Block, - - pub inline fn zero(this: *Overflow) void { - this.used = 0; - this.allocated = 0; - } - - pub fn tail(this: *Overflow) *Block { - if (this.allocated > 0 and this.ptrs[this.used].isFull()) { - this.used +%= 1; - if (this.allocated > this.used) { - this.ptrs[this.used].used = 0; - } - } - - if (this.allocated <= this.used) { - this.ptrs[this.allocated] = default_allocator.create(Block) catch unreachable; - this.ptrs[this.allocated].zero(); - this.allocated +%= 1; - } - - return this.ptrs[this.used]; - } - - pub inline fn slice(this: *Overflow) []*Block { - return this.ptrs[0..this.used]; - } - }; -} - -pub fn OverflowList(comptime ValueType: type, comptime count: comptime_int) type { - return struct { - const This = @This(); - const SizeType = std.math.IntFittingRange(0, count); - - const Block = struct { - used: SizeType, - items: [count]ValueType, - - pub inline fn zero(this: *Block) void { - this.used = 0; - } - - pub inline fn isFull(block: *const Block) bool { - return block.used >= @as(SizeType, count); - } - - pub fn append(block: *Block, value: ValueType) *ValueType { - if (comptime Environment.allow_assert) bun.assert(block.used < count); - const index = block.used; - block.items[index] = value; - block.used +%= 1; - return &block.items[index]; - } - }; - const Overflow = OverflowGroup(Block); - list: Overflow, - count: u31, - - pub inline fn zero(this: *This) void { - this.list.zero(); - this.count = 0; - } - - pub inline fn len(this: *const This) u31 { - return this.count; - } - - pub inline fn append(this: *This, value: ValueType) *ValueType { - this.count += 1; - return this.list.tail().append(value); - } - - fn reset(this: *This) void { - for (this.list.slice()) |block| { - block.used = 0; - } - this.list.used = 0; - } - - pub inline fn atIndex(this: *const This, index: IndexType) *const ValueType { - const block_id = if (index.index > 0) - index.index / count - else - 0; - - if (comptime Environment.allow_assert) bun.assert(index.is_overflow); - if (comptime Environment.allow_assert) bun.assert(this.list.used >= block_id); - if (comptime Environment.allow_assert) bun.assert(this.list.ptrs[block_id].used > (index.index % count)); - - return &this.list.ptrs[block_id].items[index.index % count]; - } - - pub inline fn atIndexMut(this: *This, index: IndexType) *ValueType { - const block_id = if (index.index > 0) - index.index / count - else - 0; - - if (comptime Environment.allow_assert) bun.assert(index.is_overflow); - if (comptime Environment.allow_assert) bun.assert(this.list.used >= block_id); - if (comptime Environment.allow_assert) bun.assert(this.list.ptrs[block_id].used > (index.index % count)); - - return &this.list.ptrs[block_id].items[index.index % count]; - } - }; -} - -/// "Formerly-BSSList" -/// It's not actually BSS anymore. -/// -/// We do keep a pointer to it globally, but because the data is not zero-initialized, it ends up taking space in the object file. -/// We don't want to spend 1-2 MB on these structs. -pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type { - const count = _count * 2; - const max_index = count - 1; - return struct { - const ChunkSize = 256; - const OverflowBlock = struct { - used: std.atomic.Value(u16), - data: [ChunkSize]ValueType, - prev: ?*OverflowBlock, - - pub inline fn zero(this: *OverflowBlock) void { - // Avoid struct initialization syntax. - // This makes Bun start about 1ms faster. - // https://github.com/ziglang/zig/issues/24313 - this.used = std.atomic.Value(u16).init(0); - this.prev = null; - } - - pub fn append(this: *OverflowBlock, item: ValueType) !*ValueType { - const index = this.used.fetchAdd(1, .acq_rel); - if (index >= ChunkSize) return error.OutOfMemory; - this.data[index] = item; - return &this.data[index]; - } - - pub fn deinit(this: *OverflowBlock) void { - if (this.prev) |p| p.deinit(); - bun.default_allocator.destroy(this); - } - }; - - const Self = @This(); - - allocator: std.mem.Allocator, - mutex: Mutex = .{}, - head: *OverflowBlock, - tail: OverflowBlock, - backing_buf: [count]ValueType, - used: u32, - - pub var instance: *Self = undefined; - pub var loaded = false; - - pub inline fn blockIndex(index: u31) usize { - return index / ChunkSize; - } - - pub fn init(allocator: std.mem.Allocator) *Self { - if (!loaded) { - instance = bun.handleOom(bun.default_allocator.create(Self)); - // Avoid struct initialization syntax. - // This makes Bun start about 1ms faster. - // https://github.com/ziglang/zig/issues/24313 - instance.allocator = allocator; - instance.mutex = .{}; - instance.tail.zero(); - instance.head = &instance.tail; - instance.used = 0; - loaded = true; - } - - return instance; - } - - pub fn deinit(self: *Self) void { - self.head.deinit(); - bun.default_allocator.destroy(instance); - loaded = false; - } - - pub fn isOverflowing() bool { - return instance.used >= @as(u16, count); - } - - pub fn exists(_: *Self, value: ValueType) bool { - return isSliceInBuffer(value, instance.backing_buf); - } - - fn appendOverflow(self: *Self, value: ValueType) !*ValueType { - instance.used += 1; - return self.head.append(value) catch brk: { - var new_block = try self.allocator.create(OverflowBlock); - new_block.zero(); - new_block.prev = self.head; - self.head = new_block; - break :brk self.head.append(value); - }; - } - - pub fn append(self: *Self, value: ValueType) !*ValueType { - self.mutex.lock(); - defer self.mutex.unlock(); - if (instance.used > max_index) { - return self.appendOverflow(value); - } else { - const index = instance.used; - instance.backing_buf[index] = value; - instance.used += 1; - return &instance.backing_buf[index]; - } - } - pub const Pair = struct { index: IndexType, value: *ValueType }; - }; -} - -/// Append-only list. -/// Stores an initial count in .bss section of the object file -/// Overflows to heap when count is exceeded. -pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type { - // I experimented with string interning here and it was around...maybe 1% when generating a .bun? - // I tried: - // - arraybacked list - // - hashmap list - - // + 1 for sentinel - const item_length = _item_length + 1; - const count = _count * 2; - const max_index = count - 1; - const ValueType = []const u8; - - return struct { - pub const Overflow = OverflowList([]const u8, count / 4); - const Self = @This(); - - backing_buf: [count * item_length]u8, - backing_buf_used: u64, - overflow_list: Overflow, - allocator: std.mem.Allocator, - slice_buf: [count][]const u8, - slice_buf_used: u16, - mutex: Mutex = .{}, - pub var instance: *Self = undefined; - var loaded: bool = false; - // only need the mutex on append - - const EmptyType = struct { - len: usize = 0, - }; - - pub fn init(allocator: std.mem.Allocator) *Self { - if (!loaded) { - instance = bun.handleOom(bun.default_allocator.create(Self)); - // Avoid struct initialization syntax. - // This makes Bun start about 1ms faster. - // https://github.com/ziglang/zig/issues/24313 - instance.allocator = allocator; - instance.backing_buf_used = 0; - instance.slice_buf_used = 0; - instance.overflow_list.zero(); - instance.mutex = .{}; - loaded = true; - } - - return instance; - } - - pub fn deinit(self: *Self) void { - _ = self; - bun.default_allocator.destroy(instance); - loaded = false; - } - - pub inline fn isOverflowing() bool { - return instance.slice_buf_used >= @as(u16, count); - } - - pub fn exists(self: *const Self, value: ValueType) bool { - return isSliceInBuffer(value, &self.backing_buf); - } - - pub fn editableSlice(slice: []const u8) []u8 { - return @constCast(slice); - } - - pub fn appendMutable(self: *Self, comptime AppendType: type, _value: AppendType) OOM![]u8 { - const appended = try @call(bun.callmod_inline, append, .{ self, AppendType, _value }); - return @constCast(appended); - } - - pub fn getMutable(self: *Self, len: usize) ![]u8 { - return try self.appendMutable(EmptyType, EmptyType{ .len = len }); - } - - pub fn printWithType(self: *Self, comptime fmt: []const u8, comptime Args: type, args: Args) OOM![]const u8 { - var buf = try self.appendMutable(EmptyType, EmptyType{ .len = std.fmt.count(fmt, args) + 1 }); - buf[buf.len - 1] = 0; - return std.fmt.bufPrint(buf.ptr[0 .. buf.len - 1], fmt, args) catch unreachable; - } - - pub fn print(self: *Self, comptime fmt: []const u8, args: anytype) OOM![]const u8 { - return try printWithType(self, fmt, @TypeOf(args), args); - } - - pub fn append(self: *Self, comptime AppendType: type, _value: AppendType) OOM![]const u8 { - self.mutex.lock(); - defer self.mutex.unlock(); - - return try self.doAppend(AppendType, _value); - } - - const lowercase_bufs = bun.ThreadlocalBuffers(struct { buf: bun.PathBuffer = undefined }); - pub fn appendLowerCase(self: *Self, comptime AppendType: type, _value: AppendType) OOM![]const u8 { - self.mutex.lock(); - defer self.mutex.unlock(); - - const lowercase_append_buf = &lowercase_bufs.get().buf; - for (_value, 0..) |c, i| { - lowercase_append_buf[i] = std.ascii.toLower(c); - } - const slice = lowercase_append_buf[0.._value.len]; - - return self.doAppend( - @TypeOf(slice), - slice, - ); - } - - inline fn doAppend( - self: *Self, - comptime AppendType: type, - _value: AppendType, - ) OOM![]const u8 { - const value_len: usize = brk: { - switch (comptime AppendType) { - EmptyType, []const u8, []u8, [:0]const u8, [:0]u8 => { - break :brk _value.len; - }, - else => { - var len: usize = 0; - for (_value) |val| { - len += val.len; - } - break :brk len; - }, - } - unreachable; - } + 1; - - var value: [:0]u8 = undefined; - if (value_len + instance.backing_buf_used < instance.backing_buf.len - 1) { - const start = instance.backing_buf_used; - instance.backing_buf_used += value_len; - - switch (AppendType) { - EmptyType => { - instance.backing_buf[instance.backing_buf_used - 1] = 0; - }, - []const u8, []u8, [:0]const u8, [:0]u8 => { - bun.copy(u8, instance.backing_buf[start .. instance.backing_buf_used - 1], _value); - instance.backing_buf[instance.backing_buf_used - 1] = 0; - }, - else => { - var remainder = instance.backing_buf[start..]; - for (_value) |val| { - bun.copy(u8, remainder, val); - remainder = remainder[val.len..]; - } - remainder[0] = 0; - }, - } - - value = instance.backing_buf[start .. instance.backing_buf_used - 1 :0]; - } else { - var value_buf = try self.allocator.alloc(u8, value_len); - - switch (comptime AppendType) { - EmptyType => {}, - []const u8, []u8, [:0]const u8, [:0]u8 => { - bun.copy(u8, value_buf, _value); - }, - else => { - var remainder = value_buf; - for (_value) |val| { - bun.copy(u8, remainder, val); - remainder = remainder[val.len..]; - } - }, - } - - value_buf[value_len - 1] = 0; - value = value_buf[0 .. value_len - 1 :0]; - } - - var result = IndexType{ .index = std.math.maxInt(u31), .is_overflow = instance.slice_buf_used > max_index }; - - if (result.is_overflow) { - result.index = @as(u31, @intCast(self.overflow_list.len())); - } else { - result.index = instance.slice_buf_used; - instance.slice_buf_used += 1; - } - - if (result.is_overflow) { - if (self.overflow_list.len() == result.index) { - _ = self.overflow_list.append(value); - } else { - self.overflow_list.atIndexMut(result).* = value; - } - - return value; - } else { - instance.slice_buf[result.index] = value; - - return instance.slice_buf[result.index]; - } - } - }; -} - -pub fn BSSMap(comptime ValueType: type, comptime count: anytype, comptime store_keys: bool, comptime estimated_key_length: usize, comptime remove_trailing_slashes: bool) type { - const max_index = count - 1; - const BSSMapType = struct { - const Self = @This(); - const Overflow = OverflowList(ValueType, count / 4); - - index: IndexMap, - overflow_list: Overflow, - allocator: std.mem.Allocator, - mutex: Mutex = .{}, - backing_buf: [count]ValueType, - backing_buf_used: u16, - - pub var instance: *Self = undefined; - - var loaded: bool = false; - - pub fn init(allocator: std.mem.Allocator) *Self { - if (!loaded) { - // Avoid struct initialization syntax. - // This makes Bun start about 1ms faster. - // https://github.com/ziglang/zig/issues/24313 - instance = bun.handleOom(bun.default_allocator.create(Self)); - instance.index = IndexMap{}; - instance.allocator = allocator; - instance.overflow_list.zero(); - instance.backing_buf_used = 0; - instance.mutex = .{}; - loaded = true; - } - - return instance; - } - - pub fn deinit(self: *Self) void { - self.index.deinit(self.allocator); - bun.default_allocator.destroy(instance); - loaded = false; - } - - pub fn isOverflowing() bool { - return instance.backing_buf_used >= @as(u16, count); - } - - pub fn getOrPut(self: *Self, denormalized_key: []const u8) !Result { - const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, std.fs.path.sep_str) else denormalized_key; - const _key = bun.hash(key); - - self.mutex.lock(); - defer self.mutex.unlock(); - const index = try self.index.getOrPut(self.allocator, _key); - - if (index.found_existing) { - return Result{ - .hash = _key, - .index = index.value_ptr.*, - .status = switch (index.value_ptr.index) { - NotFound.index => .not_found, - Unassigned.index => .unknown, - else => .exists, - }, - }; - } - index.value_ptr.* = Unassigned; - - return Result{ - .hash = _key, - .index = Unassigned, - .status = .unknown, - }; - } - - pub fn get(self: *Self, denormalized_key: []const u8) ?*ValueType { - const key = if (comptime remove_trailing_slashes) std.mem.trimRight(u8, denormalized_key, std.fs.path.sep_str) else denormalized_key; - const _key = bun.hash(key); - self.mutex.lock(); - defer self.mutex.unlock(); - const index = self.index.get(_key) orelse return null; - return self.atIndex(index); - } - - pub fn markNotFound(self: *Self, result: Result) void { - self.mutex.lock(); - defer self.mutex.unlock(); - - self.index.put(self.allocator, result.hash, NotFound) catch unreachable; - } - - pub fn atIndex(self: *Self, index: IndexType) ?*ValueType { - if (index.index == NotFound.index or index.index == Unassigned.index) return null; - - if (index.is_overflow) { - return self.overflow_list.atIndexMut(index); - } else { - return &instance.backing_buf[index.index]; - } - } - - pub fn put(self: *Self, result: *Result, value: ValueType) !*ValueType { - self.mutex.lock(); - defer self.mutex.unlock(); - - if (result.index.index == NotFound.index or result.index.index == Unassigned.index) { - result.index.is_overflow = instance.backing_buf_used > max_index; - if (result.index.is_overflow) { - result.index.index = self.overflow_list.len(); - } else { - result.index.index = instance.backing_buf_used; - instance.backing_buf_used += 1; - } - } - - try self.index.put(self.allocator, result.hash, result.index); - - if (result.index.is_overflow) { - if (self.overflow_list.len() == result.index.index) { - return self.overflow_list.append(value); - } else { - const ptr = self.overflow_list.atIndexMut(result.index); - ptr.* = value; - return ptr; - } - } else { - instance.backing_buf[result.index.index] = value; - - return &instance.backing_buf[result.index.index]; - } - } - - /// Returns true if the entry was removed - pub fn remove(self: *Self, denormalized_key: []const u8) bool { - self.mutex.lock(); - defer self.mutex.unlock(); - - const key = if (comptime remove_trailing_slashes) - std.mem.trimRight(u8, denormalized_key, std.fs.path.sep_str) - else - denormalized_key; - - const _key = bun.hash(key); - return self.index.remove(_key); - // const index = self.index.get(_key) orelse return; - // switch (index) { - // Unassigned.index, NotFound.index => { - // self.index.remove(_key); - // }, - // 0...max_index => { - // if (comptime hasDeinit(ValueType)) { - // instance.backing_buf[index].deinit(); - // } - - // instance.backing_buf[index] = undefined; - // }, - // else => { - // const i = index - count; - // if (hasDeinit(ValueType)) { - // self.overflow_list.items[i].deinit(); - // } - // self.overflow_list.items[index - count] = undefined; - // }, - // } - - } - - pub fn values(self: *Self) []ValueType { - return (&self.backing_buf)[0..self.backing_buf_used]; - } - }; - if (!store_keys) { - return BSSMapType; - } - - return struct { - map: *BSSMapType, - key_list_buffer: [count * estimated_key_length]u8 = undefined, - key_list_buffer_used: usize = 0, - key_list_slices: [count][]u8 = undefined, - key_list_overflow: OverflowList([]u8, count / 4) = OverflowList([]u8, count / 4){}, - - const Self = @This(); - pub var instance: *Self = undefined; - pub var instance_loaded = false; - - pub fn init(allocator: std.mem.Allocator) *Self { - if (!instance_loaded) { - instance = bun.handleOom(bun.default_allocator.create(Self)); - // Avoid struct initialization syntax. - // This makes Bun start about 1ms faster. - // https://github.com/ziglang/zig/issues/24313 - instance.map = BSSMapType.init(allocator); - instance.key_list_buffer_used = 0; - instance.key_list_overflow.zero(); - instance_loaded = true; - } - - return instance; - } - - pub fn deinit(self: *Self) void { - self.map.deinit(); - bun.default_allocator.destroy(instance); - instance_loaded = false; - } - - pub fn isOverflowing() bool { - return instance.map.backing_buf_used >= count; - } - pub fn getOrPut(self: *Self, key: []const u8) !Result { - return try self.map.getOrPut(key); - } - pub fn get(self: *Self, key: []const u8) ?*ValueType { - return @call(bun.callmod_inline, BSSMapType.get, .{ self.map, key }); - } - - pub fn atIndex(self: *Self, index: IndexType) ?*ValueType { - return @call(bun.callmod_inline, BSSMapType.atIndex, .{ self.map, index }); - } - - pub fn keyAtIndex(_: *Self, index: IndexType) ?[]const u8 { - return switch (index.index) { - Unassigned.index, NotFound.index => null, - else => { - if (!index.is_overflow) { - return instance.key_list_slices[index.index]; - } else { - return instance.key_list_overflow.items[index.index]; - } - }, - }; - } - - pub fn put(self: *Self, key: anytype, comptime store_key: bool, result: *Result, value: ValueType) !*ValueType { - const ptr = try self.map.put(result, value); - if (store_key) { - try self.putKey(key, result); - } - - return ptr; - } - - pub fn isKeyStaticallyAllocated(key: anytype) bool { - return isSliceInBuffer(key, &instance.key_list_buffer); - } - - // There's two parts to this. - // 1. Storing the underlying string. - // 2. Making the key accessible at the index. - pub fn putKey(self: *Self, key: anytype, result: *Result) !void { - self.map.mutex.lock(); - defer self.map.mutex.unlock(); - var slice: []u8 = undefined; - - // Is this actually a slice into the map? Don't free it. - if (isKeyStaticallyAllocated(key)) { - slice = key; - } else if (instance.key_list_buffer_used + key.len < instance.key_list_buffer.len) { - const start = instance.key_list_buffer_used; - instance.key_list_buffer_used += key.len; - slice = instance.key_list_buffer[start..instance.key_list_buffer_used]; - bun.copy(u8, slice, key); - } else { - slice = try self.map.allocator.dupe(u8, key); - } - - if (comptime remove_trailing_slashes) { - slice = std.mem.trimRight(u8, slice, "/"); - } - - if (!result.index.is_overflow) { - instance.key_list_slices[result.index.index] = slice; - } else { - if (@as(u31, @intCast(instance.key_list_overflow.items.len)) > result.index.index) { - const existing_slice = instance.key_list_overflow.items[result.index.index]; - if (!isKeyStaticallyAllocated(existing_slice)) { - self.map.allocator.free(existing_slice); - } - instance.key_list_overflow.items[result.index.index] = slice; - } else { - try instance.key_list_overflow.append(self.map.allocator, slice); - } - } - } - - pub fn markNotFound(self: *Self, result: Result) void { - self.map.markNotFound(result); - } - - /// This does not free the keys. - /// Returns `true` if an entry had previously existed. - pub fn remove(self: *Self, key: []const u8) bool { - return self.map.remove(key); - } - }; -} - -/// Checks whether `allocator` is the default allocator. -pub fn isDefault(allocator: std.mem.Allocator) bool { - return allocator.vtable == c_allocator.vtable; -} - -// The following functions operate on generic allocators. A generic allocator is a type that -// satisfies the `GenericAllocator` interface: -// -// ``` -// const GenericAllocator = struct { -// // Required. -// pub fn allocator(self: Self) std.mem.Allocator; -// -// // Optional, to allow default-initialization. `.{}` will also be tried. -// pub fn init() Self; -// -// // Optional, if this allocator owns auxiliary resources that need to be deinitialized. -// pub fn deinit(self: *Self) void; -// -// // Optional. Defining a borrowed type makes it clear who owns the allocator and prevents -// // `deinit` from being called twice. -// pub const Borrowed: type; -// pub fn borrow(self: Self) Borrowed; -// }; -// ``` -// -// Generic allocators must support being moved. They cannot contain self-references, and they cannot -// serve allocations from a buffer that exists within the allocator itself (have your allocator type -// contain a pointer to the buffer instead). -// -// As an exception, `std.mem.Allocator` is also treated as a generic allocator, and receives -// special handling in the following functions to achieve this. - -/// Gets the `std.mem.Allocator` for a given generic allocator. -pub fn asStd(allocator: anytype) std.mem.Allocator { - return if (comptime @TypeOf(allocator) == std.mem.Allocator) - allocator - else - allocator.allocator(); -} - -/// A borrowed version of an allocator. -/// -/// Some allocators have a `deinit` method that would be invalid to call multiple times (e.g., -/// `AllocationScope` and `MimallocArena`). -/// -/// If multiple structs or functions need access to the same allocator, we want to avoid simply -/// passing the allocator by value, as this could easily lead to `deinit` being called multiple -/// times if we forget who really owns the allocator. -/// -/// Passing a pointer is not always a good approach, as this results in a performance penalty for -/// zero-sized allocators, and adds another level of indirection in all cases. -/// -/// This function allows allocators that have a concept of being "owned" to define a "borrowed" -/// version of the allocator. If no such type is defined, it is assumed the allocator does not -/// own any data, and `Borrowed(Allocator)` is simply the same as `Allocator`. -pub fn Borrowed(comptime Allocator: type) type { - return if (comptime @hasDecl(Allocator, "Borrowed")) - Allocator.Borrowed - else - Allocator; -} - -/// Borrows an allocator. -/// -/// See `Borrowed` for the rationale. -pub fn borrow(allocator: anytype) Borrowed(@TypeOf(allocator)) { - return if (comptime @hasDecl(@TypeOf(allocator), "Borrowed")) - allocator.borrow() - else - allocator; -} - -/// A type that behaves like `?Allocator`. This function will either return `?Allocator` itself, -/// or an optimized type that behaves like `?Allocator`. -/// -/// Use `initNullable` and `unpackNullable` to work with the returned type. -pub fn Nullable(comptime Allocator: type) type { - return if (comptime Allocator == std.mem.Allocator) - NullableAllocator - else if (comptime @hasDecl(Allocator, "Nullable")) - Allocator.Nullable - else - ?Allocator; -} - -/// Creates a `Nullable(Allocator)` from an optional `Allocator`. -pub fn initNullable(comptime Allocator: type, allocator: ?Allocator) Nullable(Allocator) { - return if (comptime Allocator == std.mem.Allocator or @hasDecl(Allocator, "Nullable")) - .init(allocator) - else - allocator; -} - -/// Turns a `Nullable(Allocator)` back into an optional `Allocator`. -pub fn unpackNullable(comptime Allocator: type, allocator: Nullable(Allocator)) ?Allocator { - return if (comptime Allocator == std.mem.Allocator or @hasDecl(Allocator, "Nullable")) - .get() - else - allocator; -} - -/// The default allocator. This is a zero-sized type whose `allocator` method returns -/// `bun.default_allocator`. -/// -/// This type is a `GenericAllocator`; see `src/allocators.zig`. -pub const Default = struct { - pub fn allocator(self: Default) std.mem.Allocator { - _ = self; - return c_allocator; - } - - pub const deinit = void; -}; - -const basic = if (bun.use_mimalloc) - @import("./basic.zig") -else - @import("./fallback.zig"); - -const Environment = @import("../bun_core/env.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const OOM = bun.OOM; -const Mutex = bun.threading.Mutex; diff --git a/src/bun_alloc/fallback.zig b/src/bun_alloc/fallback.zig deleted file mode 100644 index caf389a42fd9..000000000000 --- a/src/bun_alloc/fallback.zig +++ /dev/null @@ -1,9 +0,0 @@ -pub const c_allocator = std.heap.c_allocator; -pub const z_allocator = @import("./fallback/z.zig").allocator; - -/// libc can free allocations without being given their size. -pub fn freeWithoutSize(ptr: ?*anyopaque) void { - std.c.free(ptr); -} - -const std = @import("std"); diff --git a/src/bun_alloc/fallback/z.zig b/src/bun_alloc/fallback/z.zig deleted file mode 100644 index c44c0debc827..000000000000 --- a/src/bun_alloc/fallback/z.zig +++ /dev/null @@ -1,43 +0,0 @@ -/// A fallback zero-initializing allocator. -pub const allocator = Allocator{ - .ptr = undefined, - .vtable = &vtable, -}; - -const vtable = Allocator.VTable{ - .alloc = alloc, - .resize = resize, - .remap = Allocator.noRemap, // the mimalloc z_allocator doesn't support remap - .free = free, -}; - -fn alloc(_: *anyopaque, len: usize, alignment: Alignment, return_address: usize) ?[*]u8 { - const result = c_allocator.rawAlloc(len, alignment, return_address) orelse - return null; - @memset(result[0..len], 0); - return result; -} - -fn resize( - _: *anyopaque, - buf: []u8, - alignment: Alignment, - new_len: usize, - return_address: usize, -) bool { - if (!c_allocator.rawResize(buf, alignment, new_len, return_address)) { - return false; - } - @memset(buf.ptr[buf.len..new_len], 0); - return true; -} - -fn free(_: *anyopaque, buf: []u8, alignment: Alignment, return_address: usize) void { - c_allocator.rawFree(buf, alignment, return_address); -} - -const std = @import("std"); -const c_allocator = std.heap.c_allocator; - -const Alignment = std.mem.Alignment; -const Allocator = std.mem.Allocator; diff --git a/src/bun_alloc/heap_breakdown.zig b/src/bun_alloc/heap_breakdown.zig deleted file mode 100644 index dc20c07efb64..000000000000 --- a/src/bun_alloc/heap_breakdown.zig +++ /dev/null @@ -1,146 +0,0 @@ -const vm_size_t = usize; - -pub const enabled = Environment.allow_assert and Environment.isMac and !Environment.enable_asan; - -fn heapLabel(comptime T: type) [:0]const u8 { - const base_name = if (comptime bun.meta.hasDecl(T, "heap_label")) - T.heap_label - else - bun.meta.typeBaseName(@typeName(T)); - return base_name; -} - -pub fn allocator(comptime T: type) std.mem.Allocator { - return namedAllocator(comptime heapLabel(T)); -} -pub fn namedAllocator(comptime name: [:0]const u8) std.mem.Allocator { - return getZone("Bun__" ++ name).allocator(); -} - -pub fn getZoneT(comptime T: type) *Zone { - return getZone(comptime heapLabel(T)); -} - -pub fn getZone(comptime name: [:0]const u8) *Zone { - comptime bun.assert(enabled); - - const static = struct { - pub var zone: *Zone = undefined; - pub fn initOnce() void { - zone = Zone.init(name); - } - - pub var once = std.once(initOnce); - }; - - static.once.call(); - return static.zone; -} - -pub const Zone = opaque { - pub fn init(comptime name: [:0]const u8) *Zone { - const zone = malloc_create_zone(0, 0); - - malloc_set_zone_name(zone, name.ptr); - - return zone; - } - - fn alignedAlloc(zone: *Zone, len: usize, alignment: std.mem.Alignment) ?[*]u8 { - // The posix_memalign only accepts alignment values that are a - // multiple of the pointer size - const eff_alignment = @max(alignment.toByteUnits(), @sizeOf(usize)); - const ptr = malloc_zone_memalign(zone, eff_alignment, len); - return @as(?[*]u8, @ptrCast(ptr)); - } - - fn alignedAllocSize(ptr: [*]u8) usize { - return std.c.malloc_size(ptr); - } - - fn rawAlloc(zone: *anyopaque, len: usize, alignment: std.mem.Alignment, _: usize) ?[*]u8 { - return alignedAlloc(@ptrCast(zone), len, alignment); - } - - fn resize(_: *anyopaque, buf: []u8, _: std.mem.Alignment, new_len: usize, _: usize) bool { - if (new_len <= buf.len) { - return true; - } - - const full_len = alignedAllocSize(buf.ptr); - if (new_len <= full_len) { - return true; - } - - return false; - } - - fn rawFree(zone: *anyopaque, buf: []u8, _: std.mem.Alignment, _: usize) void { - malloc_zone_free(@ptrCast(zone), @ptrCast(buf.ptr)); - } - - pub const vtable = std.mem.Allocator.VTable{ - .alloc = &rawAlloc, - .resize = &resize, - .remap = &std.mem.Allocator.noRemap, - .free = &rawFree, - }; - - pub fn allocator(zone: *Zone) std.mem.Allocator { - return .{ - .vtable = &vtable, - .ptr = zone, - }; - } - - /// Create a single-item pointer with initialized data. - pub inline fn create(zone: *Zone, comptime T: type, data: T) *T { - return bun.handleOom(zone.tryCreate(T, data)); - } - - /// Error-returning version of `create`. - pub inline fn tryCreate(zone: *Zone, comptime T: type, data: T) !*T { - const alignment: std.mem.Alignment = .fromByteUnits(@alignOf(T)); - const ptr: *T = @ptrCast(@alignCast( - rawAlloc(zone, @sizeOf(T), alignment, @returnAddress()) orelse return error.OutOfMemory, - )); - ptr.* = data; - return ptr; - } - - /// Free a single-item pointer - pub inline fn destroy(zone: *Zone, comptime T: type, ptr: *T) void { - malloc_zone_free(zone, @ptrCast(ptr)); - } - - pub fn isInstance(allocator_: std.mem.Allocator) bool { - return allocator_.vtable == &vtable; - } - - pub extern fn malloc_default_zone() *Zone; - pub extern fn malloc_create_zone(start_size: vm_size_t, flags: c_uint) *Zone; - pub extern fn malloc_destroy_zone(zone: *Zone) void; - pub extern fn malloc_zone_malloc(zone: *Zone, size: usize) ?*anyopaque; - pub extern fn malloc_zone_calloc(zone: *Zone, num_items: usize, size: usize) ?*anyopaque; - pub extern fn malloc_zone_valloc(zone: *Zone, size: usize) ?*anyopaque; - pub extern fn malloc_zone_free(zone: *Zone, ptr: ?*anyopaque) void; - pub extern fn malloc_zone_realloc(zone: *Zone, ptr: ?*anyopaque, size: usize) ?*anyopaque; - pub extern fn malloc_zone_from_ptr(ptr: ?*const anyopaque) *Zone; - pub extern fn malloc_zone_memalign(zone: *Zone, alignment: usize, size: usize) ?*anyopaque; - pub extern fn malloc_zone_batch_malloc(zone: *Zone, size: usize, results: [*]?*anyopaque, num_requested: c_uint) c_uint; - pub extern fn malloc_zone_batch_free(zone: *Zone, to_be_freed: [*]?*anyopaque, num: c_uint) void; - pub extern fn malloc_default_purgeable_zone() *Zone; - pub extern fn malloc_make_purgeable(ptr: ?*anyopaque) void; - pub extern fn malloc_make_nonpurgeable(ptr: ?*anyopaque) c_int; - pub extern fn malloc_zone_register(zone: *Zone) void; - pub extern fn malloc_zone_unregister(zone: *Zone) void; - pub extern fn malloc_set_zone_name(zone: *Zone, name: ?[*:0]const u8) void; - pub extern fn malloc_get_zone_name(zone: *Zone) ?[*:0]const u8; - pub extern fn malloc_zone_pressure_relief(zone: *Zone, goal: usize) usize; -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; - -const bun = @import("bun"); -const Environment = bun.Environment; diff --git a/src/bun_alloc/maybe_owned.zig b/src/bun_alloc/maybe_owned.zig deleted file mode 100644 index 61f9a4067896..000000000000 --- a/src/bun_alloc/maybe_owned.zig +++ /dev/null @@ -1,112 +0,0 @@ -/// This type can be used with `bun.ptr.Owned` to model "maybe owned" pointers: -/// -/// ``` -/// // Either owned by the default allocator, or borrowed -/// const MaybeOwnedFoo = bun.ptr.OwnedIn(*Foo, bun.allocators.MaybeOwned(bun.DefaultAllocator)); -/// -/// var owned_foo: MaybeOwnedFoo = .new(makeFoo()); -/// var borrowed_foo: MaybeOwnedFoo = .fromRawIn(some_foo_ptr, .initBorrowed()); -/// -/// owned_foo.deinit(); // calls `Foo.deinit` and frees the memory -/// borrowed_foo.deinit(); // no-op -/// ``` -/// -/// This type is a `GenericAllocator`; see `src/allocators.zig`. -pub fn MaybeOwned(comptime Allocator: type) type { - return struct { - const Self = @This(); - - _parent: bun.allocators.Nullable(Allocator), - - /// Same as `.initBorrowed()`. This allocator cannot be used to allocate memory; a panic - /// will occur. - pub const borrowed = .initBorrowed(); - - /// Creates a `MaybeOwned` allocator that owns memory. - /// - /// Allocations are forwarded to a default-initialized `Allocator`. - pub fn init() Self { - return .initOwned(bun.memory.initDefault(Allocator)); - } - - /// Creates a `MaybeOwned` allocator that owns memory, and forwards to a specific - /// allocator. - /// - /// Allocations are forwarded to `parent_alloc`. - pub fn initOwned(parent_alloc: Allocator) Self { - return .initRaw(parent_alloc); - } - - /// Creates a `MaybeOwned` allocator that does not own any memory. This allocator cannot - /// be used to allocate new memory (a panic will occur), and its implementation of `free` - /// is a no-op. - pub fn initBorrowed() Self { - return .initRaw(null); - } - - pub fn deinit(self: *Self) void { - var maybe_parent = self.intoParent(); - if (maybe_parent) |*parent_alloc| { - bun.memory.deinit(parent_alloc); - } - } - - pub fn isOwned(self: Self) bool { - return self.rawParent() != null; - } - - pub fn allocator(self: Self) std.mem.Allocator { - const maybe_parent = self.rawParent(); - return if (maybe_parent) |parent_alloc| - bun.allocators.asStd(parent_alloc) - else - .{ .ptr = undefined, .vtable = &null_vtable }; - } - - const BorrowedParent = bun.allocators.Borrowed(Allocator); - - pub fn parent(self: Self) ?BorrowedParent { - const maybe_parent = self.rawParent(); - return if (maybe_parent) |parent_alloc| - bun.allocators.borrow(parent_alloc) - else - null; - } - - pub fn intoParent(self: *Self) ?Allocator { - defer self.* = undefined; - return self.rawParent(); - } - - /// Used by smart pointer types and allocator wrappers. See `bun.allocators.borrow`. - pub const Borrowed = MaybeOwned(BorrowedParent); - - pub fn borrow(self: Self) Borrowed { - return .{ ._parent = bun.allocators.initNullable(BorrowedParent, self.parent()) }; - } - - fn initRaw(parent_alloc: ?Allocator) Self { - return .{ ._parent = bun.allocators.initNullable(Allocator, parent_alloc) }; - } - - fn rawParent(self: Self) ?Allocator { - return bun.allocators.unpackNullable(Allocator, self._parent); - } - }; -} - -fn nullAlloc(ptr: *anyopaque, len: usize, alignment: Alignment, ret_addr: usize) ?[*]u8 { - _ = .{ ptr, len, alignment, ret_addr }; - std.debug.panic("cannot allocate with a borrowed `MaybeOwned` allocator", .{}); -} - -const null_vtable: std.mem.Allocator.VTable = .{ - .alloc = nullAlloc, - .resize = std.mem.Allocator.noResize, - .remap = std.mem.Allocator.noRemap, - .free = std.mem.Allocator.noFree, -}; - -const bun = @import("bun"); -const std = @import("std"); -const Alignment = std.mem.Alignment; diff --git a/src/bun_alloc/memory.zig b/src/bun_alloc/memory.zig deleted file mode 100644 index f1afe72b7134..000000000000 --- a/src/bun_alloc/memory.zig +++ /dev/null @@ -1,210 +0,0 @@ -//! Basic utilities for working with memory and objects. - -/// Allocates memory for a value of type `T` using the provided allocator, and initializes the -/// memory with `value`. -/// -/// If `allocator` is `bun.default_allocator`, this will internally use `bun.tryNew` to benefit from -/// the added assertions. -pub fn create(comptime T: type, allocator: std.mem.Allocator, value: T) bun.OOM!*T { - if ((comptime Environment.allow_assert) and isDefault(allocator)) { - return bun.tryNew(T, value); - } - const ptr = try allocator.create(T); - ptr.* = value; - return ptr; -} - -/// Frees memory previously allocated by `create`. -/// -/// The memory must have been allocated by the `create` function in this namespace, not -/// directly by `allocator.create`. -pub fn destroy(allocator: std.mem.Allocator, ptr: anytype) void { - if ((comptime Environment.allow_assert) and isDefault(allocator)) { - bun.destroy(ptr); - } else { - allocator.destroy(ptr); - } -} - -/// Default-initializes a value of type `T`. -/// -/// This method tries the following, in order: -/// -/// * `.initDefault()`, if a method with that name exists -/// * `.init()`, if a method with that name exists -/// * `.{}`, otherwise -pub fn initDefault(comptime T: type) T { - return if (comptime std.meta.hasFn(T, "initDefault")) - .initDefault() - else if (comptime std.meta.hasFn(T, "init")) - .init() - else - .{}; -} - -/// Returns true if `T` should not be required to have a `deinit` method. -/// -/// This method is primarily for external types where a `deinit` method can't be added. -/// For other types, prefer adding a `deinit` method or adding `pub const deinit = void;` if -/// possible. -fn exemptedFromDeinit(comptime T: type) bool { - return switch (T) { - std.mem.Allocator => true, - else => { - _ = T.deinit; // no deinit method? add one, set to void, or add an exemption - return false; - }, - }; -} - -fn deinitIsVoid(comptime T: type) bool { - return switch (@TypeOf(T.deinit)) { - type => T.deinit == void, - void => true, - else => false, - }; -} - -/// Calls `deinit` on `ptr_or_slice`, or on every element of `ptr_or_slice`, if the pointer points -/// to a struct or tagged union. -/// -/// This function first does the following: -/// -/// * If `ptr_or_slice` is a single-item pointer of type `*T`: -/// - If `T` is a struct or tagged union, calls `ptr_or_slice.deinit()` -/// - If `T` is an optional, checks if `ptr_or_slice` points to a non-null value, and if so, -/// calls `bun.memory.deinit` with a pointer to the payload. -/// * If `ptr_or_slice` is a slice, for each element of the slice, calls `bun.memory.deinit` with -/// a pointer to the element. -/// -/// Then, if `ptr_or_slice` is non-const, this function also sets all memory referenced by the -/// pointer to `undefined`. -/// -/// This method does not free `ptr_or_slice` itself. -pub fn deinit(ptr_or_slice: anytype) void { - const PtrType = @TypeOf(ptr_or_slice); - const ptr_info = @typeInfo(PtrType); - switch (comptime ptr_info.pointer.size) { - .slice => { - for (ptr_or_slice) |*elem| { - deinit(elem); - } - return; - }, - .one => {}, - else => @compileError("unsupported pointer type: " ++ @typeName(PtrType)), - } - - const Child = ptr_info.pointer.child; - const mutable = !ptr_info.pointer.is_const; - defer { - if (comptime mutable) { - ptr_or_slice.* = undefined; - } - } - - switch (comptime @typeInfo(Child)) { - .void, .bool, .int, .float, .pointer, .comptime_float, .comptime_int => return, - .undefined, .null, .error_set, .@"enum", .vector => return, - .array => { - for (ptr_or_slice) |*elem| { - deinit(elem); - } - return; - }, - .@"struct" => {}, - .optional => { - if (ptr_or_slice.*) |*payload| { - deinit(payload); - } - return; - }, - .error_union => { - if (ptr_or_slice.*) |*payload| { - deinit(payload); - } else |_| {} - return; - }, - .@"union" => |u| { - if (comptime u.tag_type == null) { - @compileError("cannot deinit an untagged union: " ++ @typeName(Child)); - } - }, - .type, .noreturn, .@"fn", .@"opaque", .frame, .@"anyframe", .enum_literal => { - @compileError("unsupported type for deinit: " ++ @typeName(Child)); - }, - } - - if (comptime !exemptedFromDeinit(Child) and !deinitIsVoid(Child)) { - ptr_or_slice.deinit(); - } -} - -/// Rebase a slice from one memory buffer to another buffer. -/// -/// Given a slice which points into a memory buffer with base `old_base`, return -/// a slice which points to the same offset in a new memory buffer with base -/// `new_base`, preserving the length of the slice. -/// -/// -/// ``` -/// const old_base = [6]u8{}; -/// assert(@ptrToInt(&old_base) == 0x32); -/// -/// 0x32 0x33 0x34 0x35 0x36 0x37 -/// old_base |????|????|????|????|????|????| -/// ^ -/// |<-- slice --->| -/// -/// const new_base = [6]u8{}; -/// assert(@ptrToInt(&new_base) == 0x74); -/// const output = rebaseSlice(slice, old_base, new_base) -/// -/// 0x74 0x75 0x76 0x77 0x78 0x79 -/// new_base |????|????|????|????|????|????| -/// ^ -/// |<-- output -->| -/// ``` -pub fn rebaseSlice(slice: []const u8, old_base: [*]const u8, new_base: [*]const u8) []const u8 { - const offset = @intFromPtr(slice.ptr) - @intFromPtr(old_base); - return new_base[offset..][0..slice.len]; -} - -/// Removes the sentinel from a sentinel-terminated slice or many-item pointer. The resulting -/// non-sentinel-terminated slice can be freed with `allocator.free`. -/// -/// `ptr` must be `[:x]T` or `[*:x]T`, or their const equivalents, and it must have been allocated -/// by `allocator`. -/// -/// Most allocators will perform this operation without allocating any memory, but unlike a simple -/// cast, this function will not cause issues with allocators that need to know the exact size of -/// the allocation to free it. -pub fn dropSentinel(ptr: anytype, allocator: std.mem.Allocator) blk: { - var info = @typeInfo(@TypeOf(ptr)); - info.pointer.size = .slice; - info.pointer.sentinel_ptr = null; - break :blk bun.OOM!@Type(info); -} { - const info = @typeInfo(@TypeOf(ptr)).pointer; - const Child = info.child; - if (comptime info.sentinel_ptr == null) { - @compileError("pointer must have sentinel"); - } - - const slice = switch (comptime info.size) { - .many => std.mem.span(ptr), - .slice => ptr, - else => @compileError("only slices and many-item pointers are supported"), - }; - - if (allocator.remap(@constCast(slice), slice.len)) |new| return new; - defer allocator.free(slice); - return allocator.dupe(Child, slice); -} - -const std = @import("std"); -const Allocator = std.mem.Allocator; - -const bun = @import("bun"); -const Environment = bun.Environment; -const isDefault = bun.allocators.isDefault; diff --git a/src/bun_core/Global.zig b/src/bun_core/Global.zig deleted file mode 100644 index f26c6c5d8194..000000000000 --- a/src/bun_core/Global.zig +++ /dev/null @@ -1,243 +0,0 @@ -const Global = @This(); - -/// Does not have the canary tag, because it is exposed in `Bun.version` -/// "1.0.0" or "1.0.0-debug" -pub const package_json_version = if (Environment.isDebug) - version_string ++ "-debug" -else - version_string; - -/// This is used for `bun` without any arguments, it `package_json_version` but with canary if it is a canary build. -/// like "1.0.0-canary.12" -pub const package_json_version_with_canary = if (Environment.isDebug) - version_string ++ "-debug" -else if (Environment.is_canary) - std.fmt.comptimePrint("{s}-canary.{d}", .{ version_string, Environment.canary_revision }) -else - version_string; - -/// The version and a short hash in parenthesis. -pub const package_json_version_with_sha = if (Environment.git_sha.len == 0) - package_json_version -else if (Environment.isDebug) - std.fmt.comptimePrint("{s} ({s})", .{ version_string, Environment.git_sha[0..@min(Environment.git_sha.len, 8)] }) -else if (Environment.is_canary) - std.fmt.comptimePrint("{s}-canary.{d} ({s})", .{ version_string, Environment.canary_revision, Environment.git_sha[0..@min(Environment.git_sha.len, 8)] }) -else - std.fmt.comptimePrint("{s} ({s})", .{ version_string, Environment.git_sha[0..@min(Environment.git_sha.len, 8)] }); - -/// What is printed by `bun --revision` -/// "1.0.0+abcdefghi" or "1.0.0-canary.12+abcdefghi" -pub const package_json_version_with_revision = if (Environment.git_sha.len == 0) - package_json_version -else if (Environment.isDebug) - std.fmt.comptimePrint(version_string ++ "-debug+{s}", .{Environment.git_sha_short}) -else if (Environment.is_canary) - std.fmt.comptimePrint(version_string ++ "-canary.{d}+{s}", .{ Environment.canary_revision, Environment.git_sha_short }) -else - std.fmt.comptimePrint(version_string ++ "+{s}", .{Environment.git_sha_short}); - -// Node-style platform string. Distinct from Environment.os.nameString() on -// Android: the kernel-level OS enum stays .linux (so syscall switches keep -// working), but user-facing strings — npm user-agent, process.platform — -// must be "android" so native-addon postinstalls don't fetch glibc binaries. -pub const os_name = if (Environment.isAndroid) "android" else Environment.os.nameString(); -pub const os_display = if (Environment.isAndroid) "Android" else Environment.os.displayString(); - -// Bun v1.0.0 (Linux x64 baseline) -// Bun v1.0.0-debug (Linux x64) -// Bun v1.0.0-canary.0+44e09bb7f (Linux x64) -pub const unhandled_error_bun_version_string = "Bun v" ++ - (if (Environment.is_canary) package_json_version_with_revision else package_json_version) ++ - " (" ++ os_display ++ " " ++ arch_name ++ - (if (Environment.baseline) " baseline)" else ")"); - -pub const arch_name = if (Environment.isX64) - "x64" -else if (Environment.isX86) - "x86" -else if (Environment.isAarch64) - "arm64" -else - "unknown"; - -pub inline fn getStartTime() i128 { - return bun.start_time; -} - -extern "kernel32" fn SetThreadDescription(thread: std.os.windows.HANDLE, name: [*:0]const u16) callconv(.winapi) std.os.windows.HRESULT; - -pub fn setThreadName(name: [:0]const u8) void { - if (Environment.isLinux) { - _ = std.posix.prctl(.SET_NAME, .{@intFromPtr(name.ptr)}) catch 0; - } else if (Environment.isMac) { - _ = std.c.pthread_setname_np(name); - } else if (Environment.isFreeBSD) { - std.c.pthread_set_name_np(std.c.pthread_self(), name); - } else if (Environment.isWindows) { - // TODO: use SetThreadDescription or NtSetInformationThread with 0x26 (ThreadNameInformation) - // without causing exit code 0xC0000409 (stack buffer overrun) in child process - } -} - -const ExitFn = *const fn () callconv(.c) void; - -var on_exit_callbacks = std.ArrayListUnmanaged(ExitFn){}; -export fn Bun__atexit(function: ExitFn) void { - if (std.mem.indexOfScalar(ExitFn, on_exit_callbacks.items, function) == null) { - on_exit_callbacks.append(bun.default_allocator, function) catch {}; - } -} - -pub fn addExitCallback(function: ExitFn) void { - Bun__atexit(function); -} - -pub fn runExitCallbacks() void { - for (on_exit_callbacks.items) |callback| { - callback(); - } - on_exit_callbacks.items.len = 0; -} - -var is_exiting = std.atomic.Value(bool).init(false); -export fn bun_is_exiting() c_int { - return @intFromBool(isExiting()); -} -pub fn isExiting() bool { - return is_exiting.load(.monotonic); -} - -/// Flushes stdout and stderr (in exit/quick_exit callback) and exits with the given code. -pub fn exit(code: u32) noreturn { - is_exiting.store(true, .monotonic); - _ = @atomicRmw(usize, &bun.analytics.Features.exited, .Add, 1, .monotonic); - - // If we are crashing, allow the crash handler to finish it's work. - bun.crash_handler.sleepForeverIfAnotherThreadIsCrashing(); - - if (Environment.isDebug) { - bun.assert(bun.debug_allocator_data.backing.?.deinit() == .ok); - bun.debug_allocator_data.backing = null; - } - - // Flush output before exiting to ensure all messages are visible - Output.flush(); - - switch (Environment.os) { - .mac => std.c.exit(@bitCast(code)), - .windows => { - Bun__onExit(); - std.os.windows.kernel32.ExitProcess(code); - }, - else => { - if (Environment.enable_asan) { - std.c.exit(@bitCast(code)); - std.c.abort(); // exit should be noreturn - } - bun.c.quick_exit(@bitCast(code)); - std.c.abort(); // quick_exit should be noreturn - }, - } -} - -pub fn raiseIgnoringPanicHandler(sig: bun.SignalCode) noreturn { - Output.flush(); - Output.Source.Stdio.restore(); - - // clear segfault handler - bun.crash_handler.resetSegfaultHandler(); - - // clear signal handler - if (bun.Environment.os != .windows) { - var sa: bun.sys.Sigaction = .{ - .handler = .{ .handler = std.posix.SIG.DFL }, - .mask = bun.sys.sigemptyset(), - .flags = std.posix.SA.RESETHAND, - }; - bun.sys.sigaction(@intFromEnum(sig), &sa, null); - } - - // kill self - _ = std.c.raise(@intFromEnum(sig)); - std.c.abort(); -} - -pub const AllocatorConfiguration = struct { - verbose: bool = false, - long_running: bool = false, -}; - -pub inline fn mimalloc_cleanup(force: bool) void { - if (comptime use_mimalloc) { - Mimalloc.mi_collect(force); - } -} -// Versions are now handled by build-generated header (bun_dependency_versions.h) - -// Enabling huge pages slows down bun by 8x or so -// Keeping this code for: -// 1. documentation that an attempt was made -// 2. if I want to configure allocator later -pub inline fn configureAllocator(_: AllocatorConfiguration) void {} - -pub fn notimpl() noreturn { - @branchHint(.cold); - Output.panic("Not implemented yet!!!!!", .{}); -} - -// Make sure we always print any leftover -pub fn crash() noreturn { - @branchHint(.cold); - Global.exit(1); -} - -pub const BunInfo = struct { - bun_version: string, - platform: analytics.GenerateHeader.GeneratePlatform.Platform, - - const analytics = bun.analytics; - const JSON = bun.json; - const JSAst = bun.ast; - pub fn generate(comptime Bundler: type, _: Bundler, allocator: std.mem.Allocator) !JSAst.Expr { - const info = BunInfo{ - .bun_version = Global.package_json_version, - .platform = analytics.GenerateHeader.GeneratePlatform.forOS(), - }; - - return try JSON.toAST(allocator, BunInfo, info); - } -}; - -pub const user_agent = "Bun/" ++ Global.package_json_version; -pub export const Bun__userAgent: [*:0]const u8 = Global.user_agent; - -comptime { - _ = Bun__userAgent; -} - -pub export fn Bun__onExit() void { - bun.jsc.Node.FSEvents.closeAndWait(); - - runExitCallbacks(); - Output.flush(); - std.mem.doNotOptimizeAway(&Bun__atexit); - - Output.Source.Stdio.restore(); -} - -comptime { - _ = Bun__onExit; -} - -const string = []const u8; - -const Output = @import("./output.zig"); -const std = @import("std"); - -const Environment = @import("./env.zig"); -const version_string = Environment.version_string; - -const bun = @import("bun"); -const Mimalloc = bun.mimalloc; -const use_mimalloc = bun.use_mimalloc; diff --git a/src/bun_core/Progress.zig b/src/bun_core/Progress.zig deleted file mode 100644 index 1536bacc47d7..000000000000 --- a/src/bun_core/Progress.zig +++ /dev/null @@ -1,467 +0,0 @@ -//! This is a snapshot of the Zig std.Progress API before it's rewrite in 0.13 -//! We use this API for the progress in Bun install and some other places. -//! -//! TODO: It would be worth considering using our own progress indicator for -//! Bun install, as this bar only shows the most recent action. -//! -//! https://github.com/ziglang/zig/blob/0.12.0/lib/std/Progress.zig -//! -//! This API is non-allocating, non-fallible, and thread-safe. -//! The tradeoff is that users of this API must provide the storage -//! for each `Progress.Node`. -//! -//! Initialize the struct directly, overriding these fields as desired: -//! * `refresh_rate_ms` -//! * `initial_delay_ms` - -const Progress = @This(); - -/// `null` if the current node (and its children) should -/// not print on update() -terminal: ?std.fs.File = undefined, - -/// Is this a windows API terminal (note: this is not the same as being run on windows -/// because other terminals exist like MSYS/git-bash) -is_windows_terminal: bool = false, - -/// Whether the terminal supports ANSI escape codes. -supports_ansi_escape_codes: bool = false, - -/// If the terminal is "dumb", don't print output. -/// This can be useful if you don't want to print all -/// the stages of code generation if there are a lot. -/// You should not use it if the user should see output -/// for example showing the user what tests run. -dont_print_on_dumb: bool = false, - -root: Node = undefined, - -/// Keeps track of how much time has passed since the beginning. -/// Used to compare with `initial_delay_ms` and `refresh_rate_ms`. -timer: ?std.time.Timer = null, - -/// When the previous refresh was written to the terminal. -/// Used to compare with `refresh_rate_ms`. -prev_refresh_timestamp: u64 = undefined, - -/// This buffer represents the maximum number of bytes written to the terminal -/// with each refresh. -output_buffer: [100]u8 = undefined, - -/// How many nanoseconds between writing updates to the terminal. -refresh_rate_ns: u64 = 50 * std.time.ns_per_ms, - -/// How many nanoseconds to keep the output hidden -initial_delay_ns: u64 = 500 * std.time.ns_per_ms, - -done: bool = true, - -/// Protects the `refresh` function, as well as `node.recently_updated_child`. -/// Without this, callsites would call `Node.end` and then free `Node` memory -/// while it was still being accessed by the `refresh` function. -update_mutex: bun.Mutex = .{}, - -/// Keeps track of how many columns in the terminal have been output, so that -/// we can move the cursor back later. -columns_written: usize = undefined, - -/// Represents one unit of progress. Each node can have children nodes, or -/// one can use integers with `update`. -pub const Node = struct { - context: *Progress, - parent: ?*Node, - name: []const u8, - unit: enum { none, files, bytes } = .none, - /// Must be handled atomically to be thread-safe. - recently_updated_child: ?*Node = null, - /// Must be handled atomically to be thread-safe. 0 means null. - unprotected_estimated_total_items: usize, - /// Must be handled atomically to be thread-safe. - unprotected_completed_items: usize, - - /// Create a new child progress node. Thread-safe. - /// Call `Node.end` when done. - /// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this - /// API to set `self.parent.recently_updated_child` with the return value. - /// Until that is fixed you probably want to call `activate` on the return value. - /// Passing 0 for `estimated_total_items` means unknown. - pub fn start(self: *Node, name: []const u8, estimated_total_items: usize) Node { - return Node{ - .context = self.context, - .parent = self, - .name = name, - .unprotected_estimated_total_items = estimated_total_items, - .unprotected_completed_items = 0, - }; - } - - /// This is the same as calling `start` and then `end` on the returned `Node`. Thread-safe. - pub fn completeOne(self: *Node) void { - if (self.parent) |parent| { - @atomicStore(?*Node, &parent.recently_updated_child, self, .release); - } - _ = @atomicRmw(usize, &self.unprotected_completed_items, .Add, 1, .monotonic); - self.context.maybeRefresh(); - } - - /// Finish a started `Node`. Thread-safe. - pub fn end(self: *Node) void { - self.context.maybeRefresh(); - if (self.parent) |parent| { - { - self.context.update_mutex.lock(); - defer self.context.update_mutex.unlock(); - _ = @cmpxchgStrong(?*Node, &parent.recently_updated_child, self, null, .monotonic, .monotonic); - } - parent.completeOne(); - } else { - self.context.update_mutex.lock(); - defer self.context.update_mutex.unlock(); - self.context.done = true; - self.context.refreshWithHeldLock(); - } - } - - /// Tell the parent node that this node is actively being worked on. Thread-safe. - pub fn activate(self: *Node) void { - if (self.parent) |parent| { - @atomicStore(?*Node, &parent.recently_updated_child, self, .release); - self.context.maybeRefresh(); - } - } - - /// Thread-safe. - pub fn setName(self: *Node, name: []const u8) void { - const progress = self.context; - progress.update_mutex.lock(); - defer progress.update_mutex.unlock(); - self.name = name; - if (self.parent) |parent| { - @atomicStore(?*Node, &parent.recently_updated_child, self, .release); - if (parent.parent) |grand_parent| { - @atomicStore(?*Node, &grand_parent.recently_updated_child, parent, .release); - } - if (progress.timer) |*timer| progress.maybeRefreshWithHeldLock(timer); - } - } - - /// Thread-safe. - pub fn setUnit(self: *Node, unit: []const u8) void { - const progress = self.context; - progress.update_mutex.lock(); - defer progress.update_mutex.unlock(); - self.unit = unit; - if (self.parent) |parent| { - @atomicStore(?*Node, &parent.recently_updated_child, self, .release); - if (parent.parent) |grand_parent| { - @atomicStore(?*Node, &grand_parent.recently_updated_child, parent, .release); - } - if (progress.timer) |*timer| progress.maybeRefreshWithHeldLock(timer); - } - } - - /// Thread-safe. 0 means unknown. - pub fn setEstimatedTotalItems(self: *Node, count: usize) void { - @atomicStore(usize, &self.unprotected_estimated_total_items, count, .monotonic); - } - - /// Thread-safe. - pub fn setCompletedItems(self: *Node, completed_items: usize) void { - @atomicStore(usize, &self.unprotected_completed_items, completed_items, .monotonic); - } -}; - -/// Create a new progress node. -/// Call `Node.end` when done. -/// TODO solve https://github.com/ziglang/zig/issues/2765 and then change this -/// API to return Progress rather than accept it as a parameter. -/// `estimated_total_items` value of 0 means unknown. -pub fn start(self: *Progress, name: []const u8, estimated_total_items: usize) *Node { - const stderr = std.fs.File.stderr(); - self.terminal = null; - if (stderr.supportsAnsiEscapeCodes()) { - self.terminal = stderr; - self.supports_ansi_escape_codes = true; - } else if (builtin.os.tag == .windows and stderr.isTty()) { - self.is_windows_terminal = true; - self.terminal = stderr; - } else if (builtin.os.tag != .windows) { - // we are in a "dumb" terminal like in acme or writing to a file - self.terminal = stderr; - } - self.root = Node{ - .context = self, - .parent = null, - .name = name, - .unprotected_estimated_total_items = estimated_total_items, - .unprotected_completed_items = 0, - }; - self.columns_written = 0; - self.prev_refresh_timestamp = 0; - self.timer = std.time.Timer.start() catch null; - self.done = false; - return &self.root; -} - -/// Updates the terminal if enough time has passed since last update. Thread-safe. -pub fn maybeRefresh(self: *Progress) void { - if (self.timer) |*timer| { - if (!self.update_mutex.tryLock()) return; - defer self.update_mutex.unlock(); - maybeRefreshWithHeldLock(self, timer); - } -} - -fn maybeRefreshWithHeldLock(self: *Progress, timer: *std.time.Timer) void { - const now = timer.read(); - if (now < self.initial_delay_ns) return; - // TODO I have observed this to happen sometimes. I think we need to follow Rust's - // lead and guarantee monotonically increasing times in the std lib itself. - if (now < self.prev_refresh_timestamp) return; - if (now - self.prev_refresh_timestamp < self.refresh_rate_ns) return; - return self.refreshWithHeldLock(); -} - -/// Updates the terminal and resets `self.next_refresh_timestamp`. Thread-safe. -pub fn refresh(self: *Progress) void { - if (!self.update_mutex.tryLock()) return; - defer self.update_mutex.unlock(); - - return self.refreshWithHeldLock(); -} - -fn clearWithHeldLock(p: *Progress, end_ptr: *usize) void { - const file = p.terminal orelse return; - var end = end_ptr.*; - if (p.columns_written > 0) { - // restore the cursor position by moving the cursor - // `columns_written` cells to the left, then clear the rest of the - // line - if (p.supports_ansi_escape_codes) { - end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[{d}D", .{p.columns_written}) catch unreachable).len; - end += (std.fmt.bufPrint(p.output_buffer[end..], "\x1b[0K", .{}) catch unreachable).len; - } else if (builtin.os.tag == .windows) winapi: { - assert(p.is_windows_terminal); - - var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined; - if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) != windows.TRUE) { - // stop trying to write to this file - p.terminal = null; - break :winapi; - } - - var cursor_pos = windows.COORD{ - .X = info.dwCursorPosition.X - @as(windows.SHORT, @intCast(p.columns_written)), - .Y = info.dwCursorPosition.Y, - }; - - if (cursor_pos.X < 0) - cursor_pos.X = 0; - - const fill_chars = @as(windows.DWORD, @intCast(info.dwSize.X - cursor_pos.X)); - - var written: windows.DWORD = undefined; - if (windows.kernel32.FillConsoleOutputAttribute( - file.handle, - info.wAttributes, - fill_chars, - cursor_pos, - &written, - ) != windows.TRUE) { - // stop trying to write to this file - p.terminal = null; - break :winapi; - } - if (windows.kernel32.FillConsoleOutputCharacterW( - file.handle, - ' ', - fill_chars, - cursor_pos, - &written, - ) != windows.TRUE) { - // stop trying to write to this file - p.terminal = null; - break :winapi; - } - if (windows.kernel32.SetConsoleCursorPosition(file.handle, cursor_pos) != windows.TRUE) { - // stop trying to write to this file - p.terminal = null; - break :winapi; - } - } else { - // we are in a "dumb" terminal like in acme or writing to a file - p.output_buffer[end] = '\n'; - end += 1; - } - - p.columns_written = 0; - } - end_ptr.* = end; -} - -fn refreshWithHeldLock(self: *Progress) void { - const is_dumb = !self.supports_ansi_escape_codes and !self.is_windows_terminal; - if (is_dumb and self.dont_print_on_dumb) return; - - const file = self.terminal orelse return; - - var end: usize = 0; - clearWithHeldLock(self, &end); - - if (!self.done) { - var need_ellipse = false; - var maybe_node: ?*Node = &self.root; - while (maybe_node) |node| { - if (need_ellipse) { - self.bufWrite(&end, "... ", .{}); - } - need_ellipse = false; - const eti = @atomicLoad(usize, &node.unprotected_estimated_total_items, .monotonic); - const completed_items = @atomicLoad(usize, &node.unprotected_completed_items, .monotonic); - const current_item = completed_items + 1; - if (node.name.len != 0 or eti > 0) { - if (node.name.len != 0) { - self.bufWrite(&end, "{s}", .{node.name}); - need_ellipse = true; - } - if (eti > 0) { - if (need_ellipse) self.bufWrite(&end, " ", .{}); - switch (node.unit) { - .none => self.bufWrite(&end, "[{d}/{d}] ", .{ current_item, eti }), - .files => self.bufWrite(&end, "[{d}/{d} files] ", .{ current_item, eti }), - .bytes => self.bufWrite(&end, "[{Bi:.2}/{Bi:.2}] ", .{ current_item, eti }), - } - need_ellipse = false; - } else if (completed_items != 0) { - if (need_ellipse) self.bufWrite(&end, " ", .{}); - switch (node.unit) { - .none => self.bufWrite(&end, "[{d}] ", .{current_item}), - .files => self.bufWrite(&end, "[{d} files] ", .{current_item}), - .bytes => self.bufWrite(&end, "[{Bi:.2}] ", .{current_item}), - } - need_ellipse = false; - } - } - maybe_node = @atomicLoad(?*Node, &node.recently_updated_child, .acquire); - } - if (need_ellipse) { - self.bufWrite(&end, "... ", .{}); - } - } - - _ = file.write(self.output_buffer[0..end]) catch { - // stop trying to write to this file - self.terminal = null; - }; - if (self.timer) |*timer| { - self.prev_refresh_timestamp = timer.read(); - } -} - -pub fn log(self: *Progress, comptime format: []const u8, args: anytype) void { - const file = self.terminal orelse { - (std.debug).print(format, args); - return; - }; - var file_writer = file.writerStreaming(&.{}); - const writer = &file_writer.interface; - self.refresh(); - writer.print(format, args) catch { - self.terminal = null; - return; - }; - self.columns_written = 0; -} - -/// Allows the caller to freely write to stderr until unlock_stderr() is called. -/// During the lock, the progress information is cleared from the terminal. -pub fn lock_stderr(p: *Progress) void { - p.update_mutex.lock(); - if (p.terminal) |file| { - var end: usize = 0; - clearWithHeldLock(p, &end); - _ = file.write(p.output_buffer[0..end]) catch { - // stop trying to write to this file - p.terminal = null; - }; - } - std.debug.getStderrMutex().lock(); -} - -pub fn unlock_stderr(p: *Progress) void { - std.debug.getStderrMutex().unlock(); - p.update_mutex.unlock(); -} - -fn bufWrite(self: *Progress, end: *usize, comptime format: []const u8, args: anytype) void { - if (std.fmt.bufPrint(self.output_buffer[end.*..], format, args)) |written| { - const amt = written.len; - end.* += amt; - self.columns_written += amt; - } else |err| switch (err) { - error.NoSpaceLeft => { - self.columns_written += self.output_buffer.len - end.*; - end.* = self.output_buffer.len; - const suffix = "... "; - @memcpy(self.output_buffer[self.output_buffer.len - suffix.len ..], suffix); - }, - } -} - -test "basic functionality" { - var disable = true; - _ = &disable; - if (disable) { - // This test is disabled because it uses time.sleep() and is therefore slow. It also - // prints bogus progress data to stderr. - return error.SkipZigTest; - } - var progress = Progress{}; - const root_node = progress.start("", 100); - defer root_node.end(); - - const speed_factor = std.time.ns_per_ms; - - const sub_task_names = [_][]const u8{ - "reticulating splines", - "adjusting shoes", - "climbing towers", - "pouring juice", - }; - var next_sub_task: usize = 0; - - var i: usize = 0; - while (i < 100) : (i += 1) { - var node = root_node.start(sub_task_names[next_sub_task], 5); - node.activate(); - next_sub_task = (next_sub_task + 1) % sub_task_names.len; - - node.completeOne(); - std.Thread.sleep(5 * speed_factor); - node.completeOne(); - node.completeOne(); - std.Thread.sleep(5 * speed_factor); - node.completeOne(); - node.completeOne(); - std.Thread.sleep(5 * speed_factor); - - node.end(); - - std.Thread.sleep(5 * speed_factor); - } - { - var node = root_node.start("this is a really long name designed to activate the truncation code. let's find out if it works", 0); - node.activate(); - std.Thread.sleep(10 * speed_factor); - progress.refresh(); - std.Thread.sleep(10 * speed_factor); - node.end(); - } -} - -const builtin = @import("builtin"); -const std = @import("std"); -const windows = std.os.windows; - -const bun = @import("bun"); -const assert = bun.assert; diff --git a/src/bun_core/bounded_array.zig b/src/bun_core/bounded_array.zig deleted file mode 100644 index a7c3209bbd2b..000000000000 --- a/src/bun_core/bounded_array.zig +++ /dev/null @@ -1,308 +0,0 @@ -/// Removed from the Zig standard library in https://github.com/ziglang/zig/pull/24699/ -/// -/// Modifications: -/// - `len` is a field of integer-size instead of usize. This reduces memory usage. -/// -/// A structure with an array and a length, that can be used as a slice. -/// -/// Useful to pass around small arrays whose exact size is only known at -/// runtime, but whose maximum size is known at comptime, without requiring -/// an `Allocator`. -/// -/// ```zig -/// var actual_size = 32; -/// var a = try BoundedArray(u8, 64).init(actual_size); -/// var slice = a.slice(); // a slice of the 64-byte array -/// var a_clone = a; // creates a copy - the structure doesn't use any internal pointers -/// ``` -pub fn BoundedArray(comptime T: type, comptime buffer_capacity: usize) type { - return BoundedArrayAligned(T, .fromByteUnits(@alignOf(T)), buffer_capacity); -} - -/// A structure with an array, length and alignment, that can be used as a -/// slice. -/// -/// Useful to pass around small explicitly-aligned arrays whose exact size is -/// only known at runtime, but whose maximum size is known at comptime, without -/// requiring an `Allocator`. -/// ```zig -// var a = try BoundedArrayAligned(u8, 16, 2).init(0); -// try a.append(255); -// try a.append(255); -// const b = @ptrCast(*const [1]u16, a.constSlice().ptr); -// try testing.expectEqual(@as(u16, 65535), b[0]); -/// ``` -pub fn BoundedArrayAligned( - comptime T: type, - comptime alignment: Alignment, - comptime buffer_capacity: usize, -) type { - return struct { - const Self = @This(); - buffer: [buffer_capacity]T align(alignment.toByteUnits()) = undefined, - len: Length = 0, - - const Length = std.math.ByteAlignedInt(std.math.IntFittingRange(0, buffer_capacity)); - - pub const Buffer = @FieldType(Self, "buffer"); - - /// Set the actual length of the slice. - /// Returns error.Overflow if it exceeds the length of the backing array. - pub fn init(len: usize) error{Overflow}!Self { - if (len > buffer_capacity) return error.Overflow; - return Self{ .len = @intCast(len) }; - } - - /// View the internal array as a slice whose size was previously set. - pub fn slice(self: anytype) switch (@TypeOf(&self.buffer)) { - *align(alignment.toByteUnits()) [buffer_capacity]T => []align(alignment.toByteUnits()) T, - *align(alignment.toByteUnits()) const [buffer_capacity]T => []align(alignment.toByteUnits()) const T, - else => unreachable, - } { - return self.buffer[0..self.len]; - } - - /// View the internal array as a constant slice whose size was previously set. - pub fn constSlice(self: *const Self) []align(alignment.toByteUnits()) const T { - return self.slice(); - } - - /// Adjust the slice's length to `len`. - /// Does not initialize added items if any. - pub fn resize(self: *Self, len: usize) error{Overflow}!void { - if (len > buffer_capacity) return error.Overflow; - self.len = len; - } - - /// Remove all elements from the slice. - pub fn clear(self: *Self) void { - self.len = 0; - } - - /// Copy the content of an existing slice. - pub fn fromSlice(m: []const T) error{Overflow}!Self { - var list = try init(m.len); - @memcpy(list.slice(), m); - return list; - } - - /// Return the element at index `i` of the slice. - pub fn get(self: Self, i: usize) T { - return self.constSlice()[i]; - } - - /// Set the value of the element at index `i` of the slice. - pub fn set(self: *Self, i: usize, item: T) void { - self.slice()[i] = item; - } - - /// Return the maximum length of a slice. - pub fn capacity(self: Self) usize { - return self.buffer.len; - } - - /// Check that the slice can hold at least `additional_count` items. - pub fn ensureUnusedCapacity(self: Self, additional_count: usize) error{Overflow}!void { - if (self.len + additional_count > buffer_capacity) { - return error.Overflow; - } - } - - /// Increase length by 1, returning a pointer to the new item. - pub fn addOne(self: *Self) error{Overflow}!*T { - try self.ensureUnusedCapacity(1); - return self.addOneAssumeCapacity(); - } - - /// Increase length by 1, returning pointer to the new item. - /// Asserts that there is space for the new item. - pub fn addOneAssumeCapacity(self: *Self) *T { - assert(self.len < buffer_capacity); - self.len += 1; - return &self.slice()[self.len - 1]; - } - - /// Resize the slice, adding `n` new elements, which have `undefined` values. - /// The return value is a pointer to the array of uninitialized elements. - pub fn addManyAsArray(self: *Self, comptime n: usize) error{Overflow}!*align(alignment.toByteUnits()) [n]T { - const prev_len = self.len; - try self.resize(@as(usize, self.len) + n); - return self.slice()[prev_len..][0..n]; - } - - /// Resize the slice, adding `n` new elements, which have `undefined` values. - /// The return value is a slice pointing to the uninitialized elements. - pub fn addManyAsSlice(self: *Self, n: usize) error{Overflow}![]align(alignment.toByteUnits()) T { - const prev_len = self.len; - try self.resize(self.len + n); - return self.slice()[prev_len..][0..n]; - } - - /// Remove and return the last element from the slice, or return `null` if the slice is empty. - pub fn pop(self: *Self) ?T { - if (self.len == 0) return null; - const item = self.get(self.len - 1); - self.len -= 1; - return item; - } - - /// Return a slice of only the extra capacity after items. - /// This can be useful for writing directly into it. - /// Note that such an operation must be followed up with a - /// call to `resize()` - pub fn unusedCapacitySlice(self: *Self) []align(alignment.toByteUnits()) T { - return self.buffer[self.len..]; - } - - /// Insert `item` at index `i` by moving `slice[n .. slice.len]` to make room. - /// This operation is O(N). - pub fn insert( - self: *Self, - i: usize, - item: T, - ) error{Overflow}!void { - if (i > self.len) { - return error.Overflow; - } - _ = try self.addOne(); - var s = self.slice(); - mem.copyBackwards(T, s[i + 1 .. s.len], s[i .. s.len - 1]); - self.buffer[i] = item; - } - - /// Insert slice `items` at index `i` by moving `slice[i .. slice.len]` to make room. - /// This operation is O(N). - pub fn insertSlice(self: *Self, i: usize, items: []const T) error{Overflow}!void { - try self.ensureUnusedCapacity(items.len); - self.len += @intCast(items.len); - mem.copyBackwards(T, self.slice()[i + items.len .. self.len], self.constSlice()[i .. self.len - items.len]); - @memcpy(self.slice()[i..][0..items.len], items); - } - - /// Replace range of elements `slice[start..][0..len]` with `new_items`. - /// Grows slice if `len < new_items.len`. - /// Shrinks slice if `len > new_items.len`. - pub fn replaceRange( - self: *Self, - start: usize, - len: usize, - new_items: []const T, - ) error{Overflow}!void { - const after_range = start + len; - var range = self.slice()[start..after_range]; - - if (range.len == new_items.len) { - @memcpy(range[0..new_items.len], new_items); - } else if (range.len < new_items.len) { - const first = new_items[0..range.len]; - const rest = new_items[range.len..]; - @memcpy(range[0..first.len], first); - try self.insertSlice(after_range, rest); - } else { - @memcpy(range[0..new_items.len], new_items); - const after_subrange = start + new_items.len; - for (self.constSlice()[after_range..], 0..) |item, i| { - self.slice()[after_subrange..][i] = item; - } - self.len = @intCast(@as(usize, self.len) - @as(usize, len) - @as(usize, new_items.len)); - } - } - - /// Extend the slice by 1 element. - pub fn append(self: *Self, item: T) error{Overflow}!void { - const new_item_ptr = try self.addOne(); - new_item_ptr.* = item; - } - - /// Extend the slice by 1 element, asserting the capacity is already - /// enough to store the new item. - pub fn appendAssumeCapacity(self: *Self, item: T) void { - const new_item_ptr = self.addOneAssumeCapacity(); - new_item_ptr.* = item; - } - - /// Remove the element at index `i`, shift elements after index - /// `i` forward, and return the removed element. - /// Asserts the slice has at least one item. - /// This operation is O(N). - pub fn orderedRemove(self: *Self, i: usize) T { - const newlen = self.len - 1; - if (newlen == i) return self.pop().?; - const old_item = self.get(i); - for (self.slice()[i..newlen], 0..) |*b, j| b.* = self.get(i + 1 + j); - self.set(newlen, undefined); - self.len = newlen; - return old_item; - } - - /// Remove the element at the specified index and return it. - /// The empty slot is filled from the end of the slice. - /// This operation is O(1). - pub fn swapRemove(self: *Self, i: usize) T { - if (self.len - 1 == i) return self.pop().?; - const old_item = self.get(i); - self.set(i, self.pop().?); - return old_item; - } - - /// Append the slice of items to the slice. - pub fn appendSlice(self: *Self, items: []const T) error{Overflow}!void { - try self.ensureUnusedCapacity(items.len); - self.appendSliceAssumeCapacity(items); - } - - /// Append the slice of items to the slice, asserting the capacity is already - /// enough to store the new items. - pub fn appendSliceAssumeCapacity(self: *Self, items: []const T) void { - const old_len = self.len; - const new_len: usize = old_len + @as(usize, items.len); - self.len = @intCast(new_len); - @memcpy(self.slice()[old_len..][0..items.len], items); - } - - /// Append a value to the slice `n` times. - /// Allocates more memory as necessary. - pub fn appendNTimes(self: *Self, value: T, n: usize) error{Overflow}!void { - const old_len = self.len; - try self.resize(old_len + n); - @memset(self.slice()[old_len..self.len], value); - } - - /// Append a value to the slice `n` times. - /// Asserts the capacity is enough. - pub fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { - const old_len: usize = self.len; - const new_len: usize = old_len + @as(usize, n); - self.len = @intCast(new_len); - assert(self.len <= buffer_capacity); - @memset(self.slice()[old_len..self.len], value); - } - - pub const Writer = if (T != u8) - @compileError("The Writer interface is only defined for BoundedArray(u8, ...) " ++ - "but the given type is BoundedArray(" ++ @typeName(T) ++ ", ...)") - else - std.io.GenericWriter(*Self, error{Overflow}, appendWrite); - - /// Initializes a writer which will write into the array. - pub fn writer(self: *Self) Writer { - return .{ .context = self }; - } - - /// Same as `appendSlice` except it returns the number of bytes written, which is always the same - /// as `m.len`. The purpose of this function existing is to match `std.io.GenericWriter` API. - fn appendWrite(self: *Self, m: []const u8) error{Overflow}!usize { - try self.appendSlice(m); - return m.len; - } - }; -} - -const bun = @import("bun"); -const assert = bun.assert; - -const std = @import("std"); -const testing = std.testing; - -const mem = std.mem; -const Alignment = std.mem.Alignment; diff --git a/src/bun_core/comptime_string_map.rs b/src/bun_core/comptime_string_map.rs index 774bc5dcbbc0..f918e373683e 100644 --- a/src/bun_core/comptime_string_map.rs +++ b/src/bun_core/comptime_string_map.rs @@ -1,6 +1,6 @@ //! Static string→value maps with length-dispatched lookups. //! -//! Rust port of `src/collections/comptime_string_map.zig`. Declared via +//! Rust port of Zig's `ComptimeStringMap`. Declared via //! [`comptime_string_map!`] / [`comptime_string_set!`]; lookups compile to a //! `match key.len()` jump table plus constant-length byte compares (word-sized //! loads against immediates) — no hashing at runtime. diff --git a/src/bun_core/deprecated.zig b/src/bun_core/deprecated.zig deleted file mode 100644 index e41eec21c286..000000000000 --- a/src/bun_core/deprecated.zig +++ /dev/null @@ -1,649 +0,0 @@ -pub fn BufferedReader(comptime buffer_size: usize, comptime ReaderType: type) type { - return struct { - unbuffered_reader: ReaderType, - buf: [buffer_size]u8, - start: usize = 0, - end: usize = 0, - - pub const Error = ReaderType.Error; - pub const Reader = std.Io.GenericReader(*Self, Error, read); - - const Self = @This(); - - pub fn read(self: *Self, dest: []u8) Error!usize { - // First try reading from the already buffered data onto the destination. - const current = self.buf[self.start..self.end]; - if (current.len != 0) { - const to_transfer = @min(current.len, dest.len); - @memcpy(dest[0..to_transfer], current[0..to_transfer]); - self.start += to_transfer; - return to_transfer; - } - - // If dest is large, read from the unbuffered reader directly into the destination. - if (dest.len >= buffer_size) { - return self.unbuffered_reader.read(dest); - } - - // If dest is small, read from the unbuffered reader into our own internal buffer, - // and then transfer to destination. - self.end = try self.unbuffered_reader.read(&self.buf); - const to_transfer = @min(self.end, dest.len); - @memcpy(dest[0..to_transfer], self.buf[0..to_transfer]); - self.start = to_transfer; - return to_transfer; - } - - pub fn reader(self: *Self) Reader { - return .{ .context = self }; - } - }; -} - -pub fn bufferedReader(reader: anytype) BufferedReader(4096, @TypeOf(reader)) { - return .{ .unbuffered_reader = reader, .buf = undefined }; -} - -pub fn bufferedReaderSize(comptime size: usize, reader: anytype) BufferedReader(size, @TypeOf(reader)) { - return .{ .unbuffered_reader = reader, .buf = undefined }; -} - -/// A singly-linked list is headed by a single forward pointer. The elements -/// are singly-linked for minimum space and pointer manipulation overhead at -/// the expense of O(n) removal for arbitrary elements. New elements can be -/// added to the list after an existing element or at the head of the list. -/// A singly-linked list may only be traversed in the forward direction. -/// Singly-linked lists are ideal for applications with large datasets and -/// few or no removals or for implementing a LIFO queue. -pub fn SinglyLinkedList(comptime T: type) type { - return struct { - const Self = @This(); - - /// Node inside the linked list wrapping the actual data. - pub const Node = struct { - next: ?*Node = null, - data: T, - - pub const Data = T; - - /// Insert a new node after the current one. - /// - /// Arguments: - /// new_node: Pointer to the new node to insert. - pub fn insertAfter(node: *Node, new_node: *Node) void { - new_node.next = node.next; - node.next = new_node; - } - - /// Remove a node from the list. - /// - /// Arguments: - /// node: Pointer to the node to be removed. - /// Returns: - /// node removed - pub fn removeNext(node: *Node) ?*Node { - const next_node = node.next orelse return null; - node.next = next_node.next; - return next_node; - } - - /// Iterate over the singly-linked list from this node, until the final node is found. - /// This operation is O(N). - pub fn findLast(node: *Node) *Node { - var it = node; - while (true) { - it = it.next orelse return it; - } - } - - /// Iterate over each next node, returning the count of all nodes except the starting one. - /// This operation is O(N). - pub fn countChildren(node: *const Node) usize { - var count: usize = 0; - var it: ?*const Node = node.next; - while (it) |n| : (it = n.next) { - count += 1; - } - return count; - } - - /// Reverse the list starting from this node in-place. - /// This operation is O(N). - pub fn reverse(indirect: *?*Node) void { - if (indirect.* == null) { - return; - } - var current: *Node = indirect.*.?; - while (current.next) |next| { - current.next = next.next; - next.next = indirect.*; - indirect.* = next; - } - } - }; - - first: ?*Node = null, - - /// Insert a new node at the head. - /// - /// Arguments: - /// new_node: Pointer to the new node to insert. - pub fn prepend(list: *Self, new_node: *Node) void { - new_node.next = list.first; - list.first = new_node; - } - - /// Remove a node from the list. - /// - /// Arguments: - /// node: Pointer to the node to be removed. - pub fn remove(list: *Self, node: *Node) void { - if (list.first == node) { - list.first = node.next; - } else { - var current_elm = list.first.?; - while (current_elm.next != node) { - current_elm = current_elm.next.?; - } - current_elm.next = node.next; - } - } - - /// Remove and return the first node in the list. - /// - /// Returns: - /// A pointer to the first node in the list. - pub fn popFirst(list: *Self) ?*Node { - const first = list.first orelse return null; - list.first = first.next; - return first; - } - - /// Iterate over all nodes, returning the count. - /// This operation is O(N). - pub fn len(list: Self) usize { - if (list.first) |n| { - return 1 + n.countChildren(); - } else { - return 0; - } - } - }; -} - -test "basic SinglyLinkedList test" { - const L = SinglyLinkedList(u32); - var list = L{}; - - try testing.expect(list.len() == 0); - - var one = L.Node{ .data = 1 }; - var two = L.Node{ .data = 2 }; - var three = L.Node{ .data = 3 }; - var four = L.Node{ .data = 4 }; - var five = L.Node{ .data = 5 }; - - list.prepend(&two); // {2} - two.insertAfter(&five); // {2, 5} - list.prepend(&one); // {1, 2, 5} - two.insertAfter(&three); // {1, 2, 3, 5} - three.insertAfter(&four); // {1, 2, 3, 4, 5} - - try testing.expect(list.len() == 5); - - // Traverse forwards. - { - var it = list.first; - var index: u32 = 1; - while (it) |node| : (it = node.next) { - try testing.expect(node.data == index); - index += 1; - } - } - - _ = list.popFirst(); // {2, 3, 4, 5} - _ = list.remove(&five); // {2, 3, 4} - _ = two.removeNext(); // {2, 4} - - try testing.expect(list.first.?.data == 2); - try testing.expect(list.first.?.next.?.data == 4); - try testing.expect(list.first.?.next.?.next == null); - - L.Node.reverse(&list.first); - - try testing.expect(list.first.?.data == 4); - try testing.expect(list.first.?.next.?.data == 2); - try testing.expect(list.first.?.next.?.next == null); -} - -/// A doubly-linked list has a pair of pointers to both the head and -/// tail of the list. List elements have pointers to both the previous -/// and next elements in the sequence. The list can be traversed both -/// forward and backward. Some operations that take linear O(n) time -/// with a singly-linked list can be done without traversal in constant -/// O(1) time with a doubly-linked list: -/// -/// - Removing an element. -/// - Inserting a new element before an existing element. -/// - Pushing or popping an element from the end of the list. -pub fn DoublyLinkedList(comptime T: type) type { - return struct { - const Self = @This(); - - /// Node inside the linked list wrapping the actual data. - pub const Node = struct { - prev: ?*Node = null, - next: ?*Node = null, - data: T, - }; - - first: ?*Node = null, - last: ?*Node = null, - len: usize = 0, - - /// Insert a new node after an existing one. - /// - /// Arguments: - /// node: Pointer to a node in the list. - /// new_node: Pointer to the new node to insert. - pub fn insertAfter(list: *Self, node: *Node, new_node: *Node) void { - new_node.prev = node; - if (node.next) |next_node| { - // Intermediate node. - new_node.next = next_node; - next_node.prev = new_node; - } else { - // Last element of the list. - new_node.next = null; - list.last = new_node; - } - node.next = new_node; - - list.len += 1; - } - - /// Insert a new node before an existing one. - /// - /// Arguments: - /// node: Pointer to a node in the list. - /// new_node: Pointer to the new node to insert. - pub fn insertBefore(list: *Self, node: *Node, new_node: *Node) void { - new_node.next = node; - if (node.prev) |prev_node| { - // Intermediate node. - new_node.prev = prev_node; - prev_node.next = new_node; - } else { - // First element of the list. - new_node.prev = null; - list.first = new_node; - } - node.prev = new_node; - - list.len += 1; - } - - /// Concatenate list2 onto the end of list1, removing all entries from the former. - /// - /// Arguments: - /// list1: the list to concatenate onto - /// list2: the list to be concatenated - pub fn concatByMoving(list1: *Self, list2: *Self) void { - const l2_first = list2.first orelse return; - if (list1.last) |l1_last| { - l1_last.next = list2.first; - l2_first.prev = list1.last; - list1.len += list2.len; - } else { - // list1 was empty - list1.first = list2.first; - list1.len = list2.len; - } - list1.last = list2.last; - list2.first = null; - list2.last = null; - list2.len = 0; - } - - /// Insert a new node at the end of the list. - /// - /// Arguments: - /// new_node: Pointer to the new node to insert. - pub fn append(list: *Self, new_node: *Node) void { - if (list.last) |last| { - // Insert after last. - list.insertAfter(last, new_node); - } else { - // Empty list. - list.prepend(new_node); - } - } - - /// Insert a new node at the beginning of the list. - /// - /// Arguments: - /// new_node: Pointer to the new node to insert. - pub fn prepend(list: *Self, new_node: *Node) void { - if (list.first) |first| { - // Insert before first. - list.insertBefore(first, new_node); - } else { - // Empty list. - list.first = new_node; - list.last = new_node; - new_node.prev = null; - new_node.next = null; - - list.len = 1; - } - } - - /// Remove a node from the list. - /// - /// Arguments: - /// node: Pointer to the node to be removed. - pub fn remove(list: *Self, node: *Node) void { - if (node.prev) |prev_node| { - // Intermediate node. - prev_node.next = node.next; - } else { - // First element of the list. - list.first = node.next; - } - - if (node.next) |next_node| { - // Intermediate node. - next_node.prev = node.prev; - } else { - // Last element of the list. - list.last = node.prev; - } - - list.len -= 1; - assert(list.len == 0 or (list.first != null and list.last != null)); - } - - /// Remove and return the last node in the list. - /// - /// Returns: - /// A pointer to the last node in the list. - pub fn pop(list: *Self) ?*Node { - const last = list.last orelse return null; - list.remove(last); - return last; - } - - /// Remove and return the first node in the list. - /// - /// Returns: - /// A pointer to the first node in the list. - pub fn popFirst(list: *Self) ?*Node { - const first = list.first orelse return null; - list.remove(first); - return first; - } - }; -} - -test "basic DoublyLinkedList test" { - const L = DoublyLinkedList(u32); - var list = L{}; - - var one = L.Node{ .data = 1 }; - var two = L.Node{ .data = 2 }; - var three = L.Node{ .data = 3 }; - var four = L.Node{ .data = 4 }; - var five = L.Node{ .data = 5 }; - - list.append(&two); // {2} - list.append(&five); // {2, 5} - list.prepend(&one); // {1, 2, 5} - list.insertBefore(&five, &four); // {1, 2, 4, 5} - list.insertAfter(&two, &three); // {1, 2, 3, 4, 5} - - // Traverse forwards. - { - var it = list.first; - var index: u32 = 1; - while (it) |node| : (it = node.next) { - try testing.expect(node.data == index); - index += 1; - } - } - - // Traverse backwards. - { - var it = list.last; - var index: u32 = 1; - while (it) |node| : (it = node.prev) { - try testing.expect(node.data == (6 - index)); - index += 1; - } - } - - _ = list.popFirst(); // {2, 3, 4, 5} - _ = list.pop(); // {2, 3, 4} - list.remove(&three); // {2, 4} - - try testing.expect(list.first.?.data == 2); - try testing.expect(list.last.?.data == 4); - try testing.expect(list.len == 2); -} - -test "DoublyLinkedList concatenation" { - const L = DoublyLinkedList(u32); - var list1 = L{}; - var list2 = L{}; - - var one = L.Node{ .data = 1 }; - var two = L.Node{ .data = 2 }; - var three = L.Node{ .data = 3 }; - var four = L.Node{ .data = 4 }; - var five = L.Node{ .data = 5 }; - - list1.append(&one); - list1.append(&two); - list2.append(&three); - list2.append(&four); - list2.append(&five); - - list1.concatByMoving(&list2); - - try testing.expect(list1.last == &five); - try testing.expect(list1.len == 5); - try testing.expect(list2.first == null); - try testing.expect(list2.last == null); - try testing.expect(list2.len == 0); - - // Traverse forwards. - { - var it = list1.first; - var index: u32 = 1; - while (it) |node| : (it = node.next) { - try testing.expect(node.data == index); - index += 1; - } - } - - // Traverse backwards. - { - var it = list1.last; - var index: u32 = 1; - while (it) |node| : (it = node.prev) { - try testing.expect(node.data == (6 - index)); - index += 1; - } - } - - // Swap them back, this verifies that concatenating to an empty list works. - list2.concatByMoving(&list1); - - // Traverse forwards. - { - var it = list2.first; - var index: u32 = 1; - while (it) |node| : (it = node.next) { - try testing.expect(node.data == index); - index += 1; - } - } - - // Traverse backwards. - { - var it = list2.last; - var index: u32 = 1; - while (it) |node| : (it = node.prev) { - try testing.expect(node.data == (6 - index)); - index += 1; - } - } -} - -pub const RapidHash = struct { - const readInt = std.mem.readInt; - const assert = bun.assert; - const expect = std.testing.expect; - const expectEqual = std.testing.expectEqual; - - const RAPID_SEED: u64 = 0xbdd89aa982704029; - const RAPID_SECRET: [3]u64 = .{ 0x2d358dccaa6c78a5, 0x8bb84b93962eacc9, 0x4b33a62ed433d4a3 }; - - pub fn hash(seed: u64, input: []const u8) u64 { - const sc = RAPID_SECRET; - const len = input.len; - var a: u64 = 0; - var b: u64 = 0; - var k = input; - var is: [3]u64 = .{ seed, 0, 0 }; - - is[0] ^= mix(seed ^ sc[0], sc[1]) ^ len; - - if (len <= 16) { - if (len >= 4) { - const d: u64 = ((len & 24) >> @intCast(len >> 3)); - const e = len - 4; - a = (r32(k) << 32) | r32(k[e..]); - b = ((r32(k[d..]) << 32) | r32(k[(e - d)..])); - } else if (len > 0) - a = (@as(u64, k[0]) << 56) | (@as(u64, k[len >> 1]) << 32) | @as(u64, k[len - 1]); - } else { - var remain = len; - if (len > 48) { - is[1] = is[0]; - is[2] = is[0]; - while (remain >= 96) { - inline for (0..6) |i| { - const m1 = r64(k[8 * i * 2 ..]); - const m2 = r64(k[8 * (i * 2 + 1) ..]); - is[i % 3] = mix(m1 ^ sc[i % 3], m2 ^ is[i % 3]); - } - k = k[96..]; - remain -= 96; - } - if (remain >= 48) { - inline for (0..3) |i| { - const m1 = r64(k[8 * i * 2 ..]); - const m2 = r64(k[8 * (i * 2 + 1) ..]); - is[i] = mix(m1 ^ sc[i], m2 ^ is[i]); - } - k = k[48..]; - remain -= 48; - } - - is[0] ^= is[1] ^ is[2]; - } - - if (remain > 16) { - is[0] = mix(r64(k) ^ sc[2], r64(k[8..]) ^ is[0] ^ sc[1]); - if (remain > 32) { - is[0] = mix(r64(k[16..]) ^ sc[2], r64(k[24..]) ^ is[0]); - } - } - - a = r64(input[len - 16 ..]); - b = r64(input[len - 8 ..]); - } - - a ^= sc[1]; - b ^= is[0]; - mum(&a, &b); - return mix(a ^ sc[0] ^ len, b ^ sc[1]); - } - - test "RapidHash.hash" { - const bytes: []const u8 = "abcdefgh" ** 128; - - const sizes: [13]u64 = .{ 0, 1, 2, 3, 4, 8, 16, 32, 64, 128, 256, 512, 1024 }; - - const outcomes: [13]u64 = .{ - 0x5a6ef77074ebc84b, - 0xc11328477bc0f5d1, - 0x5644ac035e40d569, - 0x347080fbf5fcd81, - 0x56b66b8dc802bcc, - 0xb6bf9055973aac7c, - 0xed56d62eead1e402, - 0xc19072d767da8ffb, - 0x89bb40a9928a4f0d, - 0xe0af7c5e7b6e29fd, - 0x9a3ed35fbedfa11a, - 0x4c684b2119ca19fb, - 0x4b575f5bf25600d6, - }; - - for (sizes, outcomes) |s, e| { - const r = hash(RAPID_SEED, bytes[0..s]); - - try expectEqual(e, r); - } - } - - inline fn mum(a: *u64, b: *u64) void { - const r = @as(u128, a.*) * b.*; - a.* = @truncate(r); - b.* = @truncate(r >> 64); - } - - inline fn mix(a: u64, b: u64) u64 { - var copy_a = a; - var copy_b = b; - mum(©_a, ©_b); - return copy_a ^ copy_b; - } - - inline fn r64(p: []const u8) u64 { - return readInt(u64, p[0..8], .little); - } - - inline fn r32(p: []const u8) u64 { - return readInt(u32, p[0..4], .little); - } -}; - -pub fn jsErrorToWriteError(e: bun.JSError) std.Io.Writer.Error { - return switch (e) { - error.JSTerminated => error.WriteFailed, // TODO: this might lose a JSTerminated, causing m_terminationException problems - error.JSError => error.WriteFailed, // TODO: this might lose a JSError, causing exception check problems - error.OutOfMemory => bun.handleOom(error.OutOfMemory), - }; -} - -pub fn autoFormatLabelFallback(comptime ty: type, comptime fallback: []const u8) []const u8 { - comptime if (std.meta.hasFn(ty, "format")) { - return "{f}"; - } else { - return fallback; - }; -} - -pub fn autoFormatLabel(comptime ty: type) []const u8 { - return autoFormatLabelFallback(ty, "{s}"); -} - -const bun = @import("bun"); - -const std = @import("std"); -const testing = std.testing; - -const debug = std.debug; -const assert = debug.assert; diff --git a/src/bun_core/env.zig b/src/bun_core/env.zig deleted file mode 100644 index 59f64e6dd144..000000000000 --- a/src/bun_core/env.zig +++ /dev/null @@ -1,193 +0,0 @@ -pub const BuildTarget = enum { native, wasm, wasi }; -pub const build_target: BuildTarget = brk: { - if (builtin.cpu.arch.isWasm()) { - break :brk BuildTarget.wasm; - } else { - break :brk BuildTarget.native; - } -}; - -pub const isWasm = build_target == .wasm; -pub const isNative = build_target == .native; -pub const isWasi = build_target == .wasi; -pub const isMac = build_target == .native and builtin.target.os.tag == .macos; -pub const isBrowser = !isWasi and isWasm; -pub const isWindows = builtin.target.os.tag == .windows; -pub const isPosix = !isWindows and !isWasm; -pub const isDebug = builtin.mode == .Debug; -pub const isTest = builtin.is_test; -pub const isLinux = builtin.target.os.tag == .linux; -pub const isFreeBSD = builtin.target.os.tag == .freebsd; -/// kqueue-based event loop (macOS + FreeBSD share most of this path). -pub const isKqueue = isMac or isFreeBSD; -pub const isAarch64 = builtin.target.cpu.arch.isAARCH64(); -pub const isX86 = builtin.target.cpu.arch.isX86(); -pub const isX64 = builtin.target.cpu.arch == .x86_64; -pub const isMusl = builtin.target.abi.isMusl(); -pub const isAndroid = builtin.target.abi.isAndroid(); -pub const isGlibc = isLinux and builtin.target.abi.isGnu(); -pub const allow_assert = isDebug or isTest or std.builtin.OptimizeMode.ReleaseSafe == builtin.mode; -pub const ci_assert = isDebug or isTest or enable_asan or (std.builtin.OptimizeMode.ReleaseSafe == builtin.mode and is_canary); -pub const show_crash_trace = isDebug or isTest or enable_asan; -/// All calls to `@export` should be gated behind this check, so that code -/// generators that compile Zig code know not to reference and compile a ton of -/// unused code. -pub const export_cpp_apis = if (build_options.override_no_export_cpp_apis) false else (builtin.output_mode == .Obj or isTest); - -/// Whether or not to enable allocation tracking when the `AllocationScope` -/// allocator is used. -pub const enableAllocScopes = isDebug or enable_asan; - -pub const build_options = @import("build_options"); - -/// Set if compiling with `-Dno_llvm` -/// All places this is used is working around a Zig bug. -pub const zig_self_hosted_backend = build_options.zig_self_hosted_backend; - -pub const reported_nodejs_version = build_options.reported_nodejs_version; -pub const baseline = build_options.baseline; -pub const enableSIMD: bool = !baseline and !zig_self_hosted_backend; -pub const git_sha = build_options.sha; -pub const git_sha_short = if (build_options.sha.len > 0) build_options.sha[0..9] else ""; -pub const git_sha_shorter = if (build_options.sha.len > 0) build_options.sha[0..6] else ""; -pub const is_canary = build_options.is_canary; -pub const canary_revision = if (is_canary) build_options.canary_revision else ""; -pub const dump_source = isDebug and !isTest; -pub const base_path = build_options.base_path; -pub const enable_logs = build_options.enable_logs; -pub const enable_asan = build_options.enable_asan; -pub const enable_fuzzilli = build_options.enable_fuzzilli; -pub const enable_tinycc = build_options.enable_tinycc; -pub const codegen_path = build_options.codegen_path; -pub const codegen_embed = build_options.codegen_embed; - -pub const version: std.SemanticVersion = build_options.version; -pub const version_string = std.fmt.comptimePrint("{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); - -pub inline fn onlyMac() void { - if (comptime !isMac) { - unreachable; - } -} - -pub const OperatingSystem = enum { - mac, - linux, - freebsd, - windows, - // wAsM is nOt aN oPeRaTiNg SyStEm - wasm, - - pub const names = bun.ComptimeStringMap(OperatingSystem, &.{ - .{ "windows", .windows }, - .{ "win32", .windows }, - .{ "win", .windows }, - .{ "win64", .windows }, - .{ "win_x64", .windows }, - .{ "darwin", .mac }, - .{ "macos", .mac }, - .{ "macOS", .mac }, - .{ "mac", .mac }, - .{ "apple", .mac }, - .{ "linux", .linux }, - .{ "Linux", .linux }, - .{ "linux-gnu", .linux }, - .{ "gnu/linux", .linux }, - .{ "freebsd", .freebsd }, - .{ "FreeBSD", .freebsd }, - .{ "wasm", .wasm }, - }); - - /// user-facing name with capitalization - pub fn displayString(self: OperatingSystem) []const u8 { - return switch (self) { - .mac => "macOS", - .linux => "Linux", - .freebsd => "FreeBSD", - .windows => "Windows", - .wasm => "WASM", - }; - } - - /// same format as `process.platform` - pub fn nameString(self: OperatingSystem) []const u8 { - return switch (self) { - .mac => "darwin", - .linux => "linux", - .freebsd => "freebsd", - .windows => "win32", - .wasm => "wasm", - }; - } - - pub fn stdOSTag(self: OperatingSystem) std.Target.Os.Tag { - return switch (self) { - .mac => .macos, - .linux => .linux, - .freebsd => .freebsd, - .windows => .windows, - .wasm => unreachable, - }; - } - - /// npm package name, `@oven-sh/bun-{os}-{arch}` - pub fn npmName(self: OperatingSystem) []const u8 { - return switch (self) { - .mac => "darwin", - .linux => "linux", - .freebsd => "freebsd", - .windows => "windows", - .wasm => "wasm", - }; - } -}; - -pub const os: OperatingSystem = if (isMac) - .mac -else if (isLinux) - .linux -else if (isFreeBSD) - .freebsd -else if (isWindows) - .windows -else if (isWasm) - .wasm -else - @compileError("Please add your OS to the OperatingSystem enum"); - -pub const Architecture = enum { - x64, - arm64, - wasm, - - /// npm package name, `@oven-sh/bun-{os}-{arch}` - pub fn npmName(this: Architecture) []const u8 { - return switch (this) { - .x64 => "x64", - .arm64 => "aarch64", - .wasm => "wasm", - }; - } - - pub const names = bun.ComptimeStringMap(Architecture, &.{ - .{ "x86_64", .x64 }, - .{ "x64", .x64 }, - .{ "amd64", .x64 }, - .{ "aarch64", .arm64 }, - .{ "arm64", .arm64 }, - .{ "wasm", .wasm }, - }); -}; - -pub const arch: Architecture = if (isWasm) - .wasm -else if (isX64) - .x64 -else if (isAarch64) - .arm64 -else - @compileError("Please add your architecture to the Architecture enum"); - -const builtin = @import("builtin"); -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bun_core/env_var.zig b/src/bun_core/env_var.zig deleted file mode 100644 index 858604d50d4b..000000000000 --- a/src/bun_core/env_var.zig +++ /dev/null @@ -1,727 +0,0 @@ -//! Unified module for controlling and managing environment variables in Bun. -//! -//! This library uses metaprogramming to achieve type-safe accessors for environment variables. -//! Calling .get() on any of the environment variables will return the correct environment variable -//! type, whether it's a string, unsigned or boolean. This library also caches the environment -//! variables for you, for slightly faster access. -//! -//! If default values are provided, the .get() method is guaranteed not to return a nullable type, -//! whereas if no default is provided, the .get() method will return an optional type. -//! -//! Note that environment variables may fail to parse silently. If they do fail to parse, the -//! default is to show a debug warning and treat them as not set. This behavior can be customized, -//! but environment variables are not meant to be a robust configuration mechanism. If you do think -//! your feature needs more customization, consider using other means. The reason we have decided -//! upon this behavior is to avoid panics due to environment variable pollution. -//! -//! TODO(markovejnovic): It would be neat if this library supported loading floats as -//! well as strings, integers and booleans, but for now this will do. -//! -//! TODO(markovejnovic): As this library migrates away from bun.getenvZ, it should return -//! NUL-terminated slices, rather than plain slices. Perhaps there should be a -//! .getZ() accessor? -//! -//! TODO(markovejnovic): This current implementation kind of does redundant work. Instead of -//! scanning envp, and preparing everything on bootup, we lazily load -//! everything. This means that we potentially scan through envp a lot of -//! times, even though we could only do it once. - -pub const AGENT = New(kind.string, "AGENT", .{}); -pub const BUN_AGENT_RULE_DISABLED = New(kind.boolean, "BUN_AGENT_RULE_DISABLED", .{ .default = false }); -pub const BUN_COMPILE_TARGET_TARBALL_URL = New(kind.string, "BUN_COMPILE_TARGET_TARBALL_URL", .{}); -pub const BUN_CONFIG_DISABLE_COPY_FILE_RANGE = New(kind.boolean, "BUN_CONFIG_DISABLE_COPY_FILE_RANGE", .{ .default = false }); -pub const BUN_CONFIG_DISABLE_ioctl_ficlonerange = New(kind.boolean, "BUN_CONFIG_DISABLE_ioctl_ficlonerange", .{ .default = false }); -/// TODO(markovejnovic): Legacy usage had the default at 30, even though a the attached comment -/// quoted: Amazon Web Services recommends 5 seconds: -/// https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/jvm-ttl-dns.html -/// -/// It's unclear why this was done. -pub const BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS = New(kind.unsigned, "BUN_CONFIG_DNS_TIME_TO_LIVE_SECONDS", .{ .default = 30 }); -/// Idle timeout for HTTP client sockets (fetch / `bun install`), in seconds. -/// The timer is armed when the socket opens and re-armed on every read/write; -/// if it fires the request fails with `error.Timeout`. Covers the TLS -/// handshake through the response body. 0 disables. See `src/http/http.zig`. -pub const BUN_CONFIG_HTTP_IDLE_TIMEOUT = New(kind.unsigned, "BUN_CONFIG_HTTP_IDLE_TIMEOUT", .{ .default = 300 }); -pub const BUN_CRASH_REPORT_URL = New(kind.string, "BUN_CRASH_REPORT_URL", .{}); -pub const BUN_DEBUG = New(kind.string, "BUN_DEBUG", .{}); -pub const BUN_DEBUG_ALL = New(kind.boolean, "BUN_DEBUG_ALL", .{}); -pub const BUN_DEBUG_CSS_ORDER = New(kind.boolean, "BUN_DEBUG_CSS_ORDER", .{ .default = false }); -pub const BUN_DEBUG_ENABLE_RESTORE_FROM_TRANSPILER_CACHE = New(kind.boolean, "BUN_DEBUG_ENABLE_RESTORE_FROM_TRANSPILER_CACHE", .{ .default = false }); -/// Testing hook for `bun build --compile`: force `hostUsesNixStoreInterpreter()` -/// to return true without mutating `/etc/NIXOS` on the shared rootfs. Used by -/// `test/regression/issue/29290.test.ts` to exercise the Nix-host branch. -pub const BUN_DEBUG_FORCE_NIX_HOST = New(kind.boolean, "BUN_DEBUG_FORCE_NIX_HOST", .{ .default = false }); -pub const BUN_DEBUG_HASH_RANDOM_SEED = New(kind.unsigned, "BUN_DEBUG_HASH_RANDOM_SEED", .{ .deser = .{ .error_handling = .not_set } }); -pub const BUN_DEBUG_QUIET_LOGS = New(kind.boolean, "BUN_DEBUG_QUIET_LOGS", .{}); -pub const BUN_DEBUG_TEST_TEXT_LOCKFILE = New(kind.boolean, "BUN_DEBUG_TEST_TEXT_LOCKFILE", .{ .default = false }); -pub const BUN_DEV_SERVER_TEST_RUNNER = New(kind.string, "BUN_DEV_SERVER_TEST_RUNNER", .{}); -pub const BUN_ENABLE_CRASH_REPORTING = New(kind.boolean, "BUN_ENABLE_CRASH_REPORTING", .{}); -/// Opt-in: when truthy, Bun watches its original parent pid and exits as soon -/// as that process dies (even if the parent was SIGKILLed and couldn't forward -/// a signal), and on its own clean exit recursively SIGKILLs every descendant -/// so nothing it spawned outlives it. See `src/ParentDeathWatchdog.zig`. -pub const BUN_FEATURE_FLAG_NO_ORPHANS = New(kind.boolean, "BUN_FEATURE_FLAG_NO_ORPHANS", .{ .default = false }); -pub const BUN_FEATURE_FLAG_DUMP_CODE = New(kind.string, "BUN_FEATURE_FLAG_DUMP_CODE", .{}); -/// TODO(markovejnovic): It's unclear why the default here is 100_000, but this was legacy behavior -/// so we'll keep it for now. -pub const BUN_INOTIFY_COALESCE_INTERVAL = New(kind.unsigned, "BUN_INOTIFY_COALESCE_INTERVAL", .{ .default = 100_000 }); -pub const BUN_INSPECT = New(kind.string, "BUN_INSPECT", .{ .default = "" }); -pub const BUN_INSPECT_CONNECT_TO = New(kind.string, "BUN_INSPECT_CONNECT_TO", .{ .default = "" }); -pub const BUN_INSPECT_PRELOAD = New(kind.string, "BUN_INSPECT_PRELOAD", .{}); -pub const BUN_INSTALL = New(kind.string, "BUN_INSTALL", .{}); -pub const BUN_INSTALL_BIN = New(kind.string, "BUN_INSTALL_BIN", .{}); -pub const BUN_INSTALL_GLOBAL_DIR = New(kind.string, "BUN_INSTALL_GLOBAL_DIR", .{}); -/// Minimum response `Content-Length` (in bytes) for `bun install` to -/// stream a tarball directly into libarchive instead of buffering the -/// whole body first. Smaller tarballs stay on the buffered path where -/// the fixed overhead of the resumable state machine isn't worth it. -pub const BUN_INSTALL_STREAMING_MIN_SIZE = New(kind.unsigned, "BUN_INSTALL_STREAMING_MIN_SIZE", .{ .default = 2 * 1024 * 1024 }); -pub const BUN_NEEDS_PROC_SELF_WORKAROUND = New(kind.boolean, "BUN_NEEDS_PROC_SELF_WORKAROUND", .{ .default = false }); -pub const BUN_OPTIONS = New(kind.string, "BUN_OPTIONS", .{}); -pub const BUN_POSTGRES_SOCKET_MONITOR = New(kind.string, "BUN_POSTGRES_SOCKET_MONITOR", .{}); -pub const BUN_POSTGRES_SOCKET_MONITOR_READER = New(kind.string, "BUN_POSTGRES_SOCKET_MONITOR_READER", .{}); -pub const BUN_RUNTIME_TRANSPILER_CACHE_PATH = New(kind.string, "BUN_RUNTIME_TRANSPILER_CACHE_PATH", .{}); -pub const BUN_SSG_DISABLE_STATIC_ROUTE_VISITOR = New(kind.boolean, "BUN_SSG_DISABLE_STATIC_ROUTE_VISITOR", .{ .default = false }); -pub const BUN_TCC_OPTIONS = New(kind.string, "BUN_TCC_OPTIONS", .{}); -/// Standard C compiler environment variable for include paths (colon-separated). -/// Used by bun:ffi's TinyCC integration for systems like NixOS. -pub const C_INCLUDE_PATH = PlatformSpecificNew(kind.string, "C_INCLUDE_PATH", null, .{}); -/// Standard C compiler environment variable for library paths (colon-separated). -/// Used by bun:ffi's TinyCC integration for systems like NixOS. -pub const LIBRARY_PATH = PlatformSpecificNew(kind.string, "LIBRARY_PATH", null, .{}); -pub const BUN_TMPDIR = New(kind.string, "BUN_TMPDIR", .{}); -pub const BUN_TRACK_LAST_FN_NAME = New(kind.boolean, "BUN_TRACK_LAST_FN_NAME", .{ .default = false }); -pub const BUN_TRACY_PATH = New(kind.string, "BUN_TRACY_PATH", .{}); -pub const BUN_WATCHER_TRACE = New(kind.string, "BUN_WATCHER_TRACE", .{}); -pub const CI = New(kind.boolean, "CI", .{}); -pub const CI_COMMIT_SHA = New(kind.string, "CI_COMMIT_SHA", .{}); -pub const CI_JOB_URL = New(kind.string, "CI_JOB_URL", .{}); -pub const CLAUDE_CODE_AGENT_RULE_DISABLED = New(kind.boolean, "CLAUDE_CODE_AGENT_RULE_DISABLED", .{ .default = false }); -pub const CLAUDECODE = New(kind.boolean, "CLAUDECODE", .{ .default = false }); -pub const COLORTERM = New(kind.string, "COLORTERM", .{}); -pub const CURSOR_AGENT_RULE_DISABLED = New(kind.boolean, "CURSOR_AGENT_RULE_DISABLED", .{ .default = false }); -pub const CURSOR_TRACE_ID = New(kind.boolean, "CURSOR_TRACE_ID", .{ .default = false }); -pub const DO_NOT_TRACK = New(kind.boolean, "DO_NOT_TRACK", .{ .default = false }); -pub const DYLD_ROOT_PATH = PlatformSpecificNew(kind.string, "DYLD_ROOT_PATH", null, .{}); -/// TODO(markovejnovic): We should support enums in this library, and force_color's usage is, -/// indeed, an enum. The 80-20 is to make it an unsigned value (which also works well). -pub const FORCE_COLOR = New(kind.unsigned, "FORCE_COLOR", .{ .deser = .{ .error_handling = .truthy_cast, .empty_string_as = .{ .value = 1 } } }); -pub const fpath = PlatformSpecificNew(kind.string, "fpath", null, .{}); -pub const GIT_SHA = New(kind.string, "GIT_SHA", .{}); -pub const GITHUB_ACTIONS = New(kind.boolean, "GITHUB_ACTIONS", .{ .default = false }); -pub const GITHUB_REPOSITORY = New(kind.string, "GITHUB_REPOSITORY", .{}); -pub const GITHUB_RUN_ID = New(kind.string, "GITHUB_RUN_ID", .{}); -pub const GITHUB_SERVER_URL = New(kind.string, "GITHUB_SERVER_URL", .{}); -pub const GITHUB_SHA = New(kind.string, "GITHUB_SHA", .{}); -pub const GITHUB_WORKSPACE = New(kind.string, "GITHUB_WORKSPACE", .{}); -pub const HOME = PlatformSpecificNew(kind.string, "HOME", "USERPROFILE", .{}); -pub const HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET = New(kind.string, "HYPERFINE_RANDOMIZED_ENVIRONMENT_OFFSET", .{}); -pub const IS_BUN_AUTO_UPDATE = New(kind.boolean, "IS_BUN_AUTO_UPDATE", .{ .default = false }); -pub const JENKINS_URL = New(kind.string, "JENKINS_URL", .{}); -/// Dump mimalloc statistics at the end of the process. Note that this is not the same as -/// `MIMALLOC_VERBOSE`, documented here: https://microsoft.github.io/mimalloc/environment.html -pub const MI_VERBOSE = New(kind.boolean, "MI_VERBOSE", .{ .default = false }); -pub const NO_COLOR = New(kind.boolean, "NO_COLOR", .{ .default = false }); -pub const NODE_CHANNEL_FD = New(kind.string, "NODE_CHANNEL_FD", .{}); -/// Set by HostProcess.zig when spawning the WebView host subprocess. The -/// child's cli.zig checks this before anything else and hands off to C++ -/// Bun__WebView__hostMain. Never returns — no JSC, no VM. -pub const BUN_INTERNAL_WEBVIEW_HOST = New(kind.string, "BUN_INTERNAL_WEBVIEW_HOST", .{}); -pub const NODE_PRESERVE_SYMLINKS_MAIN = New(kind.boolean, "NODE_PRESERVE_SYMLINKS_MAIN", .{ .default = false }); -pub const NODE_USE_SYSTEM_CA = New(kind.boolean, "NODE_USE_SYSTEM_CA", .{ .default = false }); -pub const npm_lifecycle_event = New(kind.string, "npm_lifecycle_event", .{}); -pub const PATH = New(kind.string, "PATH", .{}); -pub const REPL_ID = New(kind.boolean, "REPL_ID", .{ .default = false }); -pub const RUNNER_DEBUG = New(kind.boolean, "RUNNER_DEBUG", .{ .default = false }); -pub const SDKROOT = PlatformSpecificNew(kind.string, "SDKROOT", null, .{}); -pub const SHELL = PlatformSpecificNew(kind.string, "SHELL", null, .{}); -/// C:\Windows, for example. -/// Note: Do not use this variable directly -- use os.zig's implementation instead. -pub const SYSTEMROOT = PlatformSpecificNew(kind.string, null, "SYSTEMROOT", .{}); -pub const TEMP = PlatformSpecificNew(kind.string, "TEMP", "TEMP", .{}); -pub const TERM = New(kind.string, "TERM", .{}); -pub const TERM_PROGRAM = New(kind.string, "TERM_PROGRAM", .{}); -pub const TMP = PlatformSpecificNew(kind.string, "TMP", "TMP", .{}); -pub const TMPDIR = PlatformSpecificNew(kind.string, "TMPDIR", "TMPDIR", .{}); -pub const TMUX = New(kind.string, "TMUX", .{}); -pub const TODIUM = New(kind.string, "TODIUM", .{}); -pub const USER = PlatformSpecificNew(kind.string, "USER", "USERNAME", .{}); -pub const WANTS_LOUD = New(kind.boolean, "WANTS_LOUD", .{ .default = false }); -/// The same as system_root. -/// Note: Do not use this variable directly -- use os.zig's implementation instead. -/// TODO(markovejnovic): Perhaps we could add support for aliases in the library, so you could -/// specify both WINDIR and SYSTEMROOT and the loader would check both? -pub const WINDIR = PlatformSpecificNew(kind.string, null, "WINDIR", .{}); -/// XDG Base Directory Specification variables. -/// For some reason, legacy usage respected these even on Windows. To avoid compatibility issues, -/// we respect them too. -pub const XDG_CACHE_HOME = New(kind.string, "XDG_CACHE_HOME", .{}); -pub const XDG_CONFIG_HOME = New(kind.string, "XDG_CONFIG_HOME", .{}); -pub const XDG_DATA_HOME = New(kind.string, "XDG_DATA_HOME", .{}); -pub const ZDOTDIR = New(kind.string, "ZDOTDIR", .{}); - -pub const feature_flag = struct { - pub const BUN_ASSUME_PERFECT_INCREMENTAL = newFeatureFlag("BUN_ASSUME_PERFECT_INCREMENTAL", .{ .default = null }); - pub const BUN_BE_BUN = newFeatureFlag("BUN_BE_BUN", .{}); - pub const BUN_DEBUG_NO_DUMP = newFeatureFlag("BUN_DEBUG_NO_DUMP", .{}); - pub const BUN_DESTRUCT_VM_ON_EXIT = newFeatureFlag("BUN_DESTRUCT_VM_ON_EXIT", .{}); - - /// Disable "nativeDependencies" - pub const BUN_FEATURE_FLAG_DISABLE_NATIVE_DEPENDENCY_LINKER = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_NATIVE_DEPENDENCY_LINKER", .{}); - - /// Disable "ignoreScripts" in package.json - pub const BUN_FEATURE_FLAG_DISABLE_IGNORE_SCRIPTS = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_IGNORE_SCRIPTS", .{}); - - pub const BUN_FEATURE_FLAG_DISABLE_ADDRCONFIG = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_ADDRCONFIG", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_ASYNC_TRANSPILER = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_ASYNC_TRANSPILER", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_ISOLATION_SOURCE_CACHE = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_ISOLATION_SOURCE_CACHE", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_DNS_CACHE = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_DNS_CACHE", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_DNS_CACHE_LIBINFO = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_DNS_CACHE_LIBINFO", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_INSTALL_INDEX = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_INSTALL_INDEX", .{}); - /// Disable streaming tarball extraction in `bun install`. When disabled, - /// the whole .tgz is buffered in memory before being decompressed and - /// extracted. Useful for bisecting streaming-specific bugs. - pub const BUN_FEATURE_FLAG_DISABLE_STREAMING_INSTALL = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_STREAMING_INSTALL", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_IO_POOL = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_IO_POOL", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_IPV4 = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_IPV4", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_IPV6 = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_IPV6", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_MEMFD = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_MEMFD", .{}); - /// The RedisClient supports auto-pipelining by default. This flag disables that behavior. - pub const BUN_FEATURE_FLAG_DISABLE_REDIS_AUTO_PIPELINING = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_REDIS_AUTO_PIPELINING", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_RWF_NONBLOCK = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_RWF_NONBLOCK", .{}); - pub const BUN_DISABLE_SLOW_LIFECYCLE_SCRIPT_LOGGING = newFeatureFlag("BUN_DISABLE_SLOW_LIFECYCLE_SCRIPT_LOGGING", .{}); - pub const BUN_DISABLE_SOURCE_CODE_PREVIEW = newFeatureFlag("BUN_DISABLE_SOURCE_CODE_PREVIEW", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_SOURCE_MAPS = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_SOURCE_MAPS", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_SPAWNSYNC_FAST_PATH = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_SPAWNSYNC_FAST_PATH", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_SQL_AUTO_PIPELINING = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_SQL_AUTO_PIPELINING", .{}); - pub const BUN_DISABLE_TRANSPILED_SOURCE_CODE_PREVIEW = newFeatureFlag("BUN_DISABLE_TRANSPILED_SOURCE_CODE_PREVIEW", .{}); - pub const BUN_FEATURE_FLAG_DISABLE_UV_FS_COPYFILE = newFeatureFlag("BUN_FEATURE_FLAG_DISABLE_UV_FS_COPYFILE", .{}); - pub const BUN_DUMP_STATE_ON_CRASH = newFeatureFlag("BUN_DUMP_STATE_ON_CRASH", .{}); - pub const BUN_ENABLE_EXPERIMENTAL_SHELL_BUILTINS = newFeatureFlag("BUN_ENABLE_EXPERIMENTAL_SHELL_BUILTINS", .{}); - pub const BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE = newFeatureFlag("BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE", .{}); - /// Offer "h2" in the fetch() TLS ALPN list and speak HTTP/2 when the - /// server selects it. Off by default while the client implementation - /// matures. `--experimental-http2-fetch` is the CLI equivalent. - pub const BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP2_CLIENT = newFeatureFlag("BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP2_CLIENT", .{}); - /// Honor `Alt-Svc: h3` from fetch() responses: subsequent requests to the - /// same origin go over QUIC/HTTP-3 instead of TCP. Off by default while - /// the client implementation matures. `--experimental-http3-fetch` is the - /// CLI equivalent. - pub const BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP3_CLIENT = newFeatureFlag("BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP3_CLIENT", .{}); - pub const BUN_FEATURE_FLAG_FORCE_IO_POOL = newFeatureFlag("BUN_FEATURE_FLAG_FORCE_IO_POOL", .{}); - pub const BUN_FEATURE_FLAG_FORCE_WINDOWS_JUNCTIONS = newFeatureFlag("BUN_FEATURE_FLAG_FORCE_WINDOWS_JUNCTIONS", .{}); - pub const BUN_INSTRUMENTS = newFeatureFlag("BUN_INSTRUMENTS", .{}); - pub const BUN_INTERNAL_BUNX_INSTALL = newFeatureFlag("BUN_INTERNAL_BUNX_INSTALL", .{}); - pub const BUN_INTERNAL_SUPPRESS_CRASH_IN_BUN_RUN = newFeatureFlag("BUN_INTERNAL_SUPPRESS_CRASH_IN_BUN_RUN", .{}); - pub const BUN_INTERNAL_SUPPRESS_CRASH_ON_NAPI_ABORT = newFeatureFlag("BUN_INTERNAL_SUPPRESS_CRASH_ON_NAPI_ABORT", .{}); - pub const BUN_INTERNAL_SUPPRESS_CRASH_ON_PROCESS_KILL_SELF = newFeatureFlag("BUN_INTERNAL_SUPPRESS_CRASH_ON_PROCESS_KILL_SELF", .{}); - pub const BUN_INTERNAL_SUPPRESS_CRASH_ON_UV_STUB = newFeatureFlag("BUN_INTERNAL_SUPPRESS_CRASH_ON_UV_STUB", .{}); - pub const BUN_FEATURE_FLAG_LAST_MODIFIED_PRETEND_304 = newFeatureFlag("BUN_FEATURE_FLAG_LAST_MODIFIED_PRETEND_304", .{}); - pub const BUN_NO_CODESIGN_MACHO_BINARY = newFeatureFlag("BUN_NO_CODESIGN_MACHO_BINARY", .{}); - pub const BUN_FEATURE_FLAG_NO_LIBDEFLATE = newFeatureFlag("BUN_FEATURE_FLAG_NO_LIBDEFLATE", .{}); - pub const NODE_NO_WARNINGS = newFeatureFlag("NODE_NO_WARNINGS", .{}); - pub const BUN_TRACE = newFeatureFlag("BUN_TRACE", .{}); -}; - -/// Interface between each of the different EnvVar types and the common logic. -fn CacheOutput(comptime ValueType: type) type { - return union(enum) { - /// The environment variable hasn't been loaded yet. - unknown: void, - /// The environment variable has been loaded but its not set. - not_set: void, - /// The environment variable is set to a value. - value: ValueType, - }; -} - -fn CacheConfigurationType(comptime CtorOptionsType: type) type { - return struct { - var_name: []const u8, - opts: CtorOptionsType, - }; -} - -/// Structure which encodes the different types of environment variables supported. -/// -/// This requires the following static members: -/// -/// - `ValueType`: The underlying environment variable type if one is set. For -/// example, a string `$PATH` ought return a `[]const u8` when set. -/// - `Cache`: A struct implementing the following methods: -/// - `getCached() CacheOutput(ValueType)`: Retrieve the cached value of the -/// environment variable, if any. -/// - `deserAndInvalidate(raw_env: ?[]const u8) ?ValueType` -/// - `CtorOptions`: A struct containing the options passed to the constructor of the environment -/// variable definition. -/// -/// This type will communicate with the common logic via the `CacheOutput` type. -const kind = struct { - const string = struct { - const ValueType = []const u8; - const Input = CacheConfigurationType(CtorOptions); - const Output = CacheOutput(ValueType); - const CtorOptions = struct { - default: ?ValueType = null, - }; - - fn Cache(comptime ip: Input) type { - _ = ip; - - const PointerType = ?[*]const u8; - const LenType = usize; - - return struct { - const Self = @This(); - - const not_loaded_sentinel = struct { - const ptr: PointerType = null; - const len: LenType = std.math.maxInt(LenType); - }; - - const not_set_sentinel = struct { - const ptr: PointerType = null; - const len: LenType = std.math.maxInt(LenType) - 1; - }; - - ptr_value: std.atomic.Value(PointerType) = .init(null), - len_value: std.atomic.Value(LenType) = .init(std.math.maxInt(LenType)), - - fn getCached(self: *Self) Output { - const len = self.len_value.load(.acquire); - - if (len == not_loaded_sentinel.len) { - return .{ .unknown = {} }; - } - - if (len == not_set_sentinel.len) { - return .{ .not_set = {} }; - } - - const ptr = self.ptr_value.load(.monotonic); - - return .{ .value = ptr.?[0..len] }; - } - - inline fn deserAndInvalidate(self: *Self, raw_env: ?[]const u8) ?ValueType { - // The implementation is racy and allows two threads to both set the value at - // the same time, as long as the value they are setting is the same. This is - // difficult to write an assertion for since it requires the DEV path take a - // .swap() path rather than a plain .store(). - - if (raw_env) |ev| { - self.ptr_value.store(ev.ptr, .monotonic); - self.len_value.store(ev.len, .release); - } else { - self.ptr_value.store(not_set_sentinel.ptr, .monotonic); - self.len_value.store(not_set_sentinel.len, .release); - } - - return raw_env; - } - }; - } - }; - - const boolean = struct { - const ValueType = bool; - const Input = CacheConfigurationType(CtorOptions); - const Output = CacheOutput(ValueType); - const CtorOptions = struct { - default: ?ValueType = null, - }; - - fn stringIsTruthy(s: []const u8) bool { - // Most values are considered truthy, except for "", "0", "false", "no", and "off". - const false_values = .{ "", "0", "false", "no", "off" }; - - inline for (false_values) |tv| { - if (std.ascii.eqlIgnoreCase(s, tv)) { - return false; - } - } - - return true; - } - - // This is a template which ignores its parameter, but is necessary so that a separate - // Cache type is emitted for every environment variable. - fn Cache(comptime ip: Input) type { - return struct { - const Self = @This(); - - const StoredType = enum(u8) { unknown, not_set, no, yes }; - - value: std.atomic.Value(StoredType) = .init(.unknown), - - inline fn getCached(self: *Self) Output { - _ = ip; - - const cached = self.value.load(.monotonic); - switch (cached) { - .unknown => { - @branchHint(.unlikely); - return .{ .unknown = {} }; - }, - .not_set => { - return .{ .not_set = {} }; - }, - .no => { - return .{ .value = false }; - }, - .yes => { - return .{ .value = true }; - }, - } - } - - inline fn deserAndInvalidate(self: *Self, raw_env: ?[]const u8) ?ValueType { - if (raw_env == null) { - self.value.store(.not_set, .monotonic); - return null; - } - - const string_is_truthy = stringIsTruthy(raw_env.?); - self.value.store(if (string_is_truthy) .yes else .no, .monotonic); - return string_is_truthy; - } - }; - } - }; - - const unsigned = struct { - const ValueType = u64; - const Input = CacheConfigurationType(CtorOptions); - const Output = CacheOutput(ValueType); - const CtorOptions = struct { - default: ?ValueType = null, - deser: struct { - /// Control how deserializing and deserialization errors are handled. - /// - /// Note that deserialization errors cannot panic. If you need more robust means of - /// handling inputs, consider not using environment variables. - error_handling: enum { - /// debug_warn on deserialization errors. - debug_warn, - /// Ignore deserialization errors and treat the variable as not set. - not_set, - /// Fallback to default. - default_fallback, - /// Formatting errors are treated as truthy values. - /// - /// If this library fails to parse the value as an integer and truthy cast is - /// enabled, truthy values will be set to 1 or 0. - /// - /// Note: Most values are considered truthy, except for "", "0", "false", "no", - /// and "off". - truthy_cast, - } = .debug_warn, - - /// Control what empty strings are treated as. - empty_string_as: union(enum) { - /// Empty strings are handled as the given value. - value: ValueType, - /// Empty strings are treated as deserialization errors. - erroneous: void, - } = .erroneous, - } = .{}, - }; - - fn Cache(comptime ip: Input) type { - return struct { - const Self = @This(); - - const StoredType = ValueType; - - /// The value meaning an environment variable that hasn't been loaded yet. - const unknown_sentinel: comptime_int = std.math.maxInt(StoredType); - /// The unique value representing an environment variable that is not set. - const not_set_sentinel: comptime_int = std.math.maxInt(StoredType) - 1; - - value: std.atomic.Value(StoredType) = .init(unknown_sentinel), - - inline fn getCached(self: *Self) Output { - switch (self.value.load(.monotonic)) { - unknown_sentinel => { - @branchHint(.unlikely); - return .{ .unknown = {} }; - }, - not_set_sentinel => { - return .{ .not_set = {} }; - }, - else => |v| { - return .{ .value = v }; - }, - } - } - - inline fn deserAndInvalidate(self: *Self, raw_env: ?[]const u8) ?ValueType { - if (raw_env == null) { - self.value.store(not_set_sentinel, .monotonic); - return null; - } - - if (std.mem.eql(u8, raw_env.?, "")) { - switch (ip.opts.deser.empty_string_as) { - .value => |v| { - self.value.store(v, .monotonic); - return v; - }, - .erroneous => { - return self.handleError(raw_env.?, "is an empty string"); - }, - } - } - - const formatted = std.fmt.parseInt(StoredType, raw_env.?, 10) catch |err| { - switch (err) { - error.Overflow => { - return self.handleError(raw_env.?, "overflows u64"); - }, - error.InvalidCharacter => { - return self.handleError(raw_env.?, "is not a valid integer"); - }, - } - }; - - if (formatted == not_set_sentinel or formatted == unknown_sentinel) { - return self.handleError(raw_env.?, "is a reserved value"); - } - - self.value.store(formatted, .monotonic); - return formatted; - } - - fn handleError( - self: *Self, - raw_env: []const u8, - comptime reason: []const u8, - ) ?ValueType { - const base_fmt = "Environment variable '{s}' has value '{s}' which "; - const fmt = base_fmt ++ reason ++ "."; - const missing_default_fmt = "Environment variable '{s}' is configured to " ++ - "fallback to default on {s}, but no default is set."; - - switch (ip.opts.deser.error_handling) { - .debug_warn => { - bun.Output.debugWarn(fmt, .{ ip.var_name, raw_env }); - self.value.store(not_set_sentinel, .monotonic); - return null; - }, - .not_set => { - self.value.store(not_set_sentinel, .monotonic); - return null; - }, - .truthy_cast => { - if (kind.boolean.stringIsTruthy(raw_env)) { - self.value.store(1, .monotonic); - return 1; - } else { - self.value.store(0, .monotonic); - return 0; - } - }, - .default_fallback => { - if (comptime ip.opts.default) |d| { - return deserAndInvalidate(d); - } - @compileError(std.fmt.comptimePrint(missing_default_fmt, .{ - ip.var_name, - "default_fallback", - })); - }, - } - } - }; - } - }; -}; - -/// Create a new environment variable definition. -/// -/// The resulting type has methods for interacting with the environment variable. -/// -/// Technically, none of the operations here are thread-safe, so writing to environment variables -/// does not guarantee that other threads will see the changes. You should avoid writing to -/// environment variables. -fn New( - comptime VariantType: type, - comptime key: [:0]const u8, - comptime opts: VariantType.CtorOptions, -) type { - return PlatformSpecificNew(VariantType, key, key, opts); -} - -/// Identical to new, except it allows you to specify different keys for POSIX and Windows. -/// -/// If the current platform does not have a key specified, all methods that attempt to read the -/// environment variable will fail at compile time, except for `platformGet` and `platformKey`, -/// which will return null instead. -fn PlatformSpecificNew( - comptime VariantType: type, - comptime posix_key: ?[:0]const u8, - comptime windows_key: ?[:0]const u8, - comptime opts: VariantType.CtorOptions, -) type { - const DefaultType = if (comptime opts.default) |d| @TypeOf(d) else void; - - const comptime_key: []const u8 = - if (posix_key) |pk| pk else if (windows_key) |wk| wk else ""; - - if (posix_key == null and windows_key == null) { - @compileError("Environment variable " ++ comptime_key ++ " has no keys for POSIX " ++ - "nor Windows specified. Provide a key for either POSIX or Windows."); - } - - const KeyType = [:0]const u8; - - // Return type as returned by each of the variants of kind. - const ValueType = VariantType.ValueType; - - // The actual return type of public methods. - const ReturnType = if (opts.default != null) ValueType else ?ValueType; - - return struct { - const Self = @This(); - - var cache: VariantType.Cache(.{ .var_name = comptime_key, .opts = opts }) = .{}; - - /// Attempt to retrieve the value of the environment variable for the current platform, if - /// the current platform has a supported definition. Returns null otherwise, unlike the - /// other methods which will fail at compile time if the platform is unsupported. - pub fn platformGet() ?ValueType { - // Get the platform-specific key - const platform_key: ?KeyType = if (comptime bun.Environment.isPosix) - posix_key - else if (comptime bun.Environment.isWindows) - windows_key - else - null; - - // If platform doesn't have a key, return null - const k = platform_key orelse return null; - - // Inline the logic from get() without calling assertPlatformSupported() - switch (cache.getCached()) { - .unknown => { - @branchHint(.unlikely); - - const env_var = bun.getenvZ(k); - const maybe_reloaded = cache.deserAndInvalidate(env_var); - - if (maybe_reloaded) |v| return v; - if (opts.default) |d| { - return d; - } - - return null; - }, - .not_set => { - if (opts.default) |d| { - return d; - } - return null; - }, - .value => |v| return v, - } - } - - /// Equal to `.platformKey()` except fails to compile if current platform is supported. - pub fn key() KeyType { - assertPlatformSupported(); - return Self.platformKey().?; - } - - /// Retrieve the key of the environment variable for the current platform, if any. - pub fn platformKey() ?KeyType { - if (bun.Environment.isPosix) { - return posix_key; - } - - if (bun.Environment.isWindows) { - return windows_key; - } - - return null; - } - - pub fn getNotEmpty() ReturnType { - if (Self.get()) |v| { - if (v.len == 0) { - return null; - } - return v; - } - return null; - } - - /// Retrieve the value of the environment variable, loading it if necessary. - /// Fails if the current platform is unsupported. - pub fn get() ReturnType { - assertPlatformSupported(); - - const cached_result = cache.getCached(); - - switch (cached_result) { - .unknown => { - @branchHint(.unlikely); - return getForceReload(); - }, - .not_set => { - if (opts.default) |d| { - return d; - } - return null; - }, - .value => |v| { - return v; - }, - } - } - - /// Retrieve the value of the environment variable, reloading it from the environment. - /// Fails if the current platform is unsupported. - fn getForceReload() ReturnType { - assertPlatformSupported(); - const env_var = bun.getenvZ(key()); - const maybe_reloaded = cache.deserAndInvalidate(env_var); - - if (maybe_reloaded) |v| { - return v; - } - - if (opts.default) |d| { - return d; - } - - return null; - } - - /// Fetch the default value of this environment variable, if any. - /// - /// It is safe to compare the result of .get() to default to test if the variable is set to - /// its default value. - pub const default: DefaultType = if (opts.default) |d| d else {}; - - fn assertPlatformSupported() void { - const missing_key_fmt = "Cannot retrieve the value of " ++ comptime_key ++ - " for {s} since no {s} key is associated with it."; - if (comptime bun.Environment.isWindows and windows_key == null) { - @compileError(std.fmt.comptimePrint(missing_key_fmt, .{ "Windows", "Windows" })); - } else if (comptime bun.Environment.isPosix and posix_key == null) { - @compileError(std.fmt.comptimePrint(missing_key_fmt, .{ "POSIX", "POSIX" })); - } - } - }; -} - -const FeatureFlagOpts = struct { - default: ?bool = false, -}; - -fn newFeatureFlag(comptime env_var: [:0]const u8, comptime opts: FeatureFlagOpts) type { - return New(kind.boolean, env_var, .{ .default = opts.default }); -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bun_core/feature_flags.zig b/src/bun_core/feature_flags.zig deleted file mode 100644 index a45df7a9a2d3..000000000000 --- a/src/bun_core/feature_flags.zig +++ /dev/null @@ -1,145 +0,0 @@ -//! If you are adding feature-flags to this file, you are in the wrong spot. Go to env_var.zig -//! instead. - -/// Enable breaking changes for the next major release of Bun -// TODO: Make this a CLI flag / runtime var so that we can verify disabled code paths can compile -pub const breaking_changes_1_4 = false; - -/// Store and reuse file descriptors during module resolution -/// This was a ~5% performance improvement -pub const store_file_descriptors = !env.isBrowser; - -pub const tracing = true; - -pub const css_supports_fence = true; - -pub const enable_entry_cache = true; - -// TODO: remove this flag, it should use bun.Output.scoped -pub const verbose_fs = false; - -pub const watch_directories = true; - -// This feature flag exists so when you have defines inside package.json, you can use single quotes in nested strings. -pub const allow_json_single_quotes = true; - -pub const is_macro_enabled = !env.isWasm and !env.isWasi; - -pub const disable_compression_in_http_client = false; - -pub const enable_keepalive = true; - -pub const atomic_file_watcher = env.isLinux; - -pub const http_buffer_pooling = true; - -pub const disable_lolhtml = false; - -/// There is, what I think is, a bug in getaddrinfo() -/// on macOS that specifically impacts localhost and not -/// other ipv4 hosts. This is a workaround for that. -/// "localhost" fails to connect. -pub const hardcode_localhost_to_127_0_0_1 = false; - -/// React will issue warnings in development if there are multiple children -/// without keys and "jsxs" is not used. -/// https://github.com/oven-sh/bun/issues/10733 -pub const support_jsxs_in_jsx_transform = true; - -pub const use_simdutf = bun.Environment.isNative; - -pub const inline_properties_in_transpiler = true; - -pub const same_target_becomes_destructuring = true; - -pub const help_catch_memory_issues = bun.Environment.enable_asan or bun.Environment.isDebug; - -/// This performs similar transforms as https://github.com/rollup/plugins/tree/master/packages/commonjs -/// -/// Though, not exactly the same. -/// -/// There are two scenarios where this kicks in: -/// -/// 1) You import a CommonJS module using ESM. -/// -/// Semantically, CommonJS expects us to wrap everything in a closure. That -/// bloats the code. We want to make the generated code as small as we can. -/// -/// To avoid that, we attempt to unwrap the CommonJS module into ESM. -/// -/// But, we can't always do that. When you have cyclical require() or directly -/// mutate exported bindings, we can't unwrap it. -/// -/// However, in the simple case, where you do something like -/// -/// exports.foo = 123; -/// exports.bar = 456; -/// -/// We can unwrap it into -/// -/// export const foo = 123; -/// export const bar = 456; -/// -/// 2) You import a CommonJS module using CommonJS. -/// -/// This is a bit more complicated. We want to avoid the closure wrapper, but -/// it's really difficult to track down all the places where you mutate the -/// exports object. `require.cache` makes it even more complicated. -/// So, we just wrap the entire module in a closure. -/// -/// But what if we previously unwrapped it? -/// -/// In that case, we wrap it again in the printer. -pub const unwrap_commonjs_to_esm = true; - -/// https://sentry.engineering/blog/the-case-for-debug-ids -/// https://github.com/mitsuhiko/source-map-rfc/blob/proposals/debug-id/proposals/debug-id.md -/// https://github.com/source-map/source-map-rfc/pull/20 -pub const source_map_debug_id = true; - -pub const export_star_redirect = false; - -pub const streaming_file_uploads_for_http_client = true; - -pub const concurrent_transpiler = true; - -// https://github.com/oven-sh/bun/issues/5426#issuecomment-1813865316 -pub const disable_auto_js_to_ts_in_node_modules = true; - -pub const runtime_transpiler_cache = true; - -/// On Windows, node_modules/.bin uses pairs of '.exe' + '.bunx' files. The -/// fast path is to load the .bunx file within `bun.exe` instead of -/// `bun_shim_impl.exe` by using `bun_shim_impl.tryStartupFromBunJS` -/// -/// When debugging weird script runner issues, it may be worth disabling this in -/// order to isolate your bug. -pub const windows_bunx_fast_path = true; - -// TODO: fix Windows-only test failures in fetch-preconnect.test.ts -pub const is_fetch_preconnect_supported = env.isPosix; - -pub const libdeflate_supported = env.isNative; - -// Mostly exists as a way to turn it off later, if necessary. -pub fn isLibdeflateEnabled() bool { - if (!libdeflate_supported) { - return false; - } - - return !bun.feature_flag.BUN_FEATURE_FLAG_NO_LIBDEFLATE.get(); -} - -/// Enable the "app" option in Bun.serve. This option will likely be removed -/// in favor of HTML loaders and configuring framework options in bunfig.toml -pub fn bake() bool { - // In canary or if an environment variable is specified. - return env.is_canary or env.isDebug or bun.feature_flag.BUN_FEATURE_FLAG_EXPERIMENTAL_BAKE.get(); -} - -/// Additional debugging features for bake.DevServer, such as the incremental visualizer. -/// To use them, extra flags are passed in addition to this one. -pub const bake_debugging_features = env.is_canary or env.isDebug; - -const bun = @import("bun"); -const env = @import("./env.zig"); diff --git a/src/bun_core/fmt.zig b/src/bun_core/fmt.zig deleted file mode 100644 index 42f1b0a9a48a..000000000000 --- a/src/bun_core/fmt.zig +++ /dev/null @@ -1,1863 +0,0 @@ -pub const TableSymbols = struct { - enable_ansi_colors: bool, - - pub const unicode = TableSymbols{ .enable_ansi_colors = true }; - pub const ascii = TableSymbols{ .enable_ansi_colors = false }; - - pub fn topLeftSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "┌" else "|"; - } - pub fn topRightSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "┐" else "|"; - } - pub fn topColumnSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "┬" else "-"; - } - - pub fn bottomLeftSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "└" else "|"; - } - pub fn bottomRightSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "┘" else "|"; - } - pub fn bottomColumnSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "┴" else "-"; - } - - pub fn middleLeftSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "├" else "|"; - } - pub fn middleRightSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "┤" else "|"; - } - pub fn middleColumnSep(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "┼" else "|"; - } - - pub fn horizontalEdge(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "─" else "-"; - } - pub fn verticalEdge(comptime s: TableSymbols) []const u8 { - return if (s.enable_ansi_colors) "│" else "|"; - } -}; - -pub fn Table( - comptime column_color: []const u8, - comptime column_left_pad: usize, - comptime column_right_pad: usize, - comptime enable_ansi_colors: bool, -) type { - const symbols = TableSymbols{ .enable_ansi_colors = enable_ansi_colors }; - return struct { - column_names: []const []const u8, - column_inside_lengths: []const usize, - - comptime symbols: TableSymbols = symbols, - - pub fn init(column_names_: []const []const u8, column_inside_lengths_: []const usize) @This() { - return .{ - .column_names = column_names_, - .column_inside_lengths = column_inside_lengths_, - }; - } - - pub fn printTopLineSeparator(this: *const @This()) void { - this.printLine(symbols.topLeftSep(), symbols.topRightSep(), symbols.topColumnSep()); - } - - pub fn printBottomLineSeparator(this: *const @This()) void { - this.printLine(symbols.bottomLeftSep(), symbols.bottomRightSep(), symbols.bottomColumnSep()); - } - - pub fn printLineSeparator(this: *const @This()) void { - this.printLine(symbols.middleLeftSep(), symbols.middleRightSep(), symbols.middleColumnSep()); - } - - pub fn printLine(this: *const @This(), left_edge_separator: string, right_edge_separator: string, column_separator: string) void { - for (this.column_inside_lengths, 0..) |column_inside_length, i| { - if (i == 0) { - Output.pretty("{s}", .{left_edge_separator}); - } else { - Output.pretty("{s}", .{column_separator}); - } - - for (0..column_left_pad + column_inside_length + column_right_pad) |_| Output.pretty("{s}", .{symbols.horizontalEdge()}); - - if (i == this.column_inside_lengths.len - 1) { - Output.pretty("{s}\n", .{right_edge_separator}); - } - } - } - - pub fn printColumnNames(this: *const @This()) void { - for (this.column_inside_lengths, 0..) |column_inside_length, i| { - Output.pretty("{s}", .{symbols.verticalEdge()}); - for (0..column_left_pad) |_| Output.pretty(" ", .{}); - Output.pretty("<" ++ column_color ++ ">{s}", .{this.column_names[i]}); - for (this.column_names[i].len..column_inside_length + column_right_pad) |_| Output.pretty(" ", .{}); - if (i == this.column_inside_lengths.len - 1) { - Output.pretty("{s}\n", .{symbols.verticalEdge()}); - } - } - } - }; -} - -pub const RedactedNpmUrlFormatter = struct { - url: string, - - pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - var i: usize = 0; - while (i < this.url.len) { - if (strings.startsWithUUID(this.url[i..])) { - try writer.writeAll("***"); - i += 36; - continue; - } - - const npm_secret_len = strings.startsWithNpmSecret(this.url[i..]); - if (npm_secret_len > 0) { - try writer.writeAll("***"); - i += npm_secret_len; - continue; - } - - // TODO: redact password from `https://username:password@registry.com/` - - try writer.writeByte(this.url[i]); - i += 1; - } - } -}; - -pub fn redactedNpmUrl(str: string) RedactedNpmUrlFormatter { - return .{ - .url = str, - }; -} - -pub const RedactedSourceFormatter = struct { - text: string, - - pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - var i: usize = 0; - while (i < this.text.len) { - if (strings.startsWithSecret(this.text[i..])) |secret| { - const offset, const len = secret; - try writer.writeAll(this.text[i..][0..offset]); - try writer.splatByteAll('*', len); - i += offset + len; - continue; - } - - try writer.writeByte(this.text[i]); - i += 1; - } - } -}; - -pub fn redactedSource(str: string) RedactedSourceFormatter { - return .{ - .text = str, - }; -} - -// https://github.com/npm/cli/blob/63d6a732c3c0e9c19fd4d147eaa5cc27c29b168d/node_modules/npm-package-arg/lib/npa.js#L163 -pub const DependencyUrlFormatter = struct { - url: string, - - pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - var remain = this.url; - while (strings.indexOfChar(remain, '/')) |slash| { - try writer.writeAll(remain[0..slash]); - try writer.writeAll("%2f"); - remain = remain[slash + 1 ..]; - } - try writer.writeAll(remain); - } -}; - -pub fn dependencyUrl(url: string) DependencyUrlFormatter { - return .{ - .url = url, - }; -} - -const IntegrityFormatStyle = enum { - short, - full, -}; - -pub fn IntegrityFormatter(comptime style: IntegrityFormatStyle) type { - return struct { - bytes: [sha.SHA512.digest]u8, - - pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - var buf: [std.base64.standard.Encoder.calcSize(sha.SHA512.digest)]u8 = undefined; - const count = bun.simdutf.base64.encode(this.bytes[0..sha.SHA512.digest], &buf, false); - - const encoded = buf[0..count]; - - if (comptime style == .short) - try writer.print("sha512-{s}[...]{s}", .{ encoded[0..13], encoded[encoded.len - 15 ..] }) - else - try writer.print("sha512-{s}", .{encoded}); - } - }; -} - -pub fn integrity(bytes: [sha.SHA512.digest]u8, comptime style: IntegrityFormatStyle) IntegrityFormatter(style) { - return .{ .bytes = bytes }; -} - -const JSONFormatter = struct { - input: []const u8, - - pub fn format(self: JSONFormatter, writer: *std.Io.Writer) !void { - try bun.js_printer.writeJSONString(self.input, @TypeOf(writer), writer, .latin1); - } -}; - -const JSONFormatterUTF8 = struct { - input: []const u8, - opts: Options, - - pub const Options = struct { - quote: bool = true, - }; - - pub fn format(self: JSONFormatterUTF8, writer: *std.Io.Writer) !void { - if (self.opts.quote) { - try bun.js_printer.writeJSONString(self.input, @TypeOf(writer), writer, .utf8); - } else { - try bun.js_printer.writePreQuotedString(self.input, @TypeOf(writer), writer, '"', false, true, .utf8); - } - } -}; - -/// Expects latin1 -pub fn formatJSONStringLatin1(text: []const u8) JSONFormatter { - return .{ .input = text }; -} - -pub fn formatJSONStringUTF8(text: []const u8, opts: JSONFormatterUTF8.Options) JSONFormatterUTF8 { - return .{ .input = text, .opts = opts }; -} - -const SharedTempBuffer = [32 * 1024]u8; -fn getSharedBuffer() []u8 { - return std.mem.asBytes(shared_temp_buffer_ptr orelse brk: { - shared_temp_buffer_ptr = bun.default_allocator.create(SharedTempBuffer) catch unreachable; - break :brk shared_temp_buffer_ptr.?; - }); -} -threadlocal var shared_temp_buffer_ptr: ?*SharedTempBuffer = null; - -pub fn formatUTF16Type(slice_: []const u16, writer: *std.Io.Writer) !void { - var chunk = getSharedBuffer(); - - // Defensively ensure recursion doesn't cause the buffer to be overwritten in-place - shared_temp_buffer_ptr = null; - defer { - if (shared_temp_buffer_ptr) |existing| { - if (existing != chunk.ptr) { - bun.default_allocator.destroy(@as(*SharedTempBuffer, @ptrCast(chunk.ptr))); - } - } else { - shared_temp_buffer_ptr = @ptrCast(chunk.ptr); - } - } - - var slice = slice_; - - while (slice.len > 0) { - const result = strings.copyUTF16IntoUTF8(chunk, slice); - if (result.read == 0 or result.written == 0) - break; - try writer.writeAll(chunk[0..result.written]); - slice = slice[result.read..]; - } -} - -pub fn formatUTF16TypeWithPathOptions(slice_: []const u16, writer: *std.Io.Writer, opts: PathFormatOptions) !void { - var chunk = getSharedBuffer(); - - // Defensively ensure recursion doesn't cause the buffer to be overwritten in-place - shared_temp_buffer_ptr = null; - defer { - if (shared_temp_buffer_ptr) |existing| { - if (existing != chunk.ptr) { - bun.default_allocator.destroy(@as(*SharedTempBuffer, @ptrCast(chunk.ptr))); - } - } else { - shared_temp_buffer_ptr = @ptrCast(chunk.ptr); - } - } - - var slice = slice_; - - while (slice.len > 0) { - const result = strings.copyUTF16IntoUTF8(chunk, slice); - if (result.read == 0 or result.written == 0) - break; - - const to_write = chunk[0..result.written]; - if (!opts.escape_backslashes and opts.path_sep == .any) { - try writer.writeAll(to_write); - } else { - var ptr = to_write; - while (strings.indexOfAny(ptr, "\\/")) |i| { - const sep = switch (opts.path_sep) { - .windows => '\\', - .posix => '/', - .auto => std.fs.path.sep, - .any => ptr[i], - }; - try writer.writeAll(ptr[0..i]); - try writer.writeByte(sep); - if (opts.escape_backslashes and sep == '\\') { - try writer.writeByte(sep); - } - - ptr = ptr[i + 1 ..]; - } - try writer.writeAll(ptr); - } - slice = slice[result.read..]; - } -} - -pub inline fn utf16(slice_: []const u16) FormatUTF16 { - return FormatUTF16{ .buf = slice_ }; -} - -/// Debug, this does not handle invalid utf32 -pub inline fn debugUtf32PathFormatter(path: []const u32) DebugUTF32PathFormatter { - return DebugUTF32PathFormatter{ .path = path }; -} - -pub const DebugUTF32PathFormatter = struct { - path: []const u32, - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - var path_buf: bun.PathBuffer = undefined; - const result = bun.simdutf.convert.utf32.to.utf8.with_errors.le(this.path, &path_buf); - const converted = if (result.isSuccessful()) - path_buf[0..result.count] - else - "Invalid UTF32!"; - - try writer.writeAll(converted); - } -}; - -pub const FormatUTF16 = struct { - buf: []const u16, - path_fmt_opts: ?PathFormatOptions = null, - pub fn format(self: @This(), writer: *std.Io.Writer) !void { - if (self.path_fmt_opts) |opts| { - try formatUTF16TypeWithPathOptions(self.buf, writer, opts); - } else { - try formatUTF16Type(self.buf, writer); - } - } -}; - -pub const FormatUTF8 = struct { - buf: []const u8, - path_fmt_opts: ?PathFormatOptions = null, - pub fn format(self: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - if (self.path_fmt_opts) |opts| { - if (opts.path_sep == .any and opts.escape_backslashes == false) { - try writer.writeAll(self.buf); - return; - } - - var ptr = self.buf; - while (strings.indexOfAny(ptr, "\\/")) |i| { - const sep = switch (opts.path_sep) { - .windows => '\\', - .posix => '/', - .auto => std.fs.path.sep, - .any => ptr[i], - }; - try writer.writeAll(ptr[0..i]); - try writer.writeByte(sep); - if (opts.escape_backslashes and sep == '\\') { - try writer.writeByte(sep); - } - ptr = ptr[i + 1 ..]; - } - - try writer.writeAll(ptr); - return; - } - - try writer.writeAll(self.buf); - } -}; - -pub const PathFormatOptions = struct { - // The path separator used when formatting the path. - path_sep: Sep = .any, - - /// Any backslashes are escaped, including backslashes - /// added through `path_sep`. - escape_backslashes: bool = false, - - pub const Sep = enum { - /// Keep paths separators as is. - any, - /// Replace all path separators with the current platform path separator. - auto, - /// Replace all path separators with `/`. - posix, - /// Replace all path separators with `\`. - windows, - }; -}; - -pub const FormatOSPath = if (Environment.isWindows) FormatUTF16 else FormatUTF8; - -pub fn fmtOSPath(buf: bun.OSPathSlice, options: PathFormatOptions) FormatOSPath { - return FormatOSPath{ - .buf = buf, - .path_fmt_opts = options, - }; -} - -pub fn fmtPath( - comptime T: type, - path: []const T, - options: PathFormatOptions, -) if (T == u8) FormatUTF8 else FormatUTF16 { - if (T == u8) { - return FormatUTF8{ - .buf = path, - .path_fmt_opts = options, - }; - } - - return FormatUTF16{ - .buf = path, - .path_fmt_opts = options, - }; -} - -pub fn formatLatin1(slice_: []const u8, writer: *std.Io.Writer) !void { - var chunk = getSharedBuffer(); - var slice = slice_; - - // Defensively ensure recursion doesn't cause the buffer to be overwritten in-place - shared_temp_buffer_ptr = null; - defer { - if (shared_temp_buffer_ptr) |existing| { - if (existing != chunk.ptr) { - bun.default_allocator.destroy(@as(*SharedTempBuffer, @ptrCast(chunk.ptr))); - } - } else { - shared_temp_buffer_ptr = @ptrCast(chunk.ptr); - } - } - - while (strings.firstNonASCII(slice)) |i| { - if (i > 0) { - try writer.writeAll(slice[0..i]); - slice = slice[i..]; - } - const result = strings.copyLatin1IntoUTF8(chunk, slice[0..@min(chunk.len, slice.len)]); - if (result.read == 0 or result.written == 0) - break; - try writer.writeAll(chunk[0..result.written]); - slice = slice[result.read..]; - } - - if (slice.len > 0) - try writer.writeAll(slice); // write the remaining bytes -} - -pub const URLFormatter = struct { - proto: Proto = .http, - hostname: ?string = null, - port: ?u16 = null, - - const Proto = enum { - http, - https, - unix, - abstract, - }; - - pub fn format(this: URLFormatter, writer: *std.Io.Writer) !void { - try writer.print("{s}://", .{switch (this.proto) { - .http => "http", - .https => "https", - .unix => "unix", - .abstract => "abstract", - }}); - - if (this.hostname) |hostname| { - const needs_brackets = hostname[0] != '[' and strings.isIPV6Address(hostname); - if (needs_brackets) { - try writer.print("[{s}]", .{hostname}); - } else { - try writer.writeAll(hostname); - } - } else { - try writer.writeAll("localhost"); - } - - if (this.proto == .unix) { - return; - } - - const is_port_optional = this.port == null or (this.proto == .https and this.port == 443) or - (this.proto == .http and this.port == 80); - if (is_port_optional) { - try writer.writeAll("/"); - } else { - try writer.print(":{d}/", .{this.port.?}); - } - } -}; - -pub const HostFormatter = struct { - host: string, - port: ?u16 = null, - is_https: bool = false, - - pub fn format(formatter: HostFormatter, writer: *std.Io.Writer) !void { - if (strings.indexOfChar(formatter.host, ':') != null) { - try writer.writeAll(formatter.host); - return; - } - - try writer.writeAll(formatter.host); - - const is_port_optional = formatter.port == null or (formatter.is_https and formatter.port == 443) or - (!formatter.is_https and formatter.port == 80); - if (!is_port_optional) { - try writer.print(":{d}", .{formatter.port.?}); - return; - } - } -}; - -/// Format a string to an ECMAScript identifier. -/// Unlike the string_mutable.zig version, this always allocate/copy -pub fn fmtIdentifier(name: string) FormatValidIdentifier { - return FormatValidIdentifier{ .name = name }; -} - -/// Format a string to an ECMAScript identifier. -/// Different implementation than string_mutable because string_mutable may avoid allocating -/// This will always allocate -pub const FormatValidIdentifier = struct { - name: string, - pub fn format(self: FormatValidIdentifier, writer: *std.Io.Writer) !void { - var iterator = strings.CodepointIterator.init(self.name); - var cursor = strings.CodepointIterator.Cursor{}; - - var has_needed_gap = false; - var needs_gap = false; - var start_i: usize = 0; - - if (!iterator.next(&cursor)) { - try writer.writeAll("_"); - return; - } - - // Common case: no gap necessary. No allocation necessary. - needs_gap = !js_lexer.isIdentifierStart(cursor.c); - if (!needs_gap) { - // Are there any non-alphanumeric chars at all? - while (iterator.next(&cursor)) { - if (!js_lexer.isIdentifierContinue(cursor.c) or cursor.width > 1) { - needs_gap = true; - start_i = cursor.i; - break; - } - } - } - - if (needs_gap) { - needs_gap = false; - if (start_i > 0) try writer.writeAll(self.name[0..start_i]); - var slice = self.name[start_i..]; - iterator = strings.CodepointIterator.init(slice); - cursor = strings.CodepointIterator.Cursor{}; - - while (iterator.next(&cursor)) { - if (js_lexer.isIdentifierContinue(cursor.c) and cursor.width == 1) { - if (needs_gap) { - try writer.writeAll("_"); - needs_gap = false; - has_needed_gap = true; - } - try writer.writeAll(slice[cursor.i .. cursor.i + @as(u32, cursor.width)]); - } else if (!needs_gap) { - needs_gap = true; - // skip the code point, replace it with a single _ - } - } - - // If it ends with an emoji - if (needs_gap) { - try writer.writeAll("_"); - needs_gap = false; - has_needed_gap = true; - } - - return; - } - - try writer.writeAll(self.name); - } -}; - -// Formats a string to be safe to output in a Github action. -// - Encodes "\n" as "%0A" to support multi-line strings. -// https://github.com/actions/toolkit/issues/193#issuecomment-605394935 -// - Strips ANSI output as it will appear malformed. -pub fn githubActionWriter(writer: *std.Io.Writer, self: string) !void { - var offset: usize = 0; - const end = @as(u32, @truncate(self.len)); - while (offset < end) { - if (strings.indexOfNewlineOrNonASCIIOrANSI(self, @as(u32, @truncate(offset)))) |i| { - const byte = self[i]; - if (byte > 0x7F) { - offset += @max(strings.wtf8ByteSequenceLength(byte), 1); - continue; - } - if (i > 0) { - try writer.writeAll(self[offset..i]); - } - var n: usize = 1; - if (byte == '\n') { - try writer.writeAll("%0A"); - } else if (i + 1 < end) { - const next = self[i + 1]; - if (byte == '\r' and next == '\n') { - n += 1; - try writer.writeAll("%0A"); - } else if (byte == '\x1b' and next == '[') { - n += 1; - if (i + 2 < end) { - const remain = self[(i + 2)..@min(i + 5, end)]; - if (strings.indexOfChar(remain, 'm')) |j| { - n += j + 1; - } - } - } - } - offset = i + n; - } else { - try writer.writeAll(self[offset..end]); - break; - } - } -} - -pub const GithubActionFormatter = struct { - text: string, - - pub fn format(this: GithubActionFormatter, writer: *std.Io.Writer) !void { - try githubActionWriter(writer, this.text); - } -}; - -pub fn githubAction(self: string) strings.GithubActionFormatter { - return GithubActionFormatter{ - .text = self, - }; -} - -pub fn quotedWriter(writer: *std.Io.Writer, self: string) !void { - const remain = self; - if (strings.containsNewlineOrNonASCIIOrQuote(remain)) { - try bun.js_printer.writeJSONString(self, @TypeOf(writer), writer, strings.Encoding.utf8); - } else { - try writer.writeAll("\""); - try writer.writeAll(self); - try writer.writeAll("\""); - } -} - -pub const QuotedFormatter = struct { - text: []const u8, - - pub fn format(this: QuotedFormatter, writer: *std.Io.Writer) !void { - try quotedWriter(writer, this.text); - } -}; - -pub fn fmtJavaScript(text: []const u8, opts: QuickAndDirtyJavaScriptSyntaxHighlighter.Options) QuickAndDirtyJavaScriptSyntaxHighlighter { - return QuickAndDirtyJavaScriptSyntaxHighlighter{ - .text = text, - .opts = opts, - }; -} - -pub const QuickAndDirtyJavaScriptSyntaxHighlighter = struct { - text: []const u8, - opts: Options, - - pub const Options = struct { - enable_colors: bool, - check_for_unhighlighted_write: bool = true, - - redact_sensitive_information: bool = false, - }; - - const ColorCode = enum { - magenta, - blue, - orange, - red, - pink, - - pub fn color(this: ColorCode) []const u8 { - return switch (this) { - .magenta => "\x1b[35m", - .blue => "\x1b[34m", - .orange => "\x1b[33m", - .red => "\x1b[31m", - // light pink - .pink => "\x1b[38;5;206m", - }; - } - }; - - pub const Keyword = enum { - abstract, - as, - async, - await, - case, - @"catch", - class, - @"const", - @"continue", - debugger, - default, - delete, - do, - @"else", - @"enum", - @"export", - extends, - false, - finally, - @"for", - function, - @"if", - implements, - import, - in, - instanceof, - interface, - let, - new, - null, - package, - private, - protected, - public, - @"return", - static, - super, - @"switch", - this, - throw, - @"break", - true, - @"try", - type, - typeof, - @"var", - void, - @"while", - with, - yield, - string, - number, - boolean, - symbol, - any, - object, - unknown, - never, - namespace, - declare, - readonly, - undefined, - - pub fn colorCode(this: Keyword) ColorCode { - return switch (this) { - .abstract => .blue, - .as => .blue, - .async => .magenta, - .await => .magenta, - .case => .magenta, - .@"catch" => .magenta, - .class => .magenta, - .@"const" => .magenta, - .@"continue" => .magenta, - .debugger => .magenta, - .default => .magenta, - .delete => .red, - .do => .magenta, - .@"else" => .magenta, - .@"break" => .magenta, - .undefined => .orange, - .@"enum" => .blue, - .@"export" => .magenta, - .extends => .magenta, - .false => .orange, - .finally => .magenta, - .@"for" => .magenta, - .function => .magenta, - .@"if" => .magenta, - .implements => .blue, - .import => .magenta, - .in => .magenta, - .instanceof => .magenta, - .interface => .blue, - .let => .magenta, - .new => .magenta, - .null => .orange, - .package => .magenta, - .private => .blue, - .protected => .blue, - .public => .blue, - .@"return" => .magenta, - .static => .magenta, - .super => .magenta, - .@"switch" => .magenta, - .this => .orange, - .throw => .magenta, - .true => .orange, - .@"try" => .magenta, - .type => .blue, - .typeof => .magenta, - .@"var" => .magenta, - .void => .magenta, - .@"while" => .magenta, - .with => .magenta, - .yield => .magenta, - .string => .blue, - .number => .blue, - .boolean => .blue, - .symbol => .blue, - .any => .blue, - .object => .blue, - .unknown => .blue, - .never => .blue, - .namespace => .blue, - .declare => .blue, - .readonly => .blue, - }; - } - }; - - pub const Keywords = bun.ComptimeEnumMap(Keyword); - - pub const RedactedKeyword = enum { - _auth, - _authToken, - token, - _password, - email, - }; - - pub const RedactedKeywords = bun.ComptimeEnumMap(RedactedKeyword); - - pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - var text = this.text; - if (this.opts.check_for_unhighlighted_write) { - if (!this.opts.enable_colors or text.len > 2048 or text.len == 0 or !strings.isAllASCII(text)) { - if (this.opts.redact_sensitive_information) { - try writer.print("{f}", .{redactedSource(text)}); - } else { - try writer.writeAll(text); - } - return; - } - } - - var prev_keyword: ?Keyword = null; - var should_redact_value = false; - - outer: while (text.len > 0) { - if (js_lexer.isIdentifierStart(text[0])) { - var i: usize = 1; - - while (i < text.len and js_lexer.isIdentifierContinue(text[i])) { - i += 1; - } - - if (Keywords.get(text[0..i])) |keyword| { - should_redact_value = false; - if (keyword != .as) - prev_keyword = keyword; - const code = keyword.colorCode(); - try writer.print(Output.prettyFmt("{s}{s}", true), .{ code.color(), text[0..i] }); - } else { - should_redact_value = this.opts.redact_sensitive_information and RedactedKeywords.has(text[0..i]); - write: { - if (prev_keyword) |prev| { - switch (prev) { - .new => { - prev_keyword = null; - - if (i < text.len and text[i] == '(') { - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - break :write; - } - }, - .abstract, .namespace, .declare, .type, .interface => { - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - prev_keyword = null; - break :write; - }, - .import => { - if (strings.eqlComptime(text[0..i], "from")) { - const code = ColorCode.magenta; - try writer.print(Output.prettyFmt("{s}{s}", true), .{ code.color(), text[0..i] }); - prev_keyword = null; - - break :write; - } - }, - else => {}, - } - } - - try writer.writeAll(text[0..i]); - } - } - text = text[i..]; - } else { - if (this.opts.redact_sensitive_information and should_redact_value) { - while (text.len > 0 and std.ascii.isWhitespace(text[0])) { - try writer.writeByte(text[0]); - text = text[1..]; - } - - // A redacted keyword followed by nothing but whitespace: - // the loop above consumed the rest of the input, so there - // is no value left to redact (`text[0]` below would be out - // of bounds). - if (text.len == 0) return; - - if (text[0] == '=' or text[0] == ':') { - try writer.writeByte(text[0]); - text = text[1..]; - while (text.len > 0 and std.ascii.isWhitespace(text[0])) { - try writer.writeByte(text[0]); - text = text[1..]; - } - - if (text.len == 0) return; - } - } - - switch (text[0]) { - '0'...'9' => |num| { - if (this.opts.redact_sensitive_information) { - if (should_redact_value) { - should_redact_value = false; - const end = strings.indexOfChar(text, '\n') orelse text.len; - text = text[end..]; - try writer.writeAll(Output.prettyFmt("***", true)); - continue; - } - - if (strings.startsWithUUID(text)) { - text = text[36..]; - try writer.writeAll(Output.prettyFmt("***", true)); - continue; - } - } - - prev_keyword = null; - var i: usize = 1; - if (text.len > 1 and num == '0' and text[1] == 'x') { - i += 1; - while (i < text.len and switch (text[i]) { - '0'...'9', 'a'...'f', 'A'...'F' => true, - else => false, - }) { - i += 1; - } - } else { - while (i < text.len and switch (text[i]) { - '0'...'9', '.', 'e', 'E', 'x', 'X', 'b', 'B', 'o', 'O' => true, - else => false, - }) { - i += 1; - } - } - - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - text = text[i..]; - }, - inline '`', '"', '\'' => |char| { - prev_keyword = null; - - var i: usize = 1; - while (i < text.len and text[i] != char) { - // if we're redacting, no need to syntax highlight contents - if (!should_redact_value and char == '`') { - if (text[i] == '$' and i + 1 < text.len and text[i + 1] == '{') { - const curly_start = i; - i += 2; - - while (i < text.len and text[i] != '}') { - if (i + 1 < text.len and text[i] == '\\') { - i += 1; - } - i += 1; - } - - try writer.print(Output.prettyFmt("{s}", true), .{text[0..curly_start]}); - try writer.writeAll("${"); - var opts = this.opts; - opts.check_for_unhighlighted_write = false; - const curly_remain = QuickAndDirtyJavaScriptSyntaxHighlighter{ - .text = text[curly_start + 2 .. i], - .opts = opts, - }; - - if (curly_remain.text.len > 0) { - try curly_remain.format(writer); - } - - if (i < text.len and text[i] == '}') { - try writer.writeAll("}"); - i += 1; - } - text = text[i..]; - i = 0; - if (text.len > 0 and text[0] == char) { - try writer.writeAll(Output.prettyFmt("`", true)); - text = text[1..]; - continue :outer; - } - continue; - } - } - - if (i + 1 < text.len and text[i] == '\\') { - i += 1; - } - - i += 1; - } - - // Include the trailing quote, if any - i += @intFromBool(i < text.len); - - if (should_redact_value) { - should_redact_value = false; - if (i > 2 and text[i - 1] == char) { - const len = text[0..i].len - 2; - try writer.print(Output.prettyFmt("{c}", true), .{char}); - try writer.splatByteAll('*', len); - try writer.print(Output.prettyFmt("{c}", true), .{char}); - } else { - try writer.splatByteAll('*', text[0..i].len); - } - text = text[i..]; - continue; - } else if (this.opts.redact_sensitive_information) { - try_redact: { - // `i == 0` happens when a `${...}` interpolation ended - // exactly at the end of the input: the scan loop above - // resets `i` to 0 and exits with `text` empty, so there - // is no quoted content to inspect (`text[1..0]` would - // be out of range). - if (i == 0) break :try_redact; - var inner = text[1..i]; - if (inner.len > 0 and inner[inner.len - 1] == char) { - inner = inner[0 .. inner.len - 1]; - } - - if (inner.len == 0) { - break :try_redact; - } - - if (inner.len == 36 and strings.isUUID(inner)) { - try writer.print(Output.prettyFmt("{c}", true), .{char}); - try writer.splatByteAll('*', 36); - try writer.print(Output.prettyFmt("{c}", true), .{char}); - text = text[i..]; - continue; - } - - const npm_secret_len = strings.startsWithNpmSecret(inner); - if (npm_secret_len != 0) { - try writer.print(Output.prettyFmt("{c}", true), .{char}); - try writer.splatByteAll('*', npm_secret_len); - try writer.print(Output.prettyFmt("{c}", true), .{char}); - text = text[i..]; - continue; - } - - if (strings.findUrlPassword(inner)) |url_pass| { - const offset, const len = url_pass; - try writer.print(Output.prettyFmt("{c}{s}", true), .{ - char, - inner[0..offset], - }); - try writer.splatByteAll('*', len); - try writer.print(Output.prettyFmt("{s}{c}", true), .{ - inner[offset + len ..], - char, - }); - text = text[i..]; - continue; - } - } - - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - text = text[i..]; - continue; - } - - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - text = text[i..]; - }, - '/' => { - prev_keyword = null; - - if (should_redact_value) { - should_redact_value = false; - const len = strings.indexOfChar(text, '\n') orelse text.len; - try writer.splatByteAll('*', len); - text = text[len..]; - continue; - } - - var i: usize = 1; - - // the start of a line comment - if (i < text.len and text[i] == '/') { - while (i < text.len and text[i] != '\n') { - i += 1; - } - - const remain_to_print = text[0..i]; - if (i < text.len and text[i] == '\n') { - i += 1; - } - - if (i < text.len and text[i] == '\r') { - i += 1; - } - - if (this.opts.redact_sensitive_information) { - try writer.print(Output.prettyFmt("{f}", true), .{redactedSource(remain_to_print)}); - } else { - try writer.print(Output.prettyFmt("{s}", true), .{remain_to_print}); - } - text = text[i..]; - continue; - } - - as_multiline_comment: { - if (i < text.len and text[i] == '*') { - i += 1; - - while (i + 2 < text.len and !strings.eqlComptime(text[i..][0..2], "*/")) { - i += 1; - } - - if (i + 2 < text.len and strings.eqlComptime(text[i..][0..2], "*/")) { - i += 2; - } else { - i = 1; - break :as_multiline_comment; - } - - if (this.opts.redact_sensitive_information) { - try writer.print(Output.prettyFmt("{f}", true), .{redactedSource(text[0..i])}); - } else { - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - } - text = text[i..]; - continue; - } - } - - try writer.writeAll(text[0..i]); - text = text[i..]; - }, - '}', '{' => |brace| { - // support potentially highlighting "from" in an import statement - if ((prev_keyword orelse Keyword.@"continue") != .import) { - prev_keyword = null; - } - - if (should_redact_value) { - should_redact_value = false; - const len = strings.indexOfChar(text, '\n') orelse text.len; - try writer.splatByteAll('*', len); - text = text[len..]; - continue; - } - - try writer.writeByte(brace); - text = text[1..]; - }, - '[', ']' => |bracket| { - prev_keyword = null; - if (should_redact_value) { - should_redact_value = false; - const len = strings.indexOfChar(text, '\n') orelse text.len; - try writer.splatByteAll('*', len); - text = text[len..]; - continue; - } - try writer.writeByte(bracket); - text = text[1..]; - }, - ';' => { - prev_keyword = null; - if (should_redact_value) { - should_redact_value = false; - const len = strings.indexOfChar(text, '\n') orelse text.len; - try writer.splatByteAll('*', len); - text = text[len..]; - continue; - } - try writer.print(Output.prettyFmt(";", true), .{}); - text = text[1..]; - }, - '.' => { - prev_keyword = null; - - if (should_redact_value) { - should_redact_value = false; - const len = strings.indexOfChar(text, '\n') orelse text.len; - try writer.splatByteAll('*', len); - text = text[len..]; - continue; - } - - var i: usize = 1; - if (text.len > 1 and (js_lexer.isIdentifierStart(text[1]) or text[1] == '#')) { - i = 2; - - while (i < text.len and js_lexer.isIdentifierContinue(text[i])) { - i += 1; - } - - if (i < text.len and (text[i] == '(')) { - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - text = text[i..]; - continue; - } - i = 1; - } - - try writer.writeByte(text[0]); - text = text[1..]; - }, - - '<' => { - if (should_redact_value) { - should_redact_value = false; - const len = strings.indexOfChar(text, '\n') orelse text.len; - try writer.splatByteAll('*', len); - text = text[len..]; - continue; - } - var i: usize = 1; - - // JSX - jsx: { - if (text.len > 1 and text[0] == '/') { - i = 2; - } - prev_keyword = null; - - while (i < text.len and js_lexer.isIdentifierContinue(text[i])) { - i += 1; - } else { - i = 1; - break :jsx; - } - - while (i < text.len and text[i] != '>') { - i += 1; - - if (i < text.len and text[i] == '<') { - i = 1; - break :jsx; - } - } - - if (i < text.len and text[i] == '>') { - i += 1; - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - text = text[i..]; - continue; - } - - i = 1; - } - - try writer.print(Output.prettyFmt("{s}", true), .{text[0..i]}); - text = text[i..]; - }, - - else => |c| { - if (should_redact_value) { - should_redact_value = false; - const len = strings.indexOfChar(text, '\n') orelse text.len; - try writer.splatByteAll('*', len); - text = text[len..]; - continue; - } - try writer.writeByte(c); - text = text[1..]; - }, - } - } - } - } -}; - -pub fn quote(self: string) bun.fmt.QuotedFormatter { - return bun.fmt.QuotedFormatter{ - .text = self, - }; -} - -pub fn EnumTagListFormatter(comptime Enum: type, comptime Separator: @Type(.enum_literal)) type { - return struct { - pretty: bool = true, - const output = brk: { - var text: []const u8 = ""; - const names = std.meta.fieldNames(Enum); - for (names, 0..) |name, i| { - if (Separator == .list) { - if (i > 0) { - if (i + 1 == names.len) { - text = text ++ ", or "; - } else { - text = text ++ ", "; - } - } - - text = text ++ "\"" ++ name ++ "\""; - } else if (Separator == .dash) { - text = text ++ "\n- " ++ name; - } else { - @compileError("Unknown separator type: must be .dash or .list"); - } - } - break :brk text; - }; - pub fn format(_: @This(), writer: *std.Io.Writer) !void { - try writer.writeAll(output); - } - }; -} - -pub fn enumTagList(comptime Enum: type, comptime separator: @Type(.enum_literal)) EnumTagListFormatter(Enum, separator) { - return EnumTagListFormatter(Enum, separator){}; -} - -pub fn formatIp(address: std.net.Address, into: []u8) ![]u8 { - // std.net.Address.format includes `:` and square brackets (IPv6) - // while Node does neither. This uses format then strips these to bring - // the result into conformance with Node. - var result = try std.fmt.bufPrint(into, "{f}", .{address}); - - // Strip `:` - if (std.mem.lastIndexOfScalar(u8, result, ':')) |colon| { - result = result[0..colon]; - } - // Strip brackets - if (result[0] == '[' and result[result.len - 1] == ']') { - result = result[1 .. result.len - 1]; - } - return result; -} - -// https://lemire.me/blog/2021/06/03/computing-the-number-of-digits-of-an-integer-even-faster/ -pub fn fastDigitCount(x: u64) u64 { - if (x == 0) { - return 1; - } - - const table = [_]u64{ - 4294967296, - 8589934582, - 8589934582, - 8589934582, - 12884901788, - 12884901788, - 12884901788, - 17179868184, - 17179868184, - 17179868184, - 21474826480, - 21474826480, - 21474826480, - 21474826480, - 25769703776, - 25769703776, - 25769703776, - 30063771072, - 30063771072, - 30063771072, - 34349738368, - 34349738368, - 34349738368, - 34349738368, - 38554705664, - 38554705664, - 38554705664, - 41949672960, - 41949672960, - 41949672960, - 42949672960, - 42949672960, - }; - return x + table[std.math.log2(x)] >> 32; -} - -pub const SizeFormatter = struct { - value: usize = 0, - opts: Options, - - pub const Options = struct { - space_between_number_and_unit: bool = true, - }; - - pub fn format(self: SizeFormatter, writer: *std.Io.Writer) std.Io.Writer.Error!void { - const math = std.math; - const value = self.value; - if (value == 0) { - if (self.opts.space_between_number_and_unit) { - return writer.writeAll("0 KB"); - } else { - return writer.writeAll("0KB"); - } - } - - if (value < 512) { - try writer.print("{d}", .{self.value}); - if (self.opts.space_between_number_and_unit) { - return writer.writeAll(" bytes"); - } else { - return writer.writeByte('B'); - } - } - - const mags_si = " KMGTPEZY"; - const log2 = math.log2(value); - const magnitude = @min(log2 / comptime math.log2(1000), mags_si.len - 1); - const new_value = math.lossyCast(f64, value) / math.pow(f64, 1000, math.lossyCast(f64, magnitude)); - const suffix = mags_si[magnitude]; - - if (suffix == ' ') { - if (self.opts.space_between_number_and_unit) { - try writer.print("{d:.2} KB", .{new_value / 1000.0}); - } else { - try writer.print("{d:.2}KB", .{new_value / 1000.0}); - } - return; - } - const precision: usize = if (std.math.approxEqAbs(f64, new_value, @trunc(new_value), 0.100)) 1 else 2; - try writer.print("{d:.[1]}", .{ new_value, precision }); - if (self.opts.space_between_number_and_unit) { - try writer.print(" {c}B", .{suffix}); - } else { - try writer.print("{c}B", .{suffix}); - } - } -}; - -pub fn size(bytes: anytype, opts: SizeFormatter.Options) SizeFormatter { - return .{ - .value = switch (@TypeOf(bytes)) { - f64, f32, f128 => @intFromFloat(bytes), - i64, isize => @intCast(bytes), - else => bytes, - }, - .opts = opts, - }; -} - -const lower_hex_table = [_]u8{ - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', -}; -const upper_hex_table = [_]u8{ - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'A', - 'B', - 'C', - 'D', - 'E', - 'F', -}; -pub fn HexIntFormatter(comptime Int: type, comptime lower: bool) type { - return struct { - value: Int, - - const table = if (lower) lower_hex_table else upper_hex_table; - - const BufType = [@bitSizeOf(Int) / 4]u8; - - fn getOutBuf(value: Int) BufType { - var buf: BufType = undefined; - inline for (&buf, 0..) |*c, i| { - // value relative to the current nibble - c.* = table[@as(u8, @as(u4, @truncate(value >> comptime ((buf.len - i - 1) * 4)))) & 0xF]; - } - return buf; - } - - pub fn format(self: @This(), writer: *std.Io.Writer) !void { - const value = self.value; - try writer.writeAll(&getOutBuf(value)); - } - }; -} - -pub fn HexInt(comptime Int: type, comptime lower: std.fmt.Case, value: Int) HexIntFormatter(Int, lower == .lower) { - const Formatter = HexIntFormatter(Int, lower == .lower); - return Formatter{ .value = value }; -} - -pub fn hexIntLower(value: anytype) HexIntFormatter(@TypeOf(value), true) { - const Formatter = HexIntFormatter(@TypeOf(value), true); - return Formatter{ .value = value }; -} - -pub fn hexIntUpper(value: anytype) HexIntFormatter(@TypeOf(value), false) { - const Formatter = HexIntFormatter(@TypeOf(value), false); - return Formatter{ .value = value }; -} - -/// Equivalent to `{d:.}` but trims trailing zeros -/// if decimal part is less than `precision` digits. -fn TrimmedPrecisionFormatter(comptime precision: usize) type { - return struct { - num: f64, - precision: usize, - - pub fn format(self: @This(), writer: *std.Io.Writer) !void { - const whole = @trunc(self.num); - try writer.print("{d}", .{whole}); - const rem = self.num - whole; - if (rem != 0) { - var buf: [2 + precision]u8 = undefined; - var formatted = std.fmt.bufPrint(&buf, "{d:." ++ std.fmt.comptimePrint("{d}", .{precision}) ++ "}", .{rem}) catch unreachable; - formatted = formatted[2..]; - const trimmed = std.mem.trimRight(u8, formatted, "0"); - try writer.print(".{s}", .{trimmed}); - } - } - }; -} - -pub fn trimmedPrecision(value: f64, comptime precision: usize) TrimmedPrecisionFormatter(precision) { - const Formatter = TrimmedPrecisionFormatter(precision); - return Formatter{ .num = value, .precision = precision }; -} - -const FormatDurationData = struct { - ns: u64, - negative: bool = false, -}; - -/// This is copied from std.fmt.formatDuration, except it will only print one decimal instead of three -fn formatDurationOneDecimal(data: FormatDurationData, writer: *std.Io.Writer) !void { - // worst case: "-XXXyXXwXXdXXhXXmXX.XXXs".len = 24 - var buf: [24]u8 = undefined; - var fbs = std.io.fixedBufferStream(&buf); - var buf_writer = fbs.writer(); - if (data.negative) { - buf_writer.writeByte('-') catch unreachable; - } - - var ns_remaining = data.ns; - inline for (.{ - .{ .ns = 365 * std.time.ns_per_day, .sep = 'y' }, - .{ .ns = std.time.ns_per_week, .sep = 'w' }, - .{ .ns = std.time.ns_per_day, .sep = 'd' }, - .{ .ns = std.time.ns_per_hour, .sep = 'h' }, - .{ .ns = std.time.ns_per_min, .sep = 'm' }, - }) |unit| { - if (ns_remaining >= unit.ns) { - const units = ns_remaining / unit.ns; - buf_writer.print("{d}", .{units}) catch unreachable; - buf_writer.writeByte(unit.sep) catch unreachable; - ns_remaining -= units * unit.ns; - if (ns_remaining == 0) - return writer.writeAll(fbs.getWritten()); - } - } - - inline for (.{ - .{ .ns = std.time.ns_per_s, .sep = "s" }, - .{ .ns = std.time.ns_per_ms, .sep = "ms" }, - .{ .ns = std.time.ns_per_us, .sep = "us" }, - }) |unit| { - const kunits = ns_remaining * 1000 / unit.ns; - if (kunits >= 1000) { - buf_writer.print("{d}", .{kunits / 1000}) catch unreachable; - const frac = @divFloor(kunits % 1000, 100); - if (frac > 0) { - var decimal_buf = [_]u8{ '.', 0 }; - _ = std.fmt.printInt(decimal_buf[1..], frac, 10, .lower, .{ .fill = '0', .width = 1 }); - buf_writer.writeAll(&decimal_buf) catch unreachable; - } - buf_writer.writeAll(unit.sep) catch unreachable; - return writer.writeAll(fbs.getWritten()); - } - } - - buf_writer.print("{d}", .{ns_remaining}) catch unreachable; - buf_writer.writeAll("ns") catch unreachable; - return writer.writeAll(fbs.getWritten()); -} - -/// Return a Formatter for number of nanoseconds according to its magnitude: -/// [#y][#w][#d][#h][#m]#[.###][n|u|m]s -pub fn fmtDurationOneDecimal(ns: u64) std.fmt.Alt(FormatDurationData, formatDurationOneDecimal) { - return .{ .data = FormatDurationData{ .ns = ns } }; -} - -pub fn fmtSlice(data: anytype, comptime delim: []const u8) FormatSlice(@TypeOf(data), delim) { - return .{ .slice = data }; -} - -fn FormatSlice(comptime T: type, comptime delim: []const u8) type { - return struct { - slice: T, - - pub fn format(self: @This(), writer: *std.Io.Writer) !void { - if (self.slice.len == 0) return; - const f = "{s}"; - try writer.print(f, .{self.slice[0]}); - for (self.slice[1..]) |item| { - if (delim.len > 0) try writer.writeAll(delim); - try writer.print(f, .{item}); - } - } - }; -} - -/// Uses WebKit's double formatter -pub fn double(number: f64) FormatDouble { - return .{ .number = number }; -} - -pub const FormatDouble = struct { - number: f64, - - pub fn dtoa(buf: *[124]u8, number: f64) []const u8 { - const len = bun.cpp.WTF__dtoa(&buf.ptr[0], number); - return buf[0..len]; - } - - pub fn dtoaWithNegativeZero(buf: *[124]u8, number: f64) []const u8 { - if (std.math.isNegativeZero(number)) { - return "-0"; - } - - const len = bun.cpp.WTF__dtoa(&buf.ptr[0], number); - return buf[0..len]; - } - - pub fn format(self: @This(), writer: *std.Io.Writer) !void { - var buf: [124]u8 = undefined; - const slice = dtoa(&buf, self.number); - try writer.writeAll(slice); - } -}; - -pub fn nullableFallback(value: anytype, null_fallback: []const u8) NullableFallback(@TypeOf(value)) { - return .{ .value = value, .null_fallback = null_fallback }; -} - -pub fn NullableFallback(comptime T: type) type { - return struct { - value: T, - null_fallback: []const u8, - - pub fn format(self: @This(), writer: *std.Io.Writer) !void { - if (self.value) |value| { - try writer.print("{}", .{value}); - } else { - try writer.writeAll(self.null_fallback); - } - } - }; -} - -pub fn escapePowershell(str: []const u8) std.fmt.Alt([]const u8, escapePowershellImpl) { - return .{ .data = str }; -} - -fn escapePowershellImpl(str: []const u8, writer: *std.Io.Writer) !void { - var remain = str; - while (bun.strings.indexOfAny(remain, "\"`")) |i| { - try writer.writeAll(remain[0..i]); - try writer.writeAll("`"); - try writer.writeByte(remain[i]); - remain = remain[i + 1 ..]; - } - try writer.writeAll(remain); -} - -// js_bindings (fmtString for highlighter.test.ts) lives in src/jsc/fmt_jsc.zig -// alongside fmt_jsc.bind.ts; bun_core/ stays JSC-free. - -// Equivalent to ERR_OUT_OF_RANGE from -fn NewOutOfRangeFormatter(comptime T: type) type { - return struct { - value: T, - min: i64 = std.math.maxInt(i64), - max: i64 = std.math.maxInt(i64), - field_name: []const u8, - msg: []const u8 = "", - - pub fn format(self: @This(), writer: *std.Io.Writer) !void { - if (self.field_name.len > 0) { - try writer.writeAll("The value of \""); - try writer.writeAll(self.field_name); - try writer.writeAll("\" is out of range. It must be "); - } else { - if (comptime Environment.isDebug) { - @panic("Set field_name plz"); - } - try writer.writeAll("The value is out of range. It must be "); - } - - const min = self.min; - const max = self.max; - const msg = self.msg; - - if (min != std.math.maxInt(i64) and max != std.math.maxInt(i64)) { - try writer.print(">= {d} and <= {d}.", .{ min, max }); - } else if (min != std.math.maxInt(i64)) { - try writer.print(">= {d}.", .{min}); - } else if (max != std.math.maxInt(i64)) { - try writer.print("<= {d}.", .{max}); - } else if (msg.len > 0) { - try writer.writeAll(msg); - try writer.writeByte('.'); - } else { - try writer.writeAll("within the range of values for type "); - try writer.writeAll(comptime @typeName(T)); - try writer.writeAll("."); - } - - if (comptime T == f64 or T == f32) { - try writer.print(" Received {f}", .{double(self.value)}); - } else if (comptime T == []const u8) { - try writer.print(" Received {s}", .{self.value}); - } else if (comptime std.meta.hasFn(@TypeOf(self.value), "format")) { - try writer.print(" Received {f}", .{self.value}); - } else { - try writer.print(" Received {}", .{self.value}); - } - } - }; -} - -const DoubleOutOfRangeFormatter = NewOutOfRangeFormatter(f64); -const IntOutOfRangeFormatter = NewOutOfRangeFormatter(i64); -const StringOutOfRangeFormatter = NewOutOfRangeFormatter([]const u8); -const BunStringOutOfRangeFormatter = NewOutOfRangeFormatter(bun.String); - -fn OutOfRangeFormatter(comptime T: type) type { - if (T == f64 or T == f32) { - return DoubleOutOfRangeFormatter; - } else if (T == []const u8) { - return StringOutOfRangeFormatter; - } else if (T == bun.String) { - return BunStringOutOfRangeFormatter; - } - return IntOutOfRangeFormatter; -} - -pub const OutOfRangeOptions = struct { - min: i64 = std.math.maxInt(i64), - max: i64 = std.math.maxInt(i64), - field_name: []const u8, - msg: []const u8 = "", -}; - -pub fn outOfRange(value: anytype, options: OutOfRangeOptions) OutOfRangeFormatter(@TypeOf(value)) { - return .{ .value = value, .min = options.min, .max = options.max, .field_name = options.field_name, .msg = options.msg }; -} - -/// esbuild has an 8 character truncation of a base32 encoded bytes. this -/// is not exactly that, but it will appear as such. the character list -/// chosen omits similar characters in the unlikely case someone is -/// trying to memorize a hash. -/// -/// this hash is used primarily for the hashes in bundler chunk file names. the -/// output is all lowercase to avoid issues with case-insensitive filesystems. -pub fn truncatedHash32(int: u64) std.fmt.Alt(u64, truncatedHash32Impl) { - return .{ .data = int }; -} - -fn truncatedHash32Impl(int: u64, writer: *std.Io.Writer) !void { - const in_bytes = std.mem.asBytes(&int); - const chars = "0123456789abcdefghjkmnpqrstvwxyz"; - try writer.writeAll(&.{ - chars[in_bytes[0] & 31], - chars[in_bytes[1] & 31], - chars[in_bytes[2] & 31], - chars[in_bytes[3] & 31], - chars[in_bytes[4] & 31], - chars[in_bytes[5] & 31], - chars[in_bytes[6] & 31], - chars[in_bytes[7] & 31], - }); -} - -const string = []const u8; - -const bun = @import("bun"); -const Environment = bun.Environment; -const Output = bun.Output; -const js_lexer = bun.js_lexer; -const sha = bun.sha; -const strings = bun.strings; - -const std = @import("std"); -const fmt = std.fmt; diff --git a/src/bun_core/output.zig b/src/bun_core/output.zig deleted file mode 100644 index ccb707ae183f..000000000000 --- a/src/bun_core/output.zig +++ /dev/null @@ -1,1380 +0,0 @@ -// These are threadlocal so we don't have stdout/stderr writing on top of each other -threadlocal var source: Source = undefined; -threadlocal var source_set: bool = false; - -// These are not threadlocal so we avoid opening stdout/stderr for every thread -var stderr_stream: Source.StreamType = undefined; -var stdout_stream: Source.StreamType = undefined; -var stdout_stream_set = false; - -// Track which stdio descriptors are TTYs (0=stdin, 1=stdout, 2=stderr) -pub export var bun_stdio_tty: [3]i32 = .{ 0, 0, 0 }; - -pub var terminal_size: std.posix.winsize = .{ - .row = 0, - .col = 0, - .xpixel = 0, - .ypixel = 0, -}; - -pub const Source = struct { - pub const StreamType: type = brk: { - if (Environment.isWasm) { - break :brk std.io.FixedBufferStream([]u8); - } else { - break :brk File; - // var stdout = std.fs.File.stdout(); - // return @TypeOf(bun.deprecated.bufferedWriter(stdout.writer())); - } - }; - - stdout_buffer: [4096]u8, - stderr_buffer: [4096]u8, - buffered_stream_backing: @TypeOf(StreamType.quietWriter(undefined)).Adapter, - buffered_error_stream_backing: @TypeOf(StreamType.quietWriter(undefined)).Adapter, - buffered_stream: *std.Io.Writer, - buffered_error_stream: *std.Io.Writer, - - stream_backing: @TypeOf(StreamType.quietWriter(undefined)).Adapter, - error_stream_backing: @TypeOf(StreamType.quietWriter(undefined)).Adapter, - stream: *std.Io.Writer, - error_stream: *std.Io.Writer, - - raw_stream: StreamType, - raw_error_stream: StreamType, - out_buffer: []u8 = &([_]u8{}), - err_buffer: []u8 = &([_]u8{}), - - pub fn init( - out: *Source, - stream: StreamType, - err_stream: StreamType, - ) void { - if ((comptime Environment.isDebug and use_mimalloc) and !source_set) { - bun.mimalloc.mi_option_set(.show_errors, 1); - } - source_set = true; - - out.* = .{ - .raw_stream = stream, - .raw_error_stream = err_stream, - - .stdout_buffer = undefined, - .stderr_buffer = undefined, - .buffered_stream = undefined, - .buffered_stream_backing = undefined, - .buffered_error_stream_backing = undefined, - .buffered_error_stream = undefined, - - .stream_backing = undefined, - .error_stream_backing = undefined, - .stream = undefined, - .error_stream = undefined, - }; - - out.buffered_stream_backing = out.raw_stream.quietWriter().adaptToNewApi(&out.stdout_buffer); - out.buffered_error_stream_backing = out.raw_error_stream.quietWriter().adaptToNewApi(&out.stderr_buffer); - out.buffered_stream = &out.buffered_stream_backing.new_interface; - out.buffered_error_stream = &out.buffered_error_stream_backing.new_interface; - - out.stream_backing = out.raw_stream.quietWriter().adaptToNewApi(&.{}); - out.error_stream_backing = out.raw_error_stream.quietWriter().adaptToNewApi(&.{}); - out.stream = &out.stream_backing.new_interface; - out.error_stream = &out.error_stream_backing.new_interface; - } - - pub fn configureThread() void { - if (source_set) return; - bun.debugAssert(stdout_stream_set); - source.init(stdout_stream, stderr_stream); - bun.StackCheck.configureThread(); - } - - pub fn configureNamedThread(name: [:0]const u8) void { - Global.setThreadName(name); - configureThread(); - } - - pub fn isNoColor() bool { - return bun.env_var.NO_COLOR.get(); - } - - pub fn getForceColorDepth() ?ColorDepth { - const force_color = bun.env_var.FORCE_COLOR.get() orelse return null; - // Supported by Node.js, if set will ignore NO_COLOR. - // - "0" to indicate no color support - // - "1", "true", or "" to indicate 16-color support - // - "2" to indicate 256-color support - // - "3" to indicate 16 million-color support - return switch (force_color) { - 0 => .none, - 1 => .@"16", - 2 => .@"256", - else => .@"16m", - }; - } - - pub fn isForceColor() bool { - return (getForceColorDepth() orelse ColorDepth.none) != .none; - } - - pub fn isColorTerminal() bool { - if (Environment.isWindows) { - // https://github.com/chalk/supports-color/blob/d4f413efaf8da045c5ab440ed418ef02dbb28bf1/index.js#L100C11-L112 - // Windows 10 build 10586 is the first Windows release that supports 256 colors. - // Windows 10 build 14931 is the first release that supports 16m/TrueColor. - // Every other version supports 16 colors. - return true; - } - - return colorDepth() != .none; - } - - const WindowsStdio = struct { - const w = bun.windows; - - /// At program start, we snapshot the console modes of standard in, out, and err - /// so that we can restore them at program exit if they change. Restoration is - /// best-effort, and may not be applied if the process is killed abruptly. - pub var console_mode = [3]?u32{ null, null, null }; - pub var console_codepage = @as(u32, 0); - pub var console_output_codepage = @as(u32, 0); - - pub export fn Bun__restoreWindowsStdio() callconv(.c) void { - restore(); - } - comptime { - if (Environment.isWindows) { - _ = &Bun__restoreWindowsStdio; - } - } - - pub fn restore() void { - const peb = std.os.windows.peb(); - const stdout = peb.ProcessParameters.hStdOutput; - const stderr = peb.ProcessParameters.hStdError; - const stdin = peb.ProcessParameters.hStdInput; - - const handles = &.{ &stdin, &stdout, &stderr }; - inline for (console_mode, handles) |mode, handle| { - if (mode) |m| { - _ = c.SetConsoleMode(handle.*, m); - } - } - - if (console_output_codepage != 0) - _ = c.SetConsoleOutputCP(console_output_codepage); - - if (console_codepage != 0) - _ = c.SetConsoleCP(console_codepage); - } - - pub fn init() void { - w.libuv.uv_disable_stdio_inheritance(); - - const stdin = std.os.windows.GetStdHandle(std.os.windows.STD_INPUT_HANDLE) catch w.INVALID_HANDLE_VALUE; - const stdout = std.os.windows.GetStdHandle(std.os.windows.STD_OUTPUT_HANDLE) catch w.INVALID_HANDLE_VALUE; - const stderr = std.os.windows.GetStdHandle(std.os.windows.STD_ERROR_HANDLE) catch w.INVALID_HANDLE_VALUE; - - const fd_internals = @import("../sys/fd.zig"); - const INVALID_HANDLE_VALUE = std.os.windows.INVALID_HANDLE_VALUE; - fd_internals.windows_cached_stderr = if (stderr != INVALID_HANDLE_VALUE) .fromSystem(stderr) else .invalid; - fd_internals.windows_cached_stdout = if (stdout != INVALID_HANDLE_VALUE) .fromSystem(stdout) else .invalid; - fd_internals.windows_cached_stdin = if (stdin != INVALID_HANDLE_VALUE) .fromSystem(stdin) else .invalid; - if (Environment.isDebug) fd_internals.windows_cached_fd_set = true; - - buffered_stdin.unbuffered_reader.context.handle = .stdin(); - - // https://learn.microsoft.com/en-us/windows/console/setconsoleoutputcp - const CP_UTF8 = 65001; - console_output_codepage = c.GetConsoleOutputCP(); - _ = c.SetConsoleOutputCP(CP_UTF8); - - console_codepage = c.GetConsoleCP(); - _ = c.SetConsoleCP(CP_UTF8); - - var mode: w.DWORD = undefined; - if (c.GetConsoleMode(stdin, &mode) != 0) { - console_mode[0] = mode; - bun_stdio_tty[0] = 1; - // There are no flags to set on standard in, but just in case something - // later modifies the mode, we can still reset it at the end of program run - // - // In the past, Bun would set ENABLE_VIRTUAL_TERMINAL_INPUT, which was not - // intentionally set for any purpose, and instead only caused problems. - } - - if (c.GetConsoleMode(stdout, &mode) != 0) { - console_mode[1] = mode; - bun_stdio_tty[1] = 1; - _ = c.SetConsoleMode(stdout, w.ENABLE_PROCESSED_OUTPUT | std.os.windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | w.ENABLE_WRAP_AT_EOL_OUTPUT | mode); - } - - if (c.GetConsoleMode(stderr, &mode) != 0) { - console_mode[2] = mode; - bun_stdio_tty[2] = 1; - _ = c.SetConsoleMode(stderr, w.ENABLE_PROCESSED_OUTPUT | std.os.windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING | w.ENABLE_WRAP_AT_EOL_OUTPUT | mode); - } - } - }; - - pub const Stdio = struct { - extern "c" var bun_is_stdio_null: [3]i32; - - pub fn isStderrNull() bool { - return bun_is_stdio_null[2] == 1; - } - - pub fn isStdoutNull() bool { - return bun_is_stdio_null[1] == 1; - } - - pub fn isStdinNull() bool { - return bun_is_stdio_null[0] == 1; - } - - pub extern "c" fn bun_initialize_process() void; - pub fn init() void { - bun_initialize_process(); - - if (Environment.isWindows) { - WindowsStdio.init(); - } - - const stdout = bun.sys.File.from(std.fs.File.stdout()); - const stderr = bun.sys.File.from(std.fs.File.stderr()); - - Source.setInit(stdout, stderr); - - if (comptime Environment.isDebug or Environment.enable_logs) { - initScopedDebugWriterAtStartup(); - } - } - - pub extern "c" fn bun_restore_stdio() void; - pub fn restore() void { - if (Environment.isWindows) { - WindowsStdio.restore(); - } else { - bun_restore_stdio(); - } - } - }; - - pub const ColorDepth = enum { - none, - @"16", - @"256", - @"16m", - }; - var lazy_color_depth: ColorDepth = .none; - var color_depth_once = std.once(getColorDepthOnce); - fn getColorDepthOnce() void { - if (getForceColorDepth()) |depth| { - lazy_color_depth = depth; - return; - } - - if (isNoColor()) { - return; - } - - const term = bun.env_var.TERM.get() orelse ""; - if (strings.eqlComptime(term, "dumb")) { - return; - } - - if (bun.env_var.TMUX.get() != null) { - lazy_color_depth = .@"256"; - return; - } - - if (bun.env_var.CI.get() != null) { - lazy_color_depth = .@"16"; - return; - } - - if (bun.env_var.TERM_PROGRAM.get()) |term_program| { - const use_16m = .{ - "ghostty", - "MacTerm", - "WezTerm", - "HyperTerm", - "iTerm.app", - }; - inline for (use_16m) |program| { - if (strings.eqlComptime(term_program, program)) { - lazy_color_depth = .@"16m"; - return; - } - } - } - - var has_color_term_set = false; - - if (bun.env_var.COLORTERM.get()) |color_term| { - if (strings.eqlComptime(color_term, "truecolor") or strings.eqlComptime(color_term, "24bit")) { - lazy_color_depth = .@"16m"; - return; - } - has_color_term_set = true; - } - - if (term.len > 0) { - if (strings.hasPrefixComptime(term, "xterm-256")) { - lazy_color_depth = .@"256"; - return; - } - const pairs = .{ - .{ "st", ColorDepth.@"16" }, - .{ "hurd", ColorDepth.@"16" }, - .{ "eterm", ColorDepth.@"16" }, - .{ "gnome", ColorDepth.@"16" }, - .{ "kterm", ColorDepth.@"16" }, - .{ "mosh", ColorDepth.@"16m" }, - .{ "putty", ColorDepth.@"16" }, - .{ "cons25", ColorDepth.@"16" }, - .{ "cygwin", ColorDepth.@"16" }, - .{ "dtterm", ColorDepth.@"16" }, - .{ "mlterm", ColorDepth.@"16" }, - .{ "console", ColorDepth.@"16" }, - .{ "jfbterm", ColorDepth.@"16" }, - .{ "konsole", ColorDepth.@"16" }, - .{ "terminator", ColorDepth.@"16m" }, - .{ "xterm-ghostty", ColorDepth.@"16m" }, - .{ "rxvt-unicode-24bit", ColorDepth.@"16m" }, - }; - - inline for (pairs) |pair| { - if (strings.eqlComptime(term, pair[0])) { - lazy_color_depth = pair[1]; - return; - } - } - - if (strings.includes(term, "con") or - strings.includes(term, "ansi") or - strings.includes(term, "rxvt") or - strings.includes(term, "color") or - strings.includes(term, "linux") or - strings.includes(term, "vt100") or - strings.includes(term, "xterm") or - strings.includes(term, "screen")) - { - lazy_color_depth = .@"16"; - return; - } - } - - if (has_color_term_set) { - lazy_color_depth = .@"16"; - return; - } - - lazy_color_depth = .none; - } - pub fn colorDepth() ColorDepth { - color_depth_once.call(); - return lazy_color_depth; - } - - pub fn setInit(stdout: StreamType, stderr: StreamType) void { - source.init(stdout, stderr); - - source_set = true; - if (!stdout_stream_set) { - stdout_stream_set = true; - if (comptime Environment.isNative) { - const is_stdout_tty = bun_stdio_tty[1] != 0; - if (is_stdout_tty) { - stdout_descriptor_type = OutputStreamDescriptor.terminal; - } - - const is_stderr_tty = bun_stdio_tty[2] != 0; - if (is_stderr_tty) { - stderr_descriptor_type = OutputStreamDescriptor.terminal; - } - - var enable_color: ?bool = null; - if (isForceColor()) { - enable_color = true; - } else if (isNoColor()) { - enable_color = false; - } else if (isColorTerminal() and (is_stdout_tty or is_stderr_tty)) { - enable_color = true; - } - - enable_ansi_colors_stdout = enable_color orelse is_stdout_tty; - enable_ansi_colors_stderr = enable_color orelse is_stderr_tty; - } - - stdout_stream = stdout; - stderr_stream = stderr; - } - } -}; - -pub const OutputStreamDescriptor = enum { - unknown, - // file, - // pipe, - terminal, -}; - -pub const enable_ansi_colors = @compileError("Deprecated to prevent accidentally using the wrong one. Use enable_ansi_colors_stdout or enable_ansi_colors_stderr instead."); -pub var enable_ansi_colors_stderr = Environment.isNative; -pub var enable_ansi_colors_stdout = Environment.isNative; -pub var enable_buffering = Environment.isNative; -pub var is_verbose = false; -pub var is_github_action = false; - -pub var stderr_descriptor_type = OutputStreamDescriptor.unknown; -pub var stdout_descriptor_type = OutputStreamDescriptor.unknown; - -pub inline fn isStdoutTTY() bool { - return bun_stdio_tty[1] != 0; -} - -pub inline fn isStderrTTY() bool { - return bun_stdio_tty[2] != 0; -} - -pub inline fn isStdinTTY() bool { - return bun_stdio_tty[0] != 0; -} - -pub fn isGithubAction() bool { - if (bun.env_var.GITHUB_ACTIONS.get()) { - // Do not print github annotations for AI agents because that wastes the context window. - return !isAIAgent(); - } - return false; -} - -pub fn isAIAgent() bool { - const get_is_agent = struct { - var value = false; - fn evaluate() bool { - if (bun.env_var.AGENT.get()) |env| { - return strings.eqlComptime(env, "1"); - } - - if (isVerbose()) { - return false; - } - - // Claude Code. - if (bun.env_var.CLAUDECODE.get()) { - return true; - } - - // Replit. - if (bun.env_var.REPL_ID.get()) { - return true; - } - - // TODO: add environment variable for Gemini - // Gemini does not appear to add any environment variables to identify it. - - // TODO: add environment variable for Codex - // codex does not appear to add any environment variables to identify it. - - // TODO: add environment variable for Cursor Background Agents - // cursor does not appear to add any environment variables to identify it. - - return false; - } - - fn setValue() void { - value = evaluate(); - } - - var once = std.once(setValue); - - pub fn isEnabled() bool { - once.call(); - return value; - } - }; - - return get_is_agent.isEnabled(); -} - -pub fn isVerbose() bool { - // Set by Github Actions when a workflow is run using debug mode. - return bun.env_var.RUNNER_DEBUG.get(); -} - -pub fn enableBuffering() void { - if (comptime Environment.isNative) enable_buffering = true; -} - -const EnableBufferingScope = struct { - prev_buffering: bool, - pub fn init() EnableBufferingScope { - const prev_buffering = enable_buffering; - enable_buffering = true; - return .{ .prev_buffering = prev_buffering }; - } - - /// Does not call Output.flush(). - pub fn deinit(self: EnableBufferingScope) void { - enable_buffering = self.prev_buffering; - } -}; - -pub fn enableBufferingScope() EnableBufferingScope { - return EnableBufferingScope.init(); -} - -pub fn disableBuffering() void { - flush(); - if (comptime Environment.isNative) enable_buffering = false; -} - -pub fn panic(comptime fmt: string, args: anytype) noreturn { - @branchHint(.cold); - - if (enable_ansi_colors_stderr) { - std.debug.panic(comptime prettyFmt(fmt, true), args); - } else { - std.debug.panic(comptime prettyFmt(fmt, false), args); - } -} - -pub const WriterType: type = @TypeOf(Source.StreamType.quietWriter(undefined)); - -pub fn rawErrorWriter() Source.StreamType { - bun.debugAssert(source_set); - return source.raw_error_stream; -} - -// TODO: investigate migrating this to the buffered one. -pub fn errorWriter() *std.Io.Writer { - bun.debugAssert(source_set); - return source.error_stream; -} - -pub fn errorWriterBuffered() *std.Io.Writer { - bun.debugAssert(source_set); - return source.buffered_error_stream; -} - -// TODO: investigate returning the buffered_error_stream -pub fn errorStream() *std.Io.Writer { - bun.debugAssert(source_set); - return source.error_stream; -} - -pub fn rawWriter() Source.StreamType { - bun.debugAssert(source_set); - return source.raw_stream; -} - -pub fn writer() *std.Io.Writer { - bun.debugAssert(source_set); - return source.stream; -} - -pub fn writerBuffered() *std.Io.Writer { - bun.debugAssert(source_set); - return source.buffered_stream; -} - -pub fn resetTerminal() void { - if (!enable_ansi_colors_stderr and !enable_ansi_colors_stdout) { - return; - } - - if (enable_ansi_colors_stderr) { - source.error_stream.writeAll("\x1B[2J\x1B[3J\x1B[H") catch {}; - } else { - source.stream.writeAll("\x1B[2J\x1B[3J\x1B[H") catch {}; - } -} - -pub fn resetTerminalAll() void { - if (enable_ansi_colors_stderr) - source.error_stream.writeAll("\x1B[2J\x1B[3J\x1B[H") catch {}; - if (enable_ansi_colors_stdout) - source.stream.writeAll("\x1B[2J\x1B[3J\x1B[H") catch {}; -} - -/// Write buffered stdout & stderr to the terminal. -/// Must be called before the process exits or the buffered output will be lost. -/// Bun automatically calls this function in Global.exit(). -pub fn flush() void { - if (Environment.isNative and source_set) { - source.buffered_stream.flush() catch {}; - source.buffered_error_stream.flush() catch {}; - // source.stream.flush() catch {}; - // source.error_stream.flush() catch {}; - } -} - -pub const ElapsedFormatter = struct { - colors: bool, - duration_ns: u64 = 0, - - pub fn format(self: ElapsedFormatter, writer_: *std.Io.Writer) !void { - switch (self.duration_ns) { - 0...std.time.ns_per_ms * 10 => { - const fmt_str = "[{d:>.2}ms]"; - switch (self.colors) { - inline else => |colors| try writer_.print(comptime prettyFmt(fmt_str, colors), .{@as(f64, @floatFromInt(self.duration_ns)) / std.time.ns_per_ms}), - } - }, - std.time.ns_per_ms * 8_000...std.math.maxInt(u64) => { - const fmt_str = "[{d:>.2}ms]"; - - switch (self.colors) { - inline else => |colors| try writer_.print(comptime prettyFmt(fmt_str, colors), .{@as(f64, @floatFromInt(self.duration_ns)) / std.time.ns_per_ms}), - } - }, - else => { - const fmt_str = "[{d:>.2}ms]"; - - switch (self.colors) { - inline else => |colors| try writer_.print(comptime prettyFmt(fmt_str, colors), .{@as(f64, @floatFromInt(self.duration_ns)) / std.time.ns_per_ms}), - } - }, - } - } -}; - -inline fn printElapsedToWithCtx(elapsed: f64, comptime printerFn: anytype, comptime has_ctx: bool, ctx: anytype) void { - switch (@as(i64, @intFromFloat(@round(elapsed)))) { - 0...1500 => { - const fmt = "[{d:>.2}ms]"; - const args = .{elapsed}; - if (comptime has_ctx) { - printerFn(ctx, fmt, args); - } else { - printerFn(fmt, args); - } - }, - else => { - const fmt = "[{d:>.2}s]"; - const args = .{elapsed / 1000.0}; - - if (comptime has_ctx) { - printerFn(ctx, fmt, args); - } else { - printerFn(fmt, args); - } - }, - } -} - -pub inline fn printElapsedTo(elapsed: f64, comptime printerFn: anytype, ctx: anytype) void { - printElapsedToWithCtx(elapsed, printerFn, true, ctx); -} - -pub fn printElapsed(elapsed: f64) void { - printElapsedToWithCtx(elapsed, prettyError, false, {}); -} - -pub fn printElapsedStdout(elapsed: f64) void { - printElapsedToWithCtx(elapsed, pretty, false, {}); -} - -pub fn printElapsedStdoutTrim(elapsed: f64) void { - switch (@as(i64, @intFromFloat(@round(elapsed)))) { - 0...1500 => { - const fmt = "[{d:>}ms]"; - const args = .{elapsed}; - pretty(fmt, args); - }, - else => { - const fmt = "[{d:>}s]"; - const args = .{elapsed / 1000.0}; - - pretty(fmt, args); - }, - } -} - -pub fn printStartEnd(start: i128, end: i128) void { - const elapsed = @divTrunc(@as(i64, @truncate(end - start)), @as(i64, std.time.ns_per_ms)); - printElapsed(@as(f64, @floatFromInt(elapsed))); -} - -pub fn printStartEndStdout(start: i128, end: i128) void { - const elapsed = @divTrunc(@as(i64, @truncate(end - start)), @as(i64, std.time.ns_per_ms)); - printElapsedStdout(@as(f64, @floatFromInt(elapsed))); -} - -pub fn printTimer(timer: *SystemTimer) void { - if (comptime Environment.isWasm) return; - const elapsed = @divTrunc(timer.read(), @as(u64, std.time.ns_per_ms)); - printElapsed(@as(f64, @floatFromInt(elapsed))); -} - -// ────────────────────────────────────────────────────────────────────────── -// Print routing -// -// `print` / `printError` / `pretty*` are called from thousands of sites with -// distinct comptime format strings. They used to be `noinline`, which forced -// one ~400-byte function body per (fmt, args-type) pair — about 2,650 of them, -// or ~1 MB of .text in release builds. The bodies were nearly identical: pick -// buffered-vs-unbuffered writer, then `Writer.print(fmt, args)`. -// -// Now the public entry points are `inline` and bottom out in two non-generic -// helpers (`destWriter`, `writeBytes`). The only per-call-site code is either -// a `writeBytes` call (when `args` is empty — ~40% of sites) or one -// `Writer.print` call. The buffering branch lives in `destWriter` so each -// site formats once instead of twice. -// ────────────────────────────────────────────────────────────────────────── - -/// Pick the active writer for `dest`, honoring `enable_buffering`. Non-generic -/// so the buffering branch isn't duplicated into every call site. -noinline fn destWriter(dest: Destination) *std.Io.Writer { - bun.debugAssert(source_set); - return switch (dest) { - .stdout => if (enable_buffering) source.buffered_stream else source.stream, - .stderr => if (enable_buffering) source.buffered_error_stream else source.error_stream, - }; -} - -/// Single shared write path for pre-formatted bytes. -noinline fn writeBytes(dest: Destination, bytes: []const u8) void { - destWriter(dest).writeAll(bytes) catch {}; -} - -inline fn hasNoArgs(comptime Args: type) bool { - return @typeInfo(Args).@"struct".fields.len == 0; -} - -inline fn printTo(dest: Destination, comptime fmt: string, args: anytype) void { - if (comptime Environment.isWasm) { - switch (dest) { - .stdout => { - source.stream.pos = 0; - source.stream.writer().print(fmt, args) catch unreachable; - root.console_log(root.Uint8Array.fromSlice(source.stream.buffer[0..source.stream.pos])); - }, - .stderr => { - source.error_stream.seekTo(0) catch return; - source.error_stream.writer().print(fmt, args) catch unreachable; - root.console_error(root.Uint8Array.fromSlice(source.err_buffer[0..source.error_stream.pos])); - }, - } - return; - } - if (comptime hasNoArgs(@TypeOf(args))) { - // Format strings escape literal braces as `{{` / `}}`; comptimePrint - // resolves those (and validates the format string) so the output - // matches what `Writer.print(fmt, .{})` would have produced. - return writeBytes(dest, comptime std.fmt.comptimePrint(fmt, .{})); - } - // There's not much we can do if this errors. Especially if it's something like BrokenPipe. - destWriter(dest).print(fmt, args) catch {}; -} - -pub inline fn printErrorable(comptime fmt: string, args: anytype) !void { - printTo(.stdout, fmt, args); -} - -/// Print to stdout -/// This will appear in the terminal, including in production. -/// Text automatically buffers -pub inline fn println(comptime fmt: string, args: anytype) void { - const fmt_ = if (fmt.len == 0 or fmt[fmt.len - 1] != '\n') fmt ++ "\n" else fmt; - return printTo(.stdout, fmt_, args); -} - -/// Print to stdout, but only in debug builds. -/// Text automatically buffers -pub fn debug(comptime fmt: string, args: anytype) void { - if (!Environment.isDebug) return; - prettyErrorln("DEBUG: " ++ fmt, args); - flush(); -} - -pub inline fn _debug(comptime fmt: string, args: anytype) void { - bun.debugAssert(source_set); - println(fmt, args); -} - -pub inline fn print(comptime fmt: string, args: anytype) void { - printTo(.stdout, fmt, args); -} - -/// Debug-only logs which should not appear in release mode -/// To enable a specific log at runtime, set the environment variable -/// BUN_DEBUG_${TAG} to 1 -/// For example, to enable the "foo" log, set the environment variable -/// BUN_DEBUG_foo=1 -/// To enable all logs, set the environment variable -/// BUN_DEBUG_ALL=1 -pub const LogFunction = fn (comptime fmt: string, args: anytype) callconv(bun.callconv_inline) void; - -pub const Visibility = enum { - /// Hide logs for this scope by default. - hidden, - /// Show logs for this scope by default. - visible, - - /// Show logs for this scope by default if and only if `condition` is true. - pub fn visibleIf(condition: bool) Visibility { - return if (condition) .visible else .hidden; - } -}; - -pub fn Scoped(comptime tag: anytype, comptime visibility: Visibility) type { - const tagname = comptime if (!Environment.enable_logs) .{} else brk: { - const input = switch (@TypeOf(tag)) { - @Type(.enum_literal) => @tagName(tag), - else => tag, - }; - var ascii_slice: [input.len]u8 = undefined; - for (input, &ascii_slice) |in, *out| { - out.* = std.ascii.toLower(in); - } - break :brk ascii_slice; - }; - - return ScopedLogger(&tagname, visibility); -} - -fn ScopedLogger(comptime tagname: []const u8, comptime visibility: Visibility) type { - if (comptime !Environment.enable_logs) { - return struct { - pub inline fn isVisible() bool { - return false; - } - pub fn log(comptime _: string, _: anytype) callconv(bun.callconv_inline) void {} - }; - } - - return struct { - var buffer: [4096]u8 = undefined; - var buffered_writer: File.QuietWriter.Adapter = undefined; - var out: *std.Io.Writer = undefined; - var out_set = false; - var really_disable = std.atomic.Value(bool).init(visibility == .hidden); - - var lock = bun.Mutex{}; - - var is_visible_once = std.once(evaluateIsVisible); - - fn evaluateIsVisible() void { - if (bun.getenvZAnyCase("BUN_DEBUG_" ++ tagname)) |val| { - really_disable.store(strings.eqlComptime(val, "0"), .monotonic); - } else if (bun.env_var.BUN_DEBUG_ALL.get()) |val| { - really_disable.store(!val, .monotonic); - } else if (bun.env_var.BUN_DEBUG_QUIET_LOGS.get()) |val| { - really_disable.store(really_disable.load(.monotonic) or val, .monotonic); - } else { - for (bun.argv) |arg| { - if (strings.eqlCaseInsensitiveASCII(arg, comptime "--debug-" ++ tagname, true)) { - really_disable.store(false, .monotonic); - break; - } else if (strings.eqlCaseInsensitiveASCII(arg, comptime "--debug-all", true)) { - really_disable.store(false, .monotonic); - break; - } - } - } - } - - pub fn isVisible() bool { - is_visible_once.call(); - return !really_disable.load(.monotonic); - } - - /// Debug-only logs which should not appear in release mode - /// To enable a specific log at runtime, set the environment variable - /// BUN_DEBUG_${TAG} to 1 - /// For example, to enable the "foo" log, set the environment variable - /// BUN_DEBUG_foo=1 - /// To enable all logs, set the environment variable - /// BUN_DEBUG_ALL=1 - pub fn log(comptime fmt: string, args: anytype) void { - if (!source_set) return; - if (fmt.len == 0 or fmt[fmt.len - 1] != '\n') { - return log(fmt ++ "\n", args); - } - - if (ScopedDebugWriter.disable_inside_log > 0) { - return; - } - - if (bun.crash_handler.isPanicking()) return; - - if (Environment.enable_logs) ScopedDebugWriter.disable_inside_log += 1; - defer { - if (Environment.enable_logs) - ScopedDebugWriter.disable_inside_log -= 1; - } - - if (!isVisible()) - return; - - if (!out_set) { - buffered_writer = scopedWriter().adaptToNewApi(&buffer); - out = &buffered_writer.new_interface; - out_set = true; - } - lock.lock(); - defer lock.unlock(); - - switch (enable_ansi_colors_stdout and source_set and scopedWriter().context.handle == rawWriter().handle) { - inline else => |use_ansi| { - out.print(comptime prettyFmt("[" ++ tagname ++ "] " ++ fmt, use_ansi), args) catch { - really_disable.store(true, .monotonic); - return; - }; - out.flush() catch { - really_disable.store(true, .monotonic); - return; - }; - }, - } - } - }; -} - -pub fn scoped(comptime tag: anytype, comptime visibility: Visibility) LogFunction { - return Scoped(tag, visibility).log; -} - -pub fn up(n: usize) void { - print("\x1B[{d}A", .{n}); -} -pub fn clearToEnd() void { - print("\x1B[0J", .{}); -} - -// Valid "colors": -// -// -// -// -// -// -// -// -// -// -// - bold -// - dim -// - reset -// - reset -const CSI = "\x1b["; -pub const color_map = ComptimeStringMap(string, .{ - &.{ "b", CSI ++ "1m" }, - &.{ "d", CSI ++ "2m" }, - &.{ "i", CSI ++ "3m" }, - &.{ "u", CSI ++ "4m" }, - &.{ "black", CSI ++ "30m" }, - &.{ "red", CSI ++ "31m" }, - &.{ "green", CSI ++ "32m" }, - &.{ "yellow", CSI ++ "33m" }, - &.{ "blue", CSI ++ "34m" }, - &.{ "magenta", CSI ++ "35m" }, - &.{ "cyan", CSI ++ "36m" }, - &.{ "white", CSI ++ "37m" }, - &.{ "bgred", CSI ++ "41m" }, - &.{ "bggreen", CSI ++ "42m" }, -}); -const RESET: string = "\x1b[0m"; -pub fn prettyFmt(comptime fmt: string, comptime is_enabled: bool) [:0]const u8 { - comptime var new_fmt: [fmt.len * 4]u8 = undefined; - comptime var new_fmt_i: usize = 0; - - @setEvalBranchQuota(9999); - comptime var i: usize = 0; - comptime while (i < fmt.len) { - switch (fmt[i]) { - '\\' => { - i += 1; - if (i < fmt.len) { - switch (fmt[i]) { - '<', '>' => { - new_fmt[new_fmt_i] = fmt[i]; - new_fmt_i += 1; - i += 1; - }, - else => { - new_fmt[new_fmt_i] = '\\'; - new_fmt_i += 1; - new_fmt[new_fmt_i] = fmt[i]; - new_fmt_i += 1; - i += 1; - }, - } - } - }, - '>' => { - i += 1; - }, - '{' => { - while (fmt.len > i and fmt[i] != '}') { - new_fmt[new_fmt_i] = fmt[i]; - new_fmt_i += 1; - i += 1; - } - }, - '<' => { - i += 1; - var is_reset = fmt[i] == '/'; - if (is_reset) i += 1; - const start: usize = i; - while (i < fmt.len and fmt[i] != '>') { - i += 1; - } - - const color_name = fmt[start..i]; - const color_str = color_picker: { - if (color_map.get(color_name)) |color_name_literal| { - break :color_picker color_name_literal; - } else if (std.mem.eql(u8, color_name, "r")) { - is_reset = true; - break :color_picker ""; - } else { - @compileError("Invalid color name passed: " ++ color_name); - } - }; - - if (is_enabled) { - for (if (is_reset) RESET else color_str) |ch| { - new_fmt[new_fmt_i] = ch; - new_fmt_i += 1; - } - } - }, - - else => { - new_fmt[new_fmt_i] = fmt[i]; - new_fmt_i += 1; - i += 1; - }, - } - }; - - return comptime (new_fmt[0..new_fmt_i].* ++ .{0})[0..new_fmt_i :0]; -} - -inline fn enableColorFor(dest: Destination) bool { - return switch (dest) { - .stdout => enable_ansi_colors_stdout, - .stderr => enable_ansi_colors_stderr, - }; -} - -inline fn prettyTo(dest: Destination, comptime fmt: string, args: anytype) void { - // Route through `printTo` so the WASM console_log/console_error path stays - // covered (destWriter alone bypasses it). - if (enableColorFor(dest)) { - printTo(dest, comptime prettyFmt(fmt, true), args); - } else { - printTo(dest, comptime prettyFmt(fmt, false), args); - } -} - -pub inline fn prettyWithPrinter(comptime fmt: string, args: anytype, comptime printer: anytype, comptime l: Destination) void { - if (enableColorFor(l)) { - printer(comptime prettyFmt(fmt, true), args); - } else { - printer(comptime prettyFmt(fmt, false), args); - } -} - -pub inline fn pretty(comptime fmt: string, args: anytype) void { - prettyTo(.stdout, fmt, args); -} - -/// Like Output.println, except it will automatically strip ansi color codes if -/// the terminal doesn't support them. -pub inline fn prettyln(comptime fmt: string, args: anytype) void { - const fmt_ = if (fmt.len == 0 or fmt[fmt.len - 1] != '\n') fmt ++ "\n" else fmt; - prettyTo(.stdout, fmt_, args); -} - -pub inline fn printErrorln(comptime fmt: string, args: anytype) void { - const fmt_ = if (fmt.len == 0 or fmt[fmt.len - 1] != '\n') fmt ++ "\n" else fmt; - return printTo(.stderr, fmt_, args); -} - -pub inline fn prettyError(comptime fmt: string, args: anytype) void { - prettyTo(.stderr, fmt, args); -} - -/// Print to stderr with ansi color codes automatically stripped out if the -/// terminal doesn't support them. Text is buffered -pub inline fn prettyErrorln(comptime fmt: string, args: anytype) void { - const fmt_ = if (fmt.len == 0 or fmt[fmt.len - 1] != '\n') fmt ++ "\n" else fmt; - prettyTo(.stderr, fmt_, args); -} - -/// Pretty-print a command that will be run. -/// $ bun run foo -fn printCommand(argv: anytype, comptime destination: Destination) void { - const prettyFn = if (destination == .stdout) pretty else prettyError; - const printFn = if (destination == .stdout) print else printError; - switch (@TypeOf(argv)) { - [][:0]const u8, []const []const u8, []const []u8, [][]const u8 => { - prettyFn("$ ", .{}); - printFn("{s}", .{argv[0]}); - if (argv.len > 1) { - for (argv[1..]) |arg| { - printFn(" {s}", .{arg}); - } - } - prettyFn("\n", .{}); - }, - []const u8, []u8, [:0]const u8, [:0]u8 => { - prettyFn("$ {s}\n", .{argv}); - }, - else => { - @compileLog(argv); - @compileError("command() was given unsupported type: " ++ @typeName(@TypeOf(argv))); - }, - } - flush(); -} - -pub fn commandOut(argv: anytype) void { - printCommand(argv, .stdout); -} - -pub fn command(argv: anytype) void { - printCommand(argv, .stderr); -} - -pub const Destination = enum(u8) { - stderr, - stdout, -}; - -pub inline fn printError(comptime fmt: string, args: anytype) void { - printTo(.stderr, fmt, args); -} - -pub const DebugTimer = struct { - timer: bun.DebugOnly(std.time.Timer) = undefined, - - pub inline fn start() DebugTimer { - if (comptime Environment.isDebug) { - return DebugTimer{ - .timer = std.time.Timer.start() catch unreachable, - }; - } else { - return .{}; - } - } - - pub const WriteError = error{}; - - pub fn format(self: DebugTimer, w: *std.Io.Writer) std.Io.Writer.Error!void { - if (comptime Environment.isDebug) { - var timer = self.timer; - try w.print("{d:.3}ms", .{@as(f64, @floatFromInt(timer.read())) / std.time.ns_per_ms}); - } - } -}; - -/// Print a blue note message to stderr -pub inline fn note(comptime fmt: []const u8, args: anytype) void { - prettyErrorln("note: " ++ fmt, args); -} - -/// Print a yellow warning message to stderr -pub inline fn warn(comptime fmt: []const u8, args: anytype) void { - prettyErrorln("warn: " ++ fmt, args); -} - -/// Print a yellow warning message, only in debug mode -pub inline fn debugWarn(comptime fmt: []const u8, args: anytype) void { - if (bun.Environment.isDebug) { - prettyErrorln("debug warn: " ++ fmt, args); - flush(); - } -} - -/// Print a red error message. The first argument takes an `error_name` value, which can be either -/// be a Zig error, or a string or enum. The error name is converted to a string and displayed -/// in place of "error:", making it useful to print things like "EACCES: Couldn't open package.json" -pub inline fn err(error_name: anytype, comptime fmt: []const u8, args: anytype) void { - const T = @TypeOf(error_name); - const info = @typeInfo(T); - - if (comptime T == bun.sys.Error or info == .pointer and info.pointer.child == bun.sys.Error) { - const e: bun.sys.Error = error_name; - const tag_name, const sys_errno = e.getErrorCodeTagName() orelse { - err("unknown error", fmt, args); - return; - }; - if (bun.sys.coreutils_error_map.get(sys_errno)) |label| { - prettyErrorln("{s}: {s}: " ++ fmt ++ " ({s})", .{ tag_name, label } ++ args ++ .{@tagName(e.syscall)}); - } else { - prettyErrorln("{s}: " ++ fmt ++ " ({s})", .{tag_name} ++ args ++ .{@tagName(e.syscall)}); - } - return; - } - - const display_name, const is_comptime_name = display_name: { - // Zig string literals are of type *const [n:0]u8 - // we assume that no one will pass this type from not using a string literal. - if (info == .pointer and info.pointer.size == .one and info.pointer.is_const) { - const child_info = @typeInfo(info.pointer.child); - if (child_info == .array and child_info.array.child == u8) { - if (child_info.array.len == 0) @compileError("Output.err should not be passed an empty string (use errGeneric)"); - break :display_name .{ error_name, true }; - } - } - - // other zig strings we shall treat as dynamic - if (comptime bun.trait.isZigString(T)) { - break :display_name .{ error_name, false }; - } - - // error unions - if (info == .error_set) { - if (info.error_set) |errors| { - if (errors.len == 0) { - @compileError("Output.err was given an empty error set"); - } - - // TODO: convert zig errors to errno for better searchability? - if (errors.len == 1) break :display_name .{ errors[0].name, true }; - } - - break :display_name .{ @errorName(error_name), false }; - } - - // enum literals - if (info == .enum_literal) { - const tag = @tagName(info); - comptime bun.assert(tag.len > 0); // how? - if (tag[0] != 'E') break :display_name .{ "E" ++ tag, true }; - break :display_name .{ tag, true }; - } - - // enums - if (info == .@"enum") { - const errno: bun.sys.SystemErrno = @enumFromInt(@intFromEnum(info)); - break :display_name .{ @tagName(errno), false }; - } - - @compileLog(error_name); - @compileError("err() was given unsupported type: " ++ @typeName(T) ++ " (." ++ @tagName(info) ++ ")"); - }; - - // if the name is known at compile time, we can do better and use it at compile time - if (comptime is_comptime_name) { - prettyErrorln("" ++ display_name ++ ": " ++ fmt, args); - } else { - prettyErrorln("{s}: " ++ fmt, .{display_name} ++ args); - } -} - -pub const ScopedDebugWriter = struct { - pub var scoped_file_writer: File.QuietWriter = undefined; - pub threadlocal var disable_inside_log: isize = 0; -}; -pub fn disableScopedDebugWriter() void { - if (!@inComptime()) { - ScopedDebugWriter.disable_inside_log += 1; - } -} -pub fn enableScopedDebugWriter() void { - if (!@inComptime()) { - ScopedDebugWriter.disable_inside_log -= 1; - } -} - -extern "c" fn getpid() c_int; - -pub fn initScopedDebugWriterAtStartup() void { - bun.debugAssert(source_set); - - if (bun.env_var.BUN_DEBUG.get()) |path| { - if (path.len > 0 and !strings.eql(path, "0") and !strings.eql(path, "false")) { - if (std.fs.path.dirname(path)) |dir| { - std.fs.cwd().makePath(dir) catch {}; - } - - // do not use libuv through this code path, since it might not be initialized yet. - const pid = std.fmt.allocPrint(bun.default_allocator, "{d}", .{getpid()}) catch @panic("failed to allocate path"); - defer bun.default_allocator.free(pid); - - const path_fmt = std.mem.replaceOwned(u8, bun.default_allocator, path, "{pid}", pid) catch @panic("failed to allocate path"); - defer bun.default_allocator.free(path_fmt); - - const fd: bun.FD = .fromStdFile(std.fs.cwd().createFile(path_fmt, .{ - .mode = if (Environment.isPosix) 0o644 else 0, - }) catch |open_err| { - panic("Failed to open file for debug output: {s} ({s})", .{ @errorName(open_err), path }); - }); - _ = fd.truncate(0); // windows - ScopedDebugWriter.scoped_file_writer = fd.quietWriter(); - return; - } - } - - ScopedDebugWriter.scoped_file_writer = source.raw_stream.quietWriter(); -} -fn scopedWriter() File.QuietWriter { - if (comptime !Environment.isDebug and !Environment.enable_logs) { - @compileError("scopedWriter() should only be called in debug mode"); - } - - return ScopedDebugWriter.scoped_file_writer; -} - -/// Print a red error message with "error: " as the prefix. For custom prefixes see `err()` -pub inline fn errGeneric(comptime fmt: []const u8, args: anytype) void { - prettyErrorln("error: " ++ fmt, args); -} - -/// Print a red error message with "error: " as the prefix and a formatted message. -pub inline fn errFmt(formatter: anytype) void { - return errGeneric("{f}", .{formatter}); -} - -pub var buffered_stdin = bun.deprecated.BufferedReader(4096, File.Reader){ - .unbuffered_reader = .{ .context = .{ .handle = if (Environment.isWindows) undefined else .stdin() } }, - .buf = undefined, -}; - -const string = []const u8; - -/// https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 -pub const synchronized_start = "\x1b[?2026h"; - -/// https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 -pub const synchronized_end = "\x1b[?2026l"; - -/// https://gist.github.com/christianparpart/d8a62cc1ab659194337d73e399004036 -pub fn synchronized() Synchronized { - return Synchronized.begin(); -} -pub const Synchronized = struct { - pub fn begin() Synchronized { - if (Environment.isPosix) { - print(synchronized_start, .{}); - } - return .{}; - } - - pub fn end(_: @This()) void { - if (Environment.isPosix) { - print(synchronized_end, .{}); - } - } -}; - -const Environment = @import("./env.zig"); -const root = @import("root"); -const std = @import("std"); -const SystemTimer = @import("../perf/system_timer.zig").Timer; - -const bun = @import("bun"); -const ComptimeStringMap = bun.ComptimeStringMap; -const Global = bun.Global; -const c = bun.c; -const strings = bun.strings; -const use_mimalloc = bun.use_mimalloc; -const File = bun.sys.File; diff --git a/src/bun_core/result.zig b/src/bun_core/result.zig deleted file mode 100644 index 159bca40bf04..000000000000 --- a/src/bun_core/result.zig +++ /dev/null @@ -1,11 +0,0 @@ -pub fn Result(comptime T: type, comptime E: type) type { - return union(enum) { - ok: T, - err: E, - - pub inline fn asErr(this: *const @This()) ?E { - if (this.* == .err) return this.err; - return null; - } - }; -} diff --git a/src/bun_core/string/immutable/escapeHTML.zig b/src/bun_core/string/immutable/escapeHTML.zig deleted file mode 100644 index 886edcc68b67..000000000000 --- a/src/bun_core/string/immutable/escapeHTML.zig +++ /dev/null @@ -1,642 +0,0 @@ -pub fn escapeHTMLForLatin1Input(allocator: std.mem.Allocator, latin1: []const u8) !Escaped(u8) { - const Scalar = struct { - pub const lengths: [std.math.maxInt(u8) + 1]u4 = brk: { - var values: [std.math.maxInt(u8) + 1]u4 = undefined; - for (values, 0..) |_, i| { - switch (i) { - '"' => { - values[i] = """.len; - }, - '&' => { - values[i] = "&".len; - }, - '\'' => { - values[i] = "'".len; - }, - '<' => { - values[i] = "<".len; - }, - '>' => { - values[i] = ">".len; - }, - else => { - values[i] = 1; - }, - } - } - - break :brk values; - }; - - fn appendString(buf: [*]u8, comptime str: []const u8) callconv(bun.callconv_inline) usize { - buf[0..str.len].* = str[0..str.len].*; - return str.len; - } - - pub fn append(buf: [*]u8, char: u8) callconv(bun.callconv_inline) usize { - if (lengths[char] == 1) { - buf[0] = char; - return 1; - } - - return switch (char) { - '"' => appendString(buf, """), - '&' => appendString(buf, "&"), - '\'' => appendString(buf, "'"), - '<' => appendString(buf, "<"), - '>' => appendString(buf, ">"), - else => unreachable, - }; - } - - pub fn push(comptime len: anytype, chars_: *const [len]u8, allo: std.mem.Allocator) callconv(bun.callconv_inline) Escaped(u8) { - const chars = chars_.*; - var total: usize = 0; - - comptime var remain_to_comp = len; - comptime var comp_i = 0; - - inline while (remain_to_comp > 0) : (remain_to_comp -= 1) { - total += lengths[chars[comp_i]]; - comp_i += 1; - } - - if (total == len) { - return .{ .original = {} }; - } - - const output = allo.alloc(u8, total) catch unreachable; - var head = output.ptr; - inline for (comptime bun.range(0, len)) |i| { - head += @This().append(head, chars[i]); - } - - return Escaped(u8){ .allocated = output }; - } - }; - @setEvalBranchQuota(5000); - switch (latin1.len) { - 0 => return Escaped(u8){ .static = "" }, - 1 => return switch (latin1[0]) { - '"' => Escaped(u8){ .static = """ }, - '&' => Escaped(u8){ .static = "&" }, - '\'' => Escaped(u8){ .static = "'" }, - '<' => Escaped(u8){ .static = "<" }, - '>' => Escaped(u8){ .static = ">" }, - else => Escaped(u8){ .original = {} }, - }, - 2 => { - const first: []const u8 = switch (latin1[0]) { - '"' => """, - '&' => "&", - '\'' => "'", - '<' => "<", - '>' => ">", - else => latin1[0..1], - }; - const second: []const u8 = switch (latin1[1]) { - '"' => """, - '&' => "&", - '\'' => "'", - '<' => "<", - '>' => ">", - else => latin1[1..2], - }; - if (first.len == 1 and second.len == 1) { - return Escaped(u8){ .original = {} }; - } - - return Escaped(u8){ .allocated = strings.append(allocator, first, second) catch unreachable }; - }, - - // The simd implementation is slower for inputs less than 32 bytes. - 3 => return Scalar.push(3, latin1[0..3], allocator), - 4 => return Scalar.push(4, latin1[0..4], allocator), - 5 => return Scalar.push(5, latin1[0..5], allocator), - 6 => return Scalar.push(6, latin1[0..6], allocator), - 7 => return Scalar.push(7, latin1[0..7], allocator), - 8 => return Scalar.push(8, latin1[0..8], allocator), - 9 => return Scalar.push(9, latin1[0..9], allocator), - 10 => return Scalar.push(10, latin1[0..10], allocator), - 11 => return Scalar.push(11, latin1[0..11], allocator), - 12 => return Scalar.push(12, latin1[0..12], allocator), - 13 => return Scalar.push(13, latin1[0..13], allocator), - 14 => return Scalar.push(14, latin1[0..14], allocator), - 15 => return Scalar.push(15, latin1[0..15], allocator), - 16 => return Scalar.push(16, latin1[0..16], allocator), - 17 => return Scalar.push(17, latin1[0..17], allocator), - 18 => return Scalar.push(18, latin1[0..18], allocator), - 19 => return Scalar.push(19, latin1[0..19], allocator), - 20 => return Scalar.push(20, latin1[0..20], allocator), - 21 => return Scalar.push(21, latin1[0..21], allocator), - 22 => return Scalar.push(22, latin1[0..22], allocator), - 23 => return Scalar.push(23, latin1[0..23], allocator), - 24 => return Scalar.push(24, latin1[0..24], allocator), - 25 => return Scalar.push(25, latin1[0..25], allocator), - 26 => return Scalar.push(26, latin1[0..26], allocator), - 27 => return Scalar.push(27, latin1[0..27], allocator), - 28 => return Scalar.push(28, latin1[0..28], allocator), - 29 => return Scalar.push(29, latin1[0..29], allocator), - 30 => return Scalar.push(30, latin1[0..30], allocator), - 31 => return Scalar.push(31, latin1[0..31], allocator), - 32 => return Scalar.push(32, latin1[0..32], allocator), - - else => { - var remaining = latin1; - - const vec_chars = "\"&'<>"; - const vecs: [vec_chars.len]AsciiVector = comptime brk: { - var _vecs: [vec_chars.len]AsciiVector = undefined; - for (vec_chars, 0..) |c, i| { - _vecs[i] = @splat(c); - } - break :brk _vecs; - }; - - var any_needs_escape = false; - var buf: std.array_list.Managed(u8) = std.array_list.Managed(u8){ - .items = &.{}, - .capacity = 0, - .allocator = allocator, - }; - - if (comptime Environment.enableSIMD) { - // pass #1: scan for any characters that need escaping - // assume most strings won't need any escaping, so don't actually allocate the buffer - scan_and_allocate_lazily: while (remaining.len >= ascii_vector_size) { - if (comptime Environment.allow_assert) assert(!any_needs_escape); - const vec: AsciiVector = remaining[0..ascii_vector_size].*; - if (@reduce(.Max, @as(AsciiVectorU1, @bitCast((vec == vecs[0]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[1]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[2]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[3]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[4])))) == 1) - { - if (comptime Environment.allow_assert) assert(buf.capacity == 0); - - buf = try std.array_list.Managed(u8).initCapacity(allocator, latin1.len + 6); - const copy_len = @intFromPtr(remaining.ptr) - @intFromPtr(latin1.ptr); - buf.appendSliceAssumeCapacity(latin1[0..copy_len]); - any_needs_escape = true; - inline for (0..ascii_vector_size) |i| { - switch (vec[i]) { - '"' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + """.len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + """.len][0..""".len].* = """.*; - buf.items.len += """.len; - }, - '&' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + "&".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + "&".len][0.."&".len].* = "&".*; - buf.items.len += "&".len; - }, - '\'' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + "'".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + "'".len][0.."'".len].* = "'".*; - buf.items.len += "'".len; - }, - '<' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + "<".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + "<".len][0.."<".len].* = "<".*; - buf.items.len += "<".len; - }, - '>' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + ">".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + ">".len][0..">".len].* = ">".*; - buf.items.len += ">".len; - }, - else => |c| { - buf.appendAssumeCapacity(c); - }, - } - } - - remaining = remaining[ascii_vector_size..]; - break :scan_and_allocate_lazily; - } - - remaining = remaining[ascii_vector_size..]; - } - } - - if (any_needs_escape) { - // pass #2: we found something that needed an escape - // so we'll go ahead and copy the buffer into a new buffer - while (remaining.len >= ascii_vector_size) { - const vec: AsciiVector = remaining[0..ascii_vector_size].*; - if (@reduce(.Max, @as(AsciiVectorU1, @bitCast((vec == vecs[0]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[1]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[2]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[3]))) | - @as(AsciiVectorU1, @bitCast((vec == vecs[4])))) == 1) - { - buf.ensureUnusedCapacity(ascii_vector_size + 6) catch unreachable; - inline for (0..ascii_vector_size) |i| { - switch (vec[i]) { - '"' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + """.len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + """.len][0..""".len].* = """.*; - buf.items.len += """.len; - }, - '&' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + "&".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + "&".len][0.."&".len].* = "&".*; - buf.items.len += "&".len; - }, - '\'' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + "'".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + "'".len][0.."'".len].* = "'".*; - buf.items.len += "'".len; - }, - '<' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + "<".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + "<".len][0.."<".len].* = "<".*; - buf.items.len += "<".len; - }, - '>' => { - buf.ensureUnusedCapacity((ascii_vector_size - i) + ">".len) catch unreachable; - buf.items.ptr[buf.items.len .. buf.items.len + ">".len][0..">".len].* = ">".*; - buf.items.len += ">".len; - }, - else => |c| { - buf.appendAssumeCapacity(c); - }, - } - } - - remaining = remaining[ascii_vector_size..]; - continue; - } - - try buf.ensureUnusedCapacity(ascii_vector_size); - buf.items.ptr[buf.items.len .. buf.items.len + ascii_vector_size][0..ascii_vector_size].* = remaining[0..ascii_vector_size].*; - buf.items.len += ascii_vector_size; - remaining = remaining[ascii_vector_size..]; - } - } - - var ptr = remaining.ptr; - const end = remaining.ptr + remaining.len; - - if (!any_needs_escape) { - scan_and_allocate_lazily: while (ptr != end) : (ptr += 1) { - switch (ptr[0]) { - '"', '&', '\'', '<', '>' => |c| { - if (comptime Environment.allow_assert) assert(buf.capacity == 0); - - buf = try std.array_list.Managed(u8).initCapacity(allocator, latin1.len + @as(usize, Scalar.lengths[c])); - const copy_len = @intFromPtr(ptr) - @intFromPtr(latin1.ptr); - if (comptime Environment.allow_assert) assert(copy_len <= buf.capacity); - buf.items.len = copy_len; - @memcpy(buf.items[0..copy_len], latin1[0..copy_len]); - any_needs_escape = true; - break :scan_and_allocate_lazily; - }, - else => {}, - } - } - } - - while (ptr != end) : (ptr += 1) { - switch (ptr[0]) { - '"' => { - buf.appendSlice(""") catch unreachable; - }, - '&' => { - buf.appendSlice("&") catch unreachable; - }, - '\'' => { - buf.appendSlice("'") catch unreachable; // modified from escape-html; used to be ''' - }, - '<' => { - buf.appendSlice("<") catch unreachable; - }, - '>' => { - buf.appendSlice(">") catch unreachable; - }, - else => |c| { - buf.append(c) catch unreachable; - }, - } - } - - if (!any_needs_escape) { - if (comptime Environment.allow_assert) assert(buf.capacity == 0); - return Escaped(u8){ .original = {} }; - } - - return Escaped(u8){ .allocated = try buf.toOwnedSlice() }; - }, - } -} - -fn Escaped(comptime T: type) type { - return union(enum) { - static: []const u8, - original: void, - allocated: []T, - }; -} - -pub fn escapeHTMLForUTF16Input(allocator: std.mem.Allocator, utf16: []const u16) !Escaped(u16) { - const Scalar = struct { - pub const lengths: [std.math.maxInt(u8) + 1]u4 = brk: { - var values: [std.math.maxInt(u8) + 1]u4 = undefined; - for (values, 0..) |_, i| { - values[i] = switch (i) { - '"' => """.len, - '&' => "&".len, - '\'' => "'".len, - '<' => "<".len, - '>' => ">".len, - else => 1, - }; - } - - break :brk values; - }; - }; - switch (utf16.len) { - 0 => return Escaped(u16){ .static = &[_]u8{} }, - 1 => { - switch (utf16[0]) { - '"' => return Escaped(u16){ .static = """ }, - '&' => return Escaped(u16){ .static = "&" }, - '\'' => return Escaped(u16){ .static = "'" }, - '<' => return Escaped(u16){ .static = "<" }, - '>' => return Escaped(u16){ .static = ">" }, - else => return Escaped(u16){ .original = {} }, - } - }, - 2 => { - const first_16 = switch (utf16[0]) { - '"' => toUTF16Literal("""), - '&' => toUTF16Literal("&"), - '\'' => toUTF16Literal("'"), - '<' => toUTF16Literal("<"), - '>' => toUTF16Literal(">"), - else => @as([]const u16, utf16[0..1]), - }; - - const second_16 = switch (utf16[1]) { - '"' => toUTF16Literal("""), - '&' => toUTF16Literal("&"), - '\'' => toUTF16Literal("'"), - '<' => toUTF16Literal("<"), - '>' => toUTF16Literal(">"), - else => @as([]const u16, utf16[1..2]), - }; - - if (first_16.ptr == utf16.ptr and second_16.ptr == utf16.ptr + 1) { - return Escaped(u16){ .original = {} }; - } - - var buf = allocator.alloc(u16, first_16.len + second_16.len) catch unreachable; - bun.copy(u16, buf, first_16); - bun.copy(u16, buf[first_16.len..], second_16); - return Escaped(u16){ .allocated = buf }; - }, - - else => { - var remaining = utf16; - - var any_needs_escape = false; - var buf: std.array_list.Managed(u16) = undefined; - - if (comptime Environment.enableSIMD) { - const vec_chars = "\"&'<>"; - const vecs: [vec_chars.len]AsciiU16Vector = brk: { - var _vecs: [vec_chars.len]AsciiU16Vector = undefined; - for (vec_chars, 0..) |c, i| { - _vecs[i] = @splat(@as(u16, c)); - } - break :brk _vecs; - }; - // pass #1: scan for any characters that need escaping - // assume most strings won't need any escaping, so don't actually allocate the buffer - scan_and_allocate_lazily: while (remaining.len >= ascii_u16_vector_size) { - if (comptime Environment.allow_assert) assert(!any_needs_escape); - const vec: AsciiU16Vector = remaining[0..ascii_u16_vector_size].*; - if (@reduce(.Max, @as(AsciiVectorU16U1, @bitCast(vec > @as(AsciiU16Vector, @splat(@as(u16, 127))))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[0]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[1]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[2]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[3]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[4])))) == 1) - { - var i: u16 = 0; - lazy: { - while (i < ascii_u16_vector_size) { - switch (remaining[i]) { - '"', '&', '\'', '<', '>' => { - any_needs_escape = true; - break :lazy; - }, - 128...std.math.maxInt(u16) => { - const cp = utf16Codepoint(remaining[i..]); - i += @as(u16, cp.len); - }, - else => { - i += 1; - }, - } - } - } - - if (!any_needs_escape) { - remaining = remaining[i..]; - continue :scan_and_allocate_lazily; - } - - if (comptime Environment.allow_assert) assert(@intFromPtr(remaining.ptr + i) >= @intFromPtr(utf16.ptr)); - const to_copy = std.mem.sliceAsBytes(utf16)[0 .. @intFromPtr(remaining.ptr + i) - @intFromPtr(utf16.ptr)]; - const to_copy_16 = std.mem.bytesAsSlice(u16, to_copy); - buf = try std.array_list.Managed(u16).initCapacity(allocator, utf16.len + 6); - try buf.appendSlice(to_copy_16); - - while (i < ascii_u16_vector_size) { - switch (remaining[i]) { - '"', '&', '\'', '<', '>' => |c| { - const result = switch (c) { - '"' => toUTF16Literal("""), - '&' => toUTF16Literal("&"), - '\'' => toUTF16Literal("'"), - '<' => toUTF16Literal("<"), - '>' => toUTF16Literal(">"), - else => unreachable, - }; - - buf.appendSlice(result) catch unreachable; - i += 1; - }, - 128...std.math.maxInt(u16) => { - const cp = utf16Codepoint(remaining[i..]); - - buf.appendSlice(remaining[i..][0..@as(usize, cp.len)]) catch unreachable; - i += @as(u16, cp.len); - }, - else => |c| { - i += 1; - buf.append(c) catch unreachable; - }, - } - } - - // edgecase: code point width could exceed asdcii_u16_vector_size - remaining = remaining[i..]; - break :scan_and_allocate_lazily; - } - - remaining = remaining[ascii_u16_vector_size..]; - } - - if (any_needs_escape) { - // pass #2: we found something that needed an escape - // but there's still some more text to - // so we'll go ahead and copy the buffer into a new buffer - while (remaining.len >= ascii_u16_vector_size) { - const vec: AsciiU16Vector = remaining[0..ascii_u16_vector_size].*; - if (@reduce(.Max, @as(AsciiVectorU16U1, @bitCast(vec > @as(AsciiU16Vector, @splat(@as(u16, 127))))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[0]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[1]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[2]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[3]))) | - @as(AsciiVectorU16U1, @bitCast((vec == vecs[4])))) == 1) - { - buf.ensureUnusedCapacity(ascii_u16_vector_size) catch unreachable; - var i: u16 = 0; - while (i < ascii_u16_vector_size) { - switch (remaining[i]) { - '"' => { - buf.appendSlice(toUTF16Literal(""")) catch unreachable; - i += 1; - }, - '&' => { - buf.appendSlice(toUTF16Literal("&")) catch unreachable; - i += 1; - }, - '\'' => { - buf.appendSlice(toUTF16Literal("'")) catch unreachable; // modified from escape-html; used to be ''' - i += 1; - }, - '<' => { - buf.appendSlice(toUTF16Literal("<")) catch unreachable; - i += 1; - }, - '>' => { - buf.appendSlice(toUTF16Literal(">")) catch unreachable; - i += 1; - }, - 128...std.math.maxInt(u16) => { - const cp = utf16Codepoint(remaining[i..]); - - buf.appendSlice(remaining[i..][0..@as(usize, cp.len)]) catch unreachable; - i += @as(u16, cp.len); - }, - else => |c| { - buf.append(c) catch unreachable; - i += 1; - }, - } - } - - remaining = remaining[i..]; - continue; - } - - try buf.ensureUnusedCapacity(ascii_u16_vector_size); - buf.items.ptr[buf.items.len .. buf.items.len + ascii_u16_vector_size][0..ascii_u16_vector_size].* = remaining[0..ascii_u16_vector_size].*; - buf.items.len += ascii_u16_vector_size; - remaining = remaining[ascii_u16_vector_size..]; - } - } - } - - var ptr = remaining.ptr; - const end = remaining.ptr + remaining.len; - - if (!any_needs_escape) { - scan_and_allocate_lazily: while (ptr != end) { - switch (ptr[0]) { - '"', '&', '\'', '<', '>' => |c| { - buf = try std.array_list.Managed(u16).initCapacity(allocator, utf16.len + @as(usize, Scalar.lengths[c])); - if (comptime Environment.allow_assert) assert(@intFromPtr(ptr) >= @intFromPtr(utf16.ptr)); - - const to_copy = std.mem.sliceAsBytes(utf16)[0 .. @intFromPtr(ptr) - @intFromPtr(utf16.ptr)]; - const to_copy_16 = std.mem.bytesAsSlice(u16, to_copy); - try buf.appendSlice(to_copy_16); - any_needs_escape = true; - break :scan_and_allocate_lazily; - }, - 128...std.math.maxInt(u16) => { - const cp = utf16Codepoint(ptr[0..if (ptr + 1 == end) 1 else 2]); - - ptr += @as(u16, cp.len); - }, - else => { - ptr += 1; - }, - } - } - } - - while (ptr != end) { - switch (ptr[0]) { - '"' => { - buf.appendSlice(toUTF16Literal(""")) catch unreachable; - ptr += 1; - }, - '&' => { - buf.appendSlice(toUTF16Literal("&")) catch unreachable; - ptr += 1; - }, - '\'' => { - buf.appendSlice(toUTF16Literal("'")) catch unreachable; // modified from escape-html; used to be ''' - ptr += 1; - }, - '<' => { - buf.appendSlice(toUTF16Literal("<")) catch unreachable; - ptr += 1; - }, - '>' => { - buf.appendSlice(toUTF16Literal(">")) catch unreachable; - ptr += 1; - }, - 128...std.math.maxInt(u16) => { - const cp = utf16Codepoint(ptr[0..if (ptr + 1 == end) 1 else 2]); - - buf.appendSlice(ptr[0..@as(usize, cp.len)]) catch unreachable; - ptr += @as(u16, cp.len); - }, - - else => |c| { - buf.append(c) catch unreachable; - ptr += 1; - }, - } - } - - if (!any_needs_escape) { - return Escaped(u16){ .original = {} }; - } - - return Escaped(u16){ .allocated = try buf.toOwnedSlice() }; - }, - } -} - -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const assert = bun.assert; - -const strings = bun.strings; -const AsciiU16Vector = strings.AsciiU16Vector; -const AsciiVector = strings.AsciiVector; -const AsciiVectorU1 = strings.AsciiVectorU1; -const AsciiVectorU16U1 = strings.AsciiVectorU16U1; -const ascii_u16_vector_size = strings.ascii_u16_vector_size; -const ascii_vector_size = strings.ascii_vector_size; -const toUTF16Literal = strings.toUTF16Literal; -const utf16Codepoint = strings.utf16Codepoint; diff --git a/src/bun_core/string/immutable/exact_size_matcher.zig b/src/bun_core/string/immutable/exact_size_matcher.zig deleted file mode 100644 index acd702a750dc..000000000000 --- a/src/bun_core/string/immutable/exact_size_matcher.zig +++ /dev/null @@ -1,72 +0,0 @@ -pub fn ExactSizeMatcher(comptime max_bytes: usize) type { - switch (max_bytes) { - 1, 2, 4, 8, 12, 16 => {}, - else => { - @compileError("max_bytes must be 1, 2, 4, 8, 12, or 16."); - }, - } - - const T = std.meta.Int( - .unsigned, - max_bytes * 8, - ); - - return struct { - pub fn match(str: anytype) T { - switch (str.len) { - 1...max_bytes - 1 => { - var tmp: [max_bytes]u8 = undefined; - @memcpy(tmp[0..str.len], str); - @memset(tmp[str.len..], 0); - - return std.mem.readInt(T, &tmp, .little); - }, - max_bytes => { - return std.mem.readInt(T, str[0..max_bytes], .little); - }, - 0 => { - return 0; - }, - else => { - return std.math.maxInt(T); - }, - } - } - - pub fn matchLower(str: anytype) T { - switch (str.len) { - 1...max_bytes - 1 => { - var tmp: [max_bytes]u8 = undefined; - for (str, 0..) |char, i| { - tmp[i] = std.ascii.toLower(char); - } - @memset(tmp[str.len..], 0); - return std.mem.readInt(T, &tmp, .little); - }, - max_bytes => { - return std.mem.readInt(T, str[0..max_bytes], .little); - }, - 0 => { - return 0; - }, - else => { - return std.math.maxInt(T); - }, - } - } - - pub fn case(comptime str: []const u8) T { - if (str.len < max_bytes) { - var bytes = std.mem.zeroes([max_bytes]u8); - bytes[0..str.len].* = str[0..str.len].*; - return std.mem.readInt(T, &bytes, .little); - } else if (str.len == max_bytes) { - return std.mem.readInt(T, str[0..str.len], .little); - } else { - @compileError("str: \"" ++ str ++ "\" too long"); - } - } - }; -} - -const std = @import("std"); diff --git a/src/bun_core/string/immutable/unicode.zig b/src/bun_core/string/immutable/unicode.zig deleted file mode 100644 index dfb2a0d3dcbb..000000000000 --- a/src/bun_core/string/immutable/unicode.zig +++ /dev/null @@ -1,2042 +0,0 @@ -pub fn NewCodePointIterator(comptime CodePointType_: type, comptime zeroValue: comptime_int) type { - return struct { - const Iterator = @This(); - bytes: []const u8, - i: usize, - next_width: usize = 0, - width: u3_fast = 0, - c: CodePointType = zeroValue, - - pub const CodePointType = CodePointType_; - - pub const ZeroValue = zeroValue; - - pub const Cursor = struct { - i: u32 = 0, - c: CodePointType = zeroValue, - width: u3_fast = 0, - }; - - pub fn init(str: string) Iterator { - return Iterator{ .bytes = str, .i = 0, .c = zeroValue }; - } - - pub fn initOffset(str: string, i: usize) Iterator { - return Iterator{ .bytes = str, .i = i, .c = zeroValue }; - } - - const SkipResult = enum { - eof, - found, - not_found, - }; - - /// Advance forward until the scalar function returns true. - /// THe simd function is "best effort" and expected to sometimes return a result which `scalar` will return false for. - /// This is because we don't decode UTF-8 in the SIMD code path. - pub fn skip(it: *const Iterator, cursor: *Cursor, simd: *const fn (input: []const u8) ?usize, scalar: *const fn (CodePointType) bool) SkipResult { - while (true) { - // 1. Get current position. Check for EOF. - const current_byte_index = cursor.i; - if (current_byte_index >= it.bytes.len) { - return .not_found; // Reached end without finding - } - - // 2. Decode the *next* character using the standard iterator method. - if (!next(it, cursor)) { - return .not_found; // Reached end or error during decode - } - - // 3. Check if the character just decoded matches the scalar condition. - if (scalar(it.c)) { - return .found; // Found it! - } - - // 4. Optimization: Can we skip ahead using SIMD? - // Scan starting from the byte *after* the character we just decoded. - const next_scan_start_index = cursor.i; - if (next_scan_start_index >= it.bytes.len) { - // Just decoded the last character and it didn't match. - return .not_found; - } - const remaining_slice = it.bytes[next_scan_start_index..]; - if (remaining_slice.len == 0) { - return .not_found; - } - - // Ask SIMD for the next potential candidate. - if (simd(remaining_slice)) |pos| { - // SIMD found a potential candidate `pos` bytes ahead. - if (pos > 0) { - // Jump the byte index to the start of the potential candidate. - cursor.i = next_scan_start_index + @as(u32, @intCast(pos)); - // Reset width so next() decodes correctly from the jumped position. - cursor.width = 0; - // Loop will continue, starting the decode from the new cursor.i. - continue; - } - // If pos == 0, SIMD suggests the *immediate next* character. - // No jump needed, just let the loop iterate naturally. - // Fallthrough to the end of the loop. - } else { - // SIMD found no potential candidates in the rest of the string. - // Since the SIMD search set is a superset of the scalar check set, - // we can guarantee that no character satisfying `scalar` exists further. - // Since the current character (decoded in step 2) also didn't match, - // we can conclude the target character is not found. - return .not_found; - } - - // If we reach here, it means SIMD returned pos=0. - // Loop continues to the next iteration, processing the immediate next char. - } // End while true - - unreachable; - } - - pub inline fn next(noalias it: *const Iterator, noalias cursor: *Cursor) bool { - const pos: u32 = @as(u32, cursor.width) + cursor.i; - if (pos >= it.bytes.len) { - return false; - } - - const cp_len = wtf8ByteSequenceLength(it.bytes[pos]); - const error_char = comptime std.math.maxInt(CodePointType); - - const codepoint = @as( - CodePointType, - switch (cp_len) { - 0 => return false, - 1 => it.bytes[pos], - else => blk: { - // Copy into a zero-padded stack buffer so we never read past - // the end of `it.bytes` when a multi-byte lead appears near - // EOF without enough continuation bytes. The zero padding is - // rejected by decodeWTF8RuneTMultibyte (0x00 is not a valid - // continuation byte), so truncated sequences become U+FFFD. - const remaining = it.bytes[pos..]; - const cp_bytes: [4]u8 = switch (@min(remaining.len, 4)) { - inline 1, 2, 3, 4 => |n| .{ - remaining[0], - if (comptime n > 1) remaining[1] else 0, - if (comptime n > 2) remaining[2] else 0, - if (comptime n > 3) remaining[3] else 0, - }, - else => unreachable, - }; - break :blk decodeWTF8RuneTMultibyte(&cp_bytes, cp_len, CodePointType, error_char); - }, - }, - ); - - cursor.* = Cursor{ - .i = pos, - .c = if (error_char != codepoint) - codepoint - else - unicode_replacement, - .width = if (codepoint != error_char) cp_len else 1, - }; - - return true; - } - - fn nextCodepointSlice(it: *Iterator) callconv(bun.callconv_inline) []const u8 { - const bytes = it.bytes; - const prev = it.i; - const next_ = prev + it.next_width; - if (bytes.len <= next_) return ""; - - const cp_len = utf8ByteSequenceLength(bytes[next_]); - it.next_width = cp_len; - it.i = @min(next_, bytes.len); - - const slice = bytes[prev..][0..@min(@as(usize, cp_len), bytes.len - prev)]; - it.width = @as(u3_fast, @intCast(slice.len)); - return slice; - } - - pub fn needsUTF8Decoding(slice: string) bool { - var it = Iterator{ .bytes = slice, .i = 0 }; - - while (true) { - const part = it.nextCodepointSlice(); - @setRuntimeSafety(false); - switch (part.len) { - 0 => return false, - 1 => continue, - else => return true, - } - } - } - - pub fn scanUntilQuotedValueOrEOF(iter: *Iterator, comptime quote: CodePointType) usize { - while (iter.c > -1) { - if (!switch (iter.nextCodepoint()) { - quote => false, - '\\' => brk: { - if (iter.nextCodepoint() == quote) { - continue; - } - break :brk true; - }, - else => true, - }) { - return iter.i + 1; - } - } - - return iter.i; - } - - pub fn nextCodepoint(it: *Iterator) CodePointType { - const slice = it.nextCodepointSlice(); - - it.c = switch (slice.len) { - 0 => zeroValue, - 1 => @as(CodePointType, @intCast(slice[0])), - 2 => @as(CodePointType, @intCast(std.unicode.utf8Decode2(slice) catch unreachable)), - 3 => @as(CodePointType, @intCast(std.unicode.utf8Decode3(slice) catch unreachable)), - 4 => @as(CodePointType, @intCast(std.unicode.utf8Decode4(slice) catch unreachable)), - else => unreachable, - }; - - return it.c; - } - - /// Look ahead at the next n codepoints without advancing the iterator. - /// If fewer than n codepoints are available, then return the remainder of the string. - pub fn peek(it: *Iterator, n: usize) []const u8 { - const original_i = it.i; - defer it.i = original_i; - - var end_ix = original_i; - for (0..n) |_| { - const next_codepoint = it.nextCodepointSlice() orelse return it.bytes[original_i..]; - end_ix += next_codepoint.len; - } - - return it.bytes[original_i..end_ix]; - } - }; -} - -pub const CodepointIterator = NewCodePointIterator(CodePoint, -1); -pub const UnsignedCodepointIterator = NewCodePointIterator(u32, 0); - -pub fn containsNonBmpCodePoint(text: string) bool { - var iter = CodepointIterator.init(text); - var curs = CodepointIterator.Cursor{}; - - while (iter.next(&curs)) { - if (curs.c > 0xFFFF) { - return true; - } - } - - return false; -} - -pub fn containsNonBmpCodePointOrIsInvalidIdentifier(text: string) bool { - var iter = CodepointIterator.init(text); - var curs = CodepointIterator.Cursor{}; - - if (!iter.next(&curs)) return true; - - if (curs.c > 0xFFFF or !js_lexer.isIdentifierStart(curs.c)) - return true; - - while (iter.next(&curs)) { - if (curs.c > 0xFFFF or !js_lexer.isIdentifierContinue(curs.c)) { - return true; - } - } - - return false; -} - -/// Convert potentially ill-formed UTF-8 or UTF-16 bytes to a Unicode Codepoint. -/// - Invalid codepoints are replaced with `zero` parameter -/// - Null bytes return 0 -pub fn decodeWTF8RuneT(p: *const [4]u8, len: u3_fast, comptime T: type, comptime zero: T) T { - if (len == 0) return zero; - if (len == 1) return p[0]; - - return decodeWTF8RuneTMultibyte(p, len, T, zero); -} - -pub fn codepointSize(comptime R: type, r: R) u3_fast { - return switch (r) { - 0b0000_0000...0b0111_1111 => 1, - 0b1100_0000...0b1101_1111 => 2, - 0b1110_0000...0b1110_1111 => 3, - 0b1111_0000...0b1111_0111 => 4, - else => 0, - }; -} - -pub fn convertUTF16ToUTF8(list_: std.array_list.Managed(u8), utf16: []const u16) OOM!std.array_list.Managed(u8) { - var list = list_; - const result = bun.simdutf.convert.utf16.to.utf8.with_errors.le( - utf16, - list.allocatedSlice(), - ); - if (result.status == .surrogate) { - // Slow path: there was invalid UTF-16, so we need to convert it without simdutf. - return toUTF8ListWithTypeBun(&list, utf16, false); - } - - list.items.len = result.count; - return list; -} - -pub fn convertUTF16ToUTF8WithoutInvalidSurrogatePairs(list_: std.array_list.Managed(u8), utf16: []const u16) error{SurrogatePair}!std.array_list.Managed(u8) { - var list = list_; - const result = bun.simdutf.convert.utf16.to.utf8.with_errors.le( - utf16, - list.allocatedSlice(), - ); - if (result.status == .surrogate) { - return error.SurrogatePair; - } - - list.items.len = result.count; - return list; -} - -pub fn convertUTF16ToUTF8Append(list: *std.array_list.Managed(u8), utf16: []const u16) OOM!void { - const result = bun.simdutf.convert.utf16.to.utf8.with_errors.le( - utf16, - list.unusedCapacitySlice(), - ); - - if (result.status == .surrogate) { - // Slow path: there was invalid UTF-16, so we need to convert it without simdutf. - _ = try toUTF8ListWithTypeBun(list, utf16, false); - return; - } - - list.items.len += result.count; -} - -pub fn toUTF8AllocWithTypeWithoutInvalidSurrogatePairs(allocator: std.mem.Allocator, utf16: []const u16) OOM![]u8 { - // previously, this function was an exact copy of `toUTF8AllocWithType`. - // TODO: actually make this function behave differently? - return toUTF8AllocWithType(allocator, utf16); -} - -pub fn toUTF8AllocWithType(allocator: std.mem.Allocator, utf16: []const u16) OOM![]u8 { - if (bun.FeatureFlags.use_simdutf) { - const length = bun.simdutf.length.utf8.from.utf16.le(utf16); - // add 16 bytes of padding for SIMDUTF - var list = try std.array_list.Managed(u8).initCapacity(allocator, length + 16); - list = try convertUTF16ToUTF8(list, utf16); - return list.toOwnedSlice(); - } - - var list = try std.array_list.Managed(u8).initCapacity(allocator, utf16.len); - list = try toUTF8ListWithType(list, utf16); - return list.toOwnedSlice(); -} - -pub fn toUTF8ListWithType(list_: std.array_list.Managed(u8), utf16: []const u16) OOM!std.array_list.Managed(u8) { - if (bun.FeatureFlags.use_simdutf) { - var list = list_; - const length = bun.simdutf.length.utf8.from.utf16.le(utf16); - try list.ensureTotalCapacityPrecise(length + 16); - const buf = try convertUTF16ToUTF8(list, utf16); - - // Commenting out because `convertUTF16ToUTF8` may convert to WTF-8 - // which uses 3 bytes for invalid surrogates, causing the length to not - // match from simdutf. - // if (Environment.allow_assert) { - // bun.unsafeAssert(buf.items.len == length); - // } - - return buf; - } - - @compileError("not implemented"); -} - -pub fn toUTF8AppendToList(list: *std.array_list.Managed(u8), utf16: []const u16) !void { - if (!bun.FeatureFlags.use_simdutf) { - @compileError("not implemented"); - } - const length = bun.simdutf.length.utf8.from.utf16.le(utf16); - try list.ensureUnusedCapacity(length + 16); - try convertUTF16ToUTF8Append(list, utf16); -} - -pub fn toUTF8FromLatin1(allocator: std.mem.Allocator, latin1: []const u8) !?std.array_list.Managed(u8) { - if (isAllASCII(latin1)) - return null; - - const list = try std.array_list.Managed(u8).initCapacity(allocator, latin1.len); - return try allocateLatin1IntoUTF8WithList(list, 0, latin1); -} - -pub fn toUTF8FromLatin1Z(allocator: std.mem.Allocator, latin1: []const u8) !?std.array_list.Managed(u8) { - if (isAllASCII(latin1)) - return null; - - const list = try std.array_list.Managed(u8).initCapacity(allocator, latin1.len + 1); - var list1 = try allocateLatin1IntoUTF8WithList(list, 0, latin1); - try list1.append(0); - return list1; -} - -pub fn toUTF8ListWithTypeBun(list: *std.array_list.Managed(u8), utf16: []const u16, comptime skip_trailing_replacement: bool) OOM!(if (skip_trailing_replacement) ?u16 else std.array_list.Managed(u8)) { - var utf16_remaining = utf16; - - while (firstNonASCII16(utf16_remaining)) |i| { - const to_copy = utf16_remaining[0..i]; - utf16_remaining = utf16_remaining[i..]; - const token = utf16_remaining[0]; - - const replacement = utf16CodepointWithFFFDAndFirstInputChar(token, utf16_remaining); - utf16_remaining = utf16_remaining[replacement.len..]; - - const count: usize = replacement.utf8Width(); - if (comptime Environment.isNative) { - try list.ensureTotalCapacityPrecise(i + count + list.items.len + @as(usize, @intFromFloat((@as(f64, @floatFromInt(@as(u52, @truncate(utf16_remaining.len)))) * 1.2)))); - } else { - try list.ensureTotalCapacityPrecise(i + count + list.items.len + utf16_remaining.len + 4); - } - list.items.len += i; - - copyU16IntoU8(list.items[list.items.len - i ..], to_copy); - - if (comptime skip_trailing_replacement) { - if (replacement.is_lead and utf16_remaining.len == 0) { - return token; - } - } - - list.items.len += count; - _ = encodeWTF8RuneT( - list.items.ptr[list.items.len - count .. list.items.len - count + 4][0..4], - u32, - @as(u32, replacement.code_point), - ); - } - - if (utf16_remaining.len > 0) { - try list.ensureTotalCapacityPrecise(utf16_remaining.len + list.items.len); - const old_len = list.items.len; - list.items.len += utf16_remaining.len; - copyU16IntoU8(list.items[old_len..], utf16_remaining); - } - - log("UTF16 {d} -> {d} UTF8", .{ utf16.len, list.items.len }); - - if (comptime skip_trailing_replacement) { - return null; - } - return list.*; -} - -pub const EncodeIntoResult = struct { - /// The number of u16s we read from the utf-16 buffer - read: u32 = 0, - /// The number of u8s we wrote to the utf-8 buffer - written: u32 = 0, -}; -pub fn allocateLatin1IntoUTF8(allocator: std.mem.Allocator, latin1_: []const u8) ![]u8 { - const list = try std.array_list.Managed(u8).initCapacity(allocator, latin1_.len); - var foo = try allocateLatin1IntoUTF8WithList(list, 0, latin1_); - return try foo.toOwnedSlice(); -} - -pub fn allocateLatin1IntoUTF8WithList(list_: std.array_list.Managed(u8), offset_into_list: usize, latin1_: []const u8) OOM!std.array_list.Managed(u8) { - var latin1 = latin1_; - var i: usize = offset_into_list; - var list = list_; - try list.ensureUnusedCapacity(latin1.len); - - while (latin1.len > 0) { - if (comptime Environment.allow_assert) assert(i < list.capacity); - var buf = list.items.ptr[i..list.capacity]; - - inner: { - var count = latin1.len / ascii_vector_size; - while (count > 0) : (count -= 1) { - const vec: AsciiVector = latin1[0..ascii_vector_size].*; - - if (@reduce(.Max, vec) > 127) { - const Int = u64; - const size = @sizeOf(Int); - - // zig or LLVM doesn't do @ctz nicely with SIMD - if (comptime ascii_vector_size >= 8) { - { - const bytes = @as(Int, @bitCast(latin1[0..size].*)); - // https://dotat.at/@/2022-06-27-tolower-swar.html - const mask = bytes & 0x8080808080808080; - - if (mask > 0) { - const first_set_byte = @ctz(mask) / 8; - if (comptime Environment.allow_assert) assert(latin1[first_set_byte] >= 127); - - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - buf = buf[first_set_byte..]; - latin1 = latin1[first_set_byte..]; - break :inner; - } - - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - latin1 = latin1[size..]; - buf = buf[size..]; - } - - if (comptime ascii_vector_size >= 16) { - const bytes = @as(Int, @bitCast(latin1[0..size].*)); - // https://dotat.at/@/2022-06-27-tolower-swar.html - const mask = bytes & 0x8080808080808080; - - if (mask > 0) { - const first_set_byte = @ctz(mask) / 8; - if (comptime Environment.allow_assert) assert(latin1[first_set_byte] >= 127); - - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - buf = buf[first_set_byte..]; - latin1 = latin1[first_set_byte..]; - break :inner; - } - } - } - unreachable; - } - - buf[0..ascii_vector_size].* = @as([ascii_vector_size]u8, @bitCast(vec))[0..ascii_vector_size].*; - latin1 = latin1[ascii_vector_size..]; - buf = buf[ascii_vector_size..]; - } - - while (latin1.len >= 8) { - const Int = u64; - const size = @sizeOf(Int); - - const bytes = @as(Int, @bitCast(latin1[0..size].*)); - // https://dotat.at/@/2022-06-27-tolower-swar.html - const mask = bytes & 0x8080808080808080; - - if (mask > 0) { - const first_set_byte = @ctz(mask) / 8; - if (comptime Environment.allow_assert) assert(latin1[first_set_byte] >= 127); - - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - latin1 = latin1[first_set_byte..]; - buf = buf[first_set_byte..]; - break :inner; - } - - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - latin1 = latin1[size..]; - buf = buf[size..]; - } - - { - if (comptime Environment.allow_assert) assert(latin1.len < 8); - const end = latin1.ptr + latin1.len; - while (latin1.ptr != end and latin1[0] < 128) { - buf[0] = latin1[0]; - buf = buf[1..]; - latin1 = latin1[1..]; - } - } - } - - while (latin1.len > 0 and latin1[0] > 127) { - i = @intFromPtr(buf.ptr) - @intFromPtr(list.items.ptr); - list.items.len = i; - try list.ensureUnusedCapacity(2 + latin1.len); - buf = list.items.ptr[i..list.capacity]; - buf[0..2].* = latin1ToCodepointBytesAssumeNotASCII(latin1[0]); - latin1 = latin1[1..]; - buf = buf[2..]; - } - - i = @intFromPtr(buf.ptr) - @intFromPtr(list.items.ptr); - list.items.len = i; - } - - log("Latin1 {d} -> UTF8 {d}", .{ latin1_.len, i }); - - return list; -} - -pub const UTF16Replacement = struct { - code_point: u32 = unicode_replacement, - len: u3_fast = 0, - - /// Explicit fail boolean to distinguish between a Unicode Replacement Codepoint - /// that was already in there - /// and a genuine error. - fail: bool = false, - - can_buffer: bool = true, - is_lead: bool = false, - - pub inline fn utf8Width(replacement: UTF16Replacement) u3_fast { - return switch (replacement.code_point) { - 0...0x7F => 1, - (0x7F + 1)...0x7FF => 2, - (0x7FF + 1)...0xFFFF => 3, - else => 4, - }; - } -}; - -pub fn convertUTF8BytesIntoUTF16WithLength(sequence: *const [4]u8, len: u3_fast, remaining_len: usize) UTF16Replacement { - if (comptime Environment.allow_assert) assert(sequence[0] > 127); - switch (len) { - 2 => { - if (comptime Environment.allow_assert) { - bun.assert(sequence[0] >= 0xC0); - bun.assert(sequence[0] <= 0xDF); - } - if (sequence[1] < 0x80 or sequence[1] > 0xBF) { - return .{ .len = 1, .fail = true, .can_buffer = remaining_len < 2 }; - } - return .{ .len = len, .code_point = ((@as(u32, sequence[0]) << 6) + @as(u32, sequence[1])) - 0x00003080 }; - }, - 3 => { - if (comptime Environment.allow_assert) { - bun.assert(sequence[0] >= 0xE0); - bun.assert(sequence[0] <= 0xEF); - } - switch (sequence[0]) { - 0xE0 => { - if (sequence[1] < 0xA0 or sequence[1] > 0xBF) { - return .{ .len = 1, .fail = true, .can_buffer = remaining_len < 2 }; - } - }, - 0xED => { - if (sequence[1] < 0x80 or sequence[1] > 0x9F) { - return .{ .len = 1, .fail = true, .can_buffer = remaining_len < 2 }; - } - }, - else => { - if (sequence[1] < 0x80 or sequence[1] > 0xBF) { - return .{ .len = 1, .fail = true, .can_buffer = remaining_len < 2 }; - } - }, - } - if (sequence[2] < 0x80 or sequence[2] > 0xBF) { - return .{ .len = 2, .fail = true, .can_buffer = remaining_len < 3 }; - } - return .{ - .len = len, - .code_point = ((@as(u32, sequence[0]) << 12) + (@as(u32, sequence[1]) << 6) + @as(u32, sequence[2])) - 0x000E2080, - }; - }, - 4 => { - switch (sequence[0]) { - 0xF0 => { - if (sequence[1] < 0x90 or sequence[1] > 0xBF) { - return .{ .len = 1, .fail = true, .can_buffer = remaining_len < 2 }; - } - }, - 0xF4 => { - if (sequence[1] < 0x80 or sequence[1] > 0x8F) { - return .{ .len = 1, .fail = true, .can_buffer = remaining_len < 2 }; - } - }, - - // invalid code point - // this used to be an assertion - 0...(0xF0 - 1), 0xF4 + 1...std.math.maxInt(@TypeOf(sequence[0])) => { - return .{ .len = 1, .fail = true, .can_buffer = false }; - }, - - else => { - if (sequence[1] < 0x80 or sequence[1] > 0xBF) { - return .{ .len = 1, .fail = true, .can_buffer = remaining_len < 2 }; - } - }, - } - - if (sequence[2] < 0x80 or sequence[2] > 0xBF) { - return .{ .len = 2, .fail = true, .can_buffer = remaining_len < 3 }; - } - if (sequence[3] < 0x80 or sequence[3] > 0xBF) { - return .{ .len = 3, .fail = true, .can_buffer = remaining_len < 4 }; - } - return .{ - .len = len, - .code_point = ((@as(u32, sequence[0]) << 18) + - (@as(u32, sequence[1]) << 12) + - (@as(u32, sequence[2]) << 6) + @as(u32, sequence[3])) - 0x03C82080, - }; - }, - // invalid unicode sequence - // 1 or 0 are both invalid here - else => return UTF16Replacement{ .len = 1, .fail = true }, - } -} - -// This variation matches WebKit behavior. -// fn convertUTF8BytesIntoUTF16(sequence: *const [4]u8, remaining_len: usize) UTF16Replacement { -pub fn convertUTF8BytesIntoUTF16(bytes: []const u8) UTF16Replacement { - const sequence: [4]u8 = switch (bytes.len) { - 0 => unreachable, - 1 => [_]u8{ bytes[0], 0, 0, 0 }, - 2 => [_]u8{ bytes[0], bytes[1], 0, 0 }, - 3 => [_]u8{ bytes[0], bytes[1], bytes[2], 0 }, - else => bytes[0..4].*, - }; - if (comptime Environment.allow_assert) assert(sequence[0] > 127); - const sequence_length = nonASCIISequenceLength(sequence[0]); - return convertUTF8BytesIntoUTF16WithLength(&sequence, sequence_length, bytes.len); -} - -pub fn copyLatin1IntoUTF8(buf_: []u8, latin1_: []const u8) EncodeIntoResult { - return copyLatin1IntoUTF8StopOnNonASCII(buf_, latin1_, false); -} - -pub fn copyLatin1IntoUTF8StopOnNonASCII(buf_: []u8, latin1_: []const u8, comptime stop: bool) EncodeIntoResult { - var buf = buf_; - var latin1 = latin1_; - - log("latin1 encode {d} -> {d}", .{ buf.len, latin1.len }); - - while (buf.len > 0 and latin1.len > 0) { - inner: { - var remaining_runs = @min(buf.len, latin1.len) / ascii_vector_size; - while (remaining_runs > 0) : (remaining_runs -= 1) { - const vec: AsciiVector = latin1[0..ascii_vector_size].*; - - if (@reduce(.Max, vec) > 127) { - if (comptime stop) return .{ .written = std.math.maxInt(u32), .read = std.math.maxInt(u32) }; - - // zig or LLVM doesn't do @ctz nicely with SIMD - if (comptime ascii_vector_size >= 8) { - const Int = u64; - const size = @sizeOf(Int); - - { - const bytes = @as(Int, @bitCast(latin1[0..size].*)); - // https://dotat.at/@/2022-06-27-tolower-swar.html - const mask = bytes & 0x8080808080808080; - - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - - if (mask > 0) { - const first_set_byte = @ctz(mask) / 8; - if (comptime Environment.allow_assert) assert(latin1[first_set_byte] >= 127); - - buf = buf[first_set_byte..]; - latin1 = latin1[first_set_byte..]; - break :inner; - } - - latin1 = latin1[size..]; - buf = buf[size..]; - } - - if (comptime ascii_vector_size >= 16) { - const bytes = @as(Int, @bitCast(latin1[0..size].*)); - // https://dotat.at/@/2022-06-27-tolower-swar.html - const mask = bytes & 0x8080808080808080; - - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - - if (comptime Environment.allow_assert) assert(mask > 0); - const first_set_byte = @ctz(mask) / 8; - if (comptime Environment.allow_assert) assert(latin1[first_set_byte] >= 127); - - buf = buf[first_set_byte..]; - latin1 = latin1[first_set_byte..]; - break :inner; - } - } - unreachable; - } - - buf[0..ascii_vector_size].* = @as([ascii_vector_size]u8, @bitCast(vec))[0..ascii_vector_size].*; - latin1 = latin1[ascii_vector_size..]; - buf = buf[ascii_vector_size..]; - } - - { - const Int = u64; - const size = @sizeOf(Int); - while (@min(buf.len, latin1.len) >= size) { - const bytes = @as(Int, @bitCast(latin1[0..size].*)); - buf[0..size].* = @as([size]u8, @bitCast(bytes)); - - // https://dotat.at/@/2022-06-27-tolower-swar.html - - const mask = bytes & 0x8080808080808080; - - if (mask > 0) { - const first_set_byte = @ctz(mask) / 8; - if (comptime stop) return .{ .written = std.math.maxInt(u32), .read = std.math.maxInt(u32) }; - if (comptime Environment.allow_assert) assert(latin1[first_set_byte] >= 127); - - buf = buf[first_set_byte..]; - latin1 = latin1[first_set_byte..]; - - break :inner; - } - - latin1 = latin1[size..]; - buf = buf[size..]; - } - } - - { - const end = latin1.ptr + @min(buf.len, latin1.len); - if (comptime Environment.allow_assert) assert(@intFromPtr(latin1.ptr + 8) > @intFromPtr(end)); - const start_ptr = @intFromPtr(buf.ptr); - const start_ptr_latin1 = @intFromPtr(latin1.ptr); - - while (latin1.ptr != end and latin1.ptr[0] <= 127) { - buf.ptr[0] = latin1.ptr[0]; - buf.ptr += 1; - latin1.ptr += 1; - } - - buf.len -= @intFromPtr(buf.ptr) - start_ptr; - latin1.len -= @intFromPtr(latin1.ptr) - start_ptr_latin1; - } - } - - if (latin1.len > 0) { - if (buf.len >= 2) { - if (comptime stop) return .{ .written = std.math.maxInt(u32), .read = std.math.maxInt(u32) }; - - buf[0..2].* = latin1ToCodepointBytesAssumeNotASCII(latin1[0]); - latin1 = latin1[1..]; - buf = buf[2..]; - } else { - break; - } - } - } - - return .{ - .written = @as(u32, @truncate(buf_.len - buf.len)), - .read = @as(u32, @truncate(latin1_.len - latin1.len)), - }; -} - -pub fn replaceLatin1WithUTF8(buf_: []u8) void { - var latin1 = buf_; - while (strings.firstNonASCII(latin1)) |i| { - latin1[i..][0..2].* = latin1ToCodepointBytesAssumeNotASCII(latin1[i]); - - latin1 = latin1[i + 2 ..]; - } -} - -pub fn elementLengthLatin1IntoUTF8(slice: []const u8) usize { - return bun.simdutf.length.utf8.from.latin1(slice); -} - -pub fn copyCP1252IntoUTF16(buf_: []u16, latin1_: []const u8) EncodeIntoResult { - var buf = buf_; - var latin1 = latin1_; - while (buf.len > 0 and latin1.len > 0) { - const to_write = strings.firstNonASCII(latin1) orelse @as(u32, @truncate(@min(latin1.len, buf.len))); - strings.copyU8IntoU16(buf, latin1[0..to_write]); - - latin1 = latin1[to_write..]; - buf = buf[to_write..]; - if (latin1.len > 0 and buf.len >= 1) { - buf[0] = cp1252ToCodepointBytesAssumeNotASCII16(latin1[0]); - latin1 = latin1[1..]; - buf = buf[1..]; - } - } - - return .{ - .read = @as(u32, @truncate(buf_.len - buf.len)), - .written = @as(u32, @truncate(latin1_.len - latin1.len)), - }; -} - -pub fn copyLatin1IntoUTF16(comptime Buffer: type, buf_: Buffer, latin1_: []const u8) EncodeIntoResult { - const len = @min(buf_.len, latin1_.len); - for (buf_[0..len], latin1_[0..len]) |*out, in| out.* = in; - return .{ .read = @as(u32, @truncate(len)), .written = @as(u32, @truncate(len)) }; -} - -pub fn elementLengthCP1252IntoUTF16(cp1252_: []const u8) usize { - // cp1252 is always at most 1 UTF-16 code unit long - return cp1252_.len; -} - -pub fn eqlUtf16(comptime self: string, other: []const u16) bool { - if (self.len != other.len) return false; - - if (self.len == 0) return true; - - return bun.C.memcmp(bun.cast([*]const u8, self.ptr), bun.cast([*]const u8, other.ptr), self.len * @sizeOf(u16)) == 0; -} - -pub fn toUTF8Alloc(allocator: std.mem.Allocator, js: []const u16) OOM![]u8 { - return try toUTF8AllocWithType(allocator, js); -} - -pub fn toUTF8AllocZ(allocator: std.mem.Allocator, js: []const u16) OOM![:0]u8 { - var list = std.array_list.Managed(u8).init(allocator); - try toUTF8AppendToList(&list, js); - try list.append(0); - return list.items[0 .. list.items.len - 1 :0]; -} - -pub fn appendUTF8MachineWordToUTF16MachineWord(output: *[@sizeOf(usize) / 2]u16, input: *const [@sizeOf(usize) / 2]u8) callconv(bun.callconv_inline) void { - output[0 .. @sizeOf(usize) / 2].* = @as( - [4]u16, - @bitCast(@as( - @Vector(4, u16), - @as(@Vector(4, u8), @bitCast(input[0 .. @sizeOf(usize) / 2].*)), - )), - ); -} - -pub fn copyU8IntoU16(output_: []u16, input_: []const u8) callconv(bun.callconv_inline) void { - const output = output_; - const input = input_; - if (comptime Environment.allow_assert) assert(input.len <= output.len); - - // https://zig.godbolt.org/z/9rTn1orcY - - var input_ptr = input.ptr; - var output_ptr = output.ptr; - - const last_input_ptr = input_ptr + @min(input.len, output.len); - - while (last_input_ptr != input_ptr) { - output_ptr[0] = input_ptr[0]; - output_ptr += 1; - input_ptr += 1; - } -} - -pub inline fn copyU16IntoU8(output: []u8, input: []align(1) const u16) void { - if (comptime Environment.allow_assert) assert(input.len <= output.len); - const count = @min(input.len, output.len); - - bun.highway.copyU16ToU8(input[0..count], output[0..count]); -} - -pub fn copyLatin1IntoASCII(dest: []u8, src: []const u8) void { - var remain = src; - var to = dest; - - const non_ascii_offset = strings.firstNonASCII(remain) orelse @as(u32, @truncate(remain.len)); - if (non_ascii_offset > 0) { - @memcpy(to[0..non_ascii_offset], remain[0..non_ascii_offset]); - remain = remain[non_ascii_offset..]; - to = to[non_ascii_offset..]; - - // ascii fast path - if (remain.len == 0) { - return; - } - } - - if (to.len >= 16 and bun.Environment.enableSIMD) { - const vector_size = 16; - // https://zig.godbolt.org/z/qezsY8T3W - const remain_in_u64 = remain[0 .. remain.len - (remain.len % vector_size)]; - const to_in_u64 = to[0 .. to.len - (to.len % vector_size)]; - var remain_as_u64 = std.mem.bytesAsSlice(u64, remain_in_u64); - var to_as_u64 = std.mem.bytesAsSlice(u64, to_in_u64); - const end_vector_len = @min(remain_as_u64.len, to_as_u64.len); - remain_as_u64 = remain_as_u64[0..end_vector_len]; - to_as_u64 = to_as_u64[0..end_vector_len]; - const end_ptr = remain_as_u64.ptr + remain_as_u64.len; - // using the pointer instead of the length is super important for the codegen - while (end_ptr != remain_as_u64.ptr) { - const buf = remain_as_u64[0]; - // this gets auto-vectorized - const mask = @as(u64, 0x7f7f7f7f7f7f7f7f); - to_as_u64[0] = buf & mask; - - remain_as_u64 = remain_as_u64[1..]; - to_as_u64 = to_as_u64[1..]; - } - remain = remain[remain_in_u64.len..]; - to = to[to_in_u64.len..]; - } - - for (to) |*to_byte| { - to_byte.* = @as(u8, @as(u7, @truncate(remain[0]))); - remain = remain[1..]; - } -} - -/// It is common on Windows to find files that are not encoded in UTF8. Most of these include -/// a 'byte-order mark' codepoint at the start of the file. The layout of this codepoint can -/// determine the encoding. -/// -/// https://en.wikipedia.org/wiki/Byte_order_mark -pub const BOM = enum { - utf8, - utf16_le, - utf16_be, - utf32_le, - utf32_be, - - pub const utf8_bytes = [_]u8{ 0xef, 0xbb, 0xbf }; - pub const utf16_le_bytes = [_]u8{ 0xff, 0xfe }; - pub const utf16_be_bytes = [_]u8{ 0xfe, 0xff }; - pub const utf32_le_bytes = [_]u8{ 0xff, 0xfe, 0x00, 0x00 }; - pub const utf32_be_bytes = [_]u8{ 0x00, 0x00, 0xfe, 0xff }; - - pub fn detect(bytes: []const u8) ?BOM { - if (bytes.len < 3) return null; - if (eqlComptimeIgnoreLen(bytes, utf8_bytes)) return .utf8; - if (eqlComptimeIgnoreLen(bytes, utf16_le_bytes)) { - // if (bytes.len > 4 and eqlComptimeIgnoreLen(bytes[2..], utf32_le_bytes[2..])) - // return .utf32_le; - return .utf16_le; - } - // if (eqlComptimeIgnoreLen(bytes, utf16_be_bytes)) return .utf16_be; - // if (bytes.len > 4 and eqlComptimeIgnoreLen(bytes, utf32_le_bytes)) return .utf32_le; - return null; - } - - pub fn detectAndSplit(bytes: []const u8) struct { ?BOM, []const u8 } { - const bom = detect(bytes); - if (bom == null) return .{ null, bytes }; - return .{ bom, bytes[bom.?.length()..] }; - } - - pub fn getHeader(bom: BOM) []const u8 { - return switch (bom) { - inline else => |t| comptime &@field(BOM, @tagName(t) ++ "_bytes"), - }; - } - - pub fn length(bom: BOM) usize { - return switch (bom) { - inline else => |t| comptime (&@field(BOM, @tagName(t) ++ "_bytes")).len, - }; - } - - /// If an allocation is needed, free the input and the caller will - /// replace it with the new return - pub fn removeAndConvertToUTF8AndFree(bom: BOM, allocator: std.mem.Allocator, bytes: []u8) OOM![]u8 { - switch (bom) { - .utf8 => { - _ = bun.c.memmove(bytes.ptr, bytes.ptr + utf8_bytes.len, bytes.len - utf8_bytes.len); - return bytes[0 .. bytes.len - utf8_bytes.len]; - }, - .utf16_le => { - const trimmed_bytes = bytes[utf16_le_bytes.len..]; - const trimmed_bytes_u16: []const u16 = @alignCast(std.mem.bytesAsSlice(u16, trimmed_bytes)); - const out = try toUTF8Alloc(allocator, trimmed_bytes_u16); - allocator.free(bytes); - return out; - }, - else => { - // TODO: this needs to re-encode, for now we just remove the BOM - const bom_bytes = bom.getHeader(); - _ = bun.c.memmove(bytes.ptr, bytes.ptr + bom_bytes.len, bytes.len - bom_bytes.len); - return bytes[0 .. bytes.len - bom_bytes.len]; - }, - } - } - - /// This is required for fs.zig's `use_shared_buffer` flag. we cannot free that pointer. - /// The returned slice will always point to the base of the input. - /// - /// Requires an arraylist in case it must be grown. - pub fn removeAndConvertToUTF8WithoutDealloc(bom: BOM, allocator: std.mem.Allocator, list: *std.ArrayListUnmanaged(u8)) ![]u8 { - const bytes = list.items; - switch (bom) { - .utf8 => { - bun.C.memmove(bytes.ptr, bytes.ptr + utf8_bytes.len, bytes.len - utf8_bytes.len); - return bytes[0 .. bytes.len - utf8_bytes.len]; - }, - .utf16_le => { - const trimmed_bytes = bytes[utf16_le_bytes.len..]; - const trimmed_bytes_u16: []const u16 = @alignCast(std.mem.bytesAsSlice(u16, trimmed_bytes)); - const out = try toUTF8Alloc(allocator, trimmed_bytes_u16); - if (list.capacity < out.len) { - try list.ensureTotalCapacity(allocator, out.len); - } - list.items.len = out.len; - @memcpy(list.items, out); - return out; - }, - else => { - // TODO: this needs to re-encode, for now we just remove the BOM - const bom_bytes = bom.getHeader(); - bun.C.memmove(bytes.ptr, bytes.ptr + bom_bytes.len, bytes.len - bom_bytes.len); - return bytes[0 .. bytes.len - bom_bytes.len]; - }, - } - } -}; - -/// @deprecated. If you are using this, you likely will need to remove other BOMs and handle encoding. -/// Use the BOM struct's `detect` and conversion functions instead. -pub fn withoutUTF8BOM(bytes: []const u8) []const u8 { - if (strings.hasPrefixComptime(bytes, BOM.utf8_bytes)) { - return bytes[BOM.utf8_bytes.len..]; - } else { - return bytes; - } -} - -// https://github.com/WebKit/WebKit/blob/443e796d1538654c34f2690e39600c70c8052b63/Source/WebCore/PAL/pal/text/TextCodecUTF8.cpp#L69 -pub fn nonASCIISequenceLength(first_byte: u8) u3_fast { - return switch (first_byte) { - 0...193 => 0, - 194...223 => 2, - 224...239 => 3, - 240...244 => 4, - 245...255 => 0, - }; -} - -/// Convert a UTF-8 string to a UTF-16 string IF there are any non-ascii characters -/// If there are no non-ascii characters, this returns null -/// This is intended to be used for strings that go to JavaScript -pub fn toUTF16Alloc(allocator: std.mem.Allocator, bytes: []const u8, comptime fail_if_invalid: bool, comptime sentinel: bool) !if (sentinel) ?[:0]u16 else ?[]u16 { - if (strings.firstNonASCII(bytes)) |i| { - const output_: ?std.array_list.Managed(u16) = if (comptime bun.FeatureFlags.use_simdutf) simd: { - const out_length = bun.simdutf.length.utf16.from.utf8(bytes); - if (out_length == 0) - break :simd null; - - var out = try allocator.alloc(u16, out_length + if (sentinel) 1 else 0); - log("toUTF16 {d} UTF8 -> {d} UTF16", .{ bytes.len, out_length }); - - const res = bun.simdutf.convert.utf8.to.utf16.with_errors.le(bytes, if (comptime sentinel) out[0..out_length] else out); - if (res.status == .success) { - if (comptime sentinel) { - out[out_length] = 0; - return out[0..out_length :0]; - } - return out; - } - - if (comptime fail_if_invalid) { - allocator.free(out); - return error.InvalidByteSequence; - } - - break :simd .{ - .items = out[0..i], - .capacity = out.len, - .allocator = allocator, - }; - } else null; - var output = output_ orelse fallback: { - var list = try std.array_list.Managed(u16).initCapacity(allocator, i + 2); - list.items.len = i; - strings.copyU8IntoU16(list.items, bytes[0..i]); - break :fallback list; - }; - errdefer output.deinit(); - - var remaining = bytes[i..]; - - { - const replacement = strings.convertUTF8BytesIntoUTF16(remaining); - if (comptime fail_if_invalid) { - if (replacement.fail) { - if (comptime Environment.allow_assert) assert(replacement.code_point == unicode_replacement); - return error.InvalidByteSequence; - } - } - remaining = remaining[@max(replacement.len, 1)..]; - - //#define U16_LENGTH(c) ((uint32_t)(c)<=0xffff ? 1 : 2) - switch (replacement.code_point) { - 0...0xffff => |c| { - try output.append(@as(u16, @intCast(c))); - }, - else => |c| { - try output.appendSlice(&[_]u16{ strings.u16Lead(c), strings.u16Trail(c) }); - }, - } - } - - while (strings.firstNonASCII(remaining)) |j| { - const end = output.items.len; - try output.ensureUnusedCapacity(j); - output.items.len += j; - strings.copyU8IntoU16(output.items[end..][0..j], remaining[0..j]); - remaining = remaining[j..]; - - const replacement = strings.convertUTF8BytesIntoUTF16(remaining); - if (comptime fail_if_invalid) { - if (replacement.fail) { - if (comptime Environment.allow_assert) assert(replacement.code_point == unicode_replacement); - return error.InvalidByteSequence; - } - } - remaining = remaining[@max(replacement.len, 1)..]; - - //#define U16_LENGTH(c) ((uint32_t)(c)<=0xffff ? 1 : 2) - switch (replacement.code_point) { - 0...0xffff => |c| { - try output.append(@as(u16, @intCast(c))); - }, - else => |c| { - try output.appendSlice(&[_]u16{ strings.u16Lead(c), strings.u16Trail(c) }); - }, - } - } - - if (remaining.len > 0) { - try output.ensureTotalCapacityPrecise(output.items.len + remaining.len + comptime if (sentinel) 1 else 0); - - output.items.len += remaining.len; - strings.copyU8IntoU16(output.items[output.items.len - remaining.len ..], remaining); - } - - if (comptime sentinel) { - try output.ensureUnusedCapacity(1); - output.appendAssumeCapacity(0); - return output.items[0 .. output.items.len - 1 :0]; - } - - return output.items; - } - - return null; -} - -pub const TestingAPIs = @import("../../jsc/bun_string_jsc.zig").UnicodeTestingAPIs; - -// this one does the thing it's named after -pub fn toUTF16AllocForReal(allocator: std.mem.Allocator, bytes: []const u8, comptime fail_if_invalid: bool, comptime sentinel: bool) !if (sentinel) [:0]u16 else []u16 { - return (try toUTF16Alloc(allocator, bytes, fail_if_invalid, sentinel)) orelse { - const output = try allocator.alloc(u16, bytes.len + if (sentinel) 1 else 0); - bun.strings.copyU8IntoU16(if (sentinel) output[0..bytes.len] else output, bytes); - - if (comptime sentinel) { - output[bytes.len] = 0; - return output[0..bytes.len :0]; - } - - return output; - }; -} - -pub fn toUTF16AllocMaybeBuffered( - allocator: std.mem.Allocator, - bytes: []const u8, - comptime fail_if_invalid: bool, - comptime flush: bool, -) error{ OutOfMemory, InvalidByteSequence }!?struct { []u16, [3]u8, u2 } { - const first_non_ascii = strings.firstNonASCII(bytes) orelse return null; - - var output: std.ArrayListUnmanaged(u16) = if (comptime bun.FeatureFlags.use_simdutf) output: { - const out_length = bun.simdutf.length.utf16.from.utf8(bytes); - - if (out_length == 0) { - break :output .{}; - } - - var out = try allocator.alloc(u16, out_length); - - const res = bun.simdutf.convert.utf8.to.utf16.with_errors.le(bytes, out); - if (res.status == .success) { - log("toUTF16 {d} UTF8 -> {d} UTF16", .{ bytes.len, out_length }); - return .{ out, .{0} ** 3, 0 }; - } - - var list = std.ArrayListUnmanaged(u16).fromOwnedSlice(out[0..first_non_ascii]); - list.capacity = out.len; - - break :output list; - } else .{}; - errdefer output.deinit(allocator); - - const start = if (output.items.len > 0) first_non_ascii else 0; - var remaining = bytes[start..]; - - var non_ascii: ?u32 = 0; - while (non_ascii) |i| : (non_ascii = strings.firstNonASCII(remaining)) { - { - const end = output.items.len; - try output.ensureUnusedCapacity(allocator, i + 2); // +2 for UTF16 codepoint - output.items.len += i; - strings.copyU8IntoU16(output.items[end..][0..i], remaining[0..i]); - remaining = remaining[i..]; - } - - const sequence: [4]u8 = switch (remaining.len) { - 0 => unreachable, - 1 => .{ remaining[0], 0, 0, 0 }, - 2 => .{ remaining[0], remaining[1], 0, 0 }, - 3 => .{ remaining[0], remaining[1], remaining[2], 0 }, - else => remaining[0..4].*, - }; - - const converted_length = strings.nonASCIISequenceLength(sequence[0]); - - const converted = strings.convertUTF8BytesIntoUTF16WithLength(&sequence, converted_length, remaining.len); - - if (comptime !flush) { - if (converted.fail and converted.can_buffer and converted_length > remaining.len) { - const buffered: [3]u8 = switch (remaining.len) { - else => unreachable, - 1 => .{ remaining[0], 0, 0 }, - 2 => .{ remaining[0], remaining[1], 0 }, - 3 => .{ remaining[0], remaining[1], remaining[2] }, - }; - return .{ output.items, buffered, @intCast(remaining.len) }; - } - } - - if (comptime fail_if_invalid) { - if (converted.fail) { - if (comptime Environment.allow_assert) { - bun.assert(converted.code_point == unicode_replacement); - } - return error.InvalidByteSequence; - } - } - - remaining = remaining[@max(converted.len, 1)..]; - - // #define U16_LENGTH(c) ((uint32_t)(c)<=0xffff ? 1 : 2) - switch (converted.code_point) { - 0...0xffff => |c| output.appendAssumeCapacity(@intCast(c)), - else => |c| output.appendSliceAssumeCapacity(&.{ strings.u16Lead(c), strings.u16Trail(c) }), - } - } - - if (remaining.len > 0) { - try output.ensureTotalCapacityPrecise(allocator, output.items.len + remaining.len); - output.items.len += remaining.len; - strings.copyU8IntoU16(output.items[output.items.len - remaining.len ..], remaining); - } - - log("toUTF16 {d} UTF8 -> {d} UTF16", .{ bytes.len, output.items.len }); - return .{ output.items, .{0} ** 3, 0 }; -} - -pub fn utf16CodepointWithFFFD(input: []const u16) UTF16Replacement { - return utf16CodepointWithFFFDAndFirstInputChar(input[0], input); -} - -fn utf16CodepointWithFFFDAndFirstInputChar(char: u16, input: []const u16) UTF16Replacement { - const c0 = @as(u21, char); - - if (c0 & ~@as(u21, 0x03ff) == 0xd800) { - // surrogate pair - if (input.len == 1) - return .{ - .len = 1, - .is_lead = true, - }; - //error.DanglingSurrogateHalf; - const c1 = @as(u21, input[1]); - if (c1 & ~@as(u21, 0x03ff) != 0xdc00) - if (input.len == 1) { - return .{ - .len = 1, - }; - } else { - return .{ - .fail = true, - .len = 1, - .code_point = strings.unicode_replacement, - .is_lead = true, - }; - }; - // return error.ExpectedSecondSurrogateHalf; - - return .{ .len = 2, .code_point = 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)) }; - } else if (c0 & ~@as(u21, 0x03ff) == 0xdc00) { - // return error.UnexpectedSecondSurrogateHalf; - return .{ .fail = true, .len = 1, .code_point = unicode_replacement }; - } else { - return .{ .code_point = c0, .len = 1 }; - } -} - -pub fn utf16Codepoint(input: []const u16) UTF16Replacement { - const c0 = @as(u21, input[0]); - - if (c0 & ~@as(u21, 0x03ff) == 0xd800) { - // surrogate pair - if (input.len == 1) - return .{ - .len = 1, - }; - //error.DanglingSurrogateHalf; - const c1 = @as(u21, input[1]); - if (c1 & ~@as(u21, 0x03ff) != 0xdc00) - if (input.len == 1) - return .{ - .len = 1, - }; - // return error.ExpectedSecondSurrogateHalf; - - return .{ .len = 2, .code_point = 0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)) }; - } else if (c0 & ~@as(u21, 0x03ff) == 0xdc00) { - // return error.UnexpectedSecondSurrogateHalf; - return .{ .len = 1 }; - } else { - return .{ .code_point = c0, .len = 1 }; - } -} - -// TODO: remove this -pub const w = toUTF16Literal; - -pub fn toUTF16Literal(comptime str: []const u8) [:0]const u16 { - return literal(u16, str); -} - -pub fn literal(comptime T: type, comptime str: []const u8) *const [literalLength(T, str):0]T { - const Holder = struct { - pub const value = switch (T) { - u8 => (str[0..str.len].* ++ .{0})[0..str.len :0], - u16 => std.unicode.utf8ToUtf16LeStringLiteral(str), - else => @compileError("unsupported type " ++ @typeName(T) ++ " in strings.literal() call."), - }; - }; - - return Holder.value; -} - -fn literalLength(comptime T: type, comptime str: string) usize { - return comptime switch (T) { - u8 => str.len, - u16 => std.unicode.calcUtf16LeLen(str) catch unreachable, - else => 0, // let other errors report first - }; -} - -// Copyright (c) 2008-2009 Bjoern Hoehrmann -// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. -pub fn isValidUTF8WithoutSIMD(slice: []const u8) bool { - var state: u8 = 0; - - for (slice) |byte| { - state = decodeCheck(state, byte); - } - return state == UTF8_ACCEPT; -} - -pub fn isValidUTF8(slice: []const u8) bool { - if (bun.FeatureFlags.use_simdutf) - return bun.simdutf.validate.utf8(slice); - - return isValidUTF8WithoutSIMD(slice); -} - -pub fn isAllASCII(slice: []const u8) bool { - if (@inComptime()) { - for (slice) |char| { - if (char > 127) { - return false; - } - } - return true; - } - - return bun.simdutf.validate.ascii(slice); -} - -const UTF8_ACCEPT: u8 = 0; -const UTF8_REJECT: u8 = 12; - -const utf8d: [364]u8 = .{ - // The first part of the table maps bytes to character classes that - // to reduce the size of the transition table and create bitmasks. - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 11, 6, 6, 6, 5, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - - // The second part is a transition table that maps a combination - // of a state of the automaton and a character class to a state. - 0, 12, 24, 36, 60, 96, 84, 12, 12, 12, 48, 72, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 0, 12, 12, 12, 12, 12, 0, - 12, 0, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 24, 12, 12, - 12, 12, 12, 12, 12, 24, 12, 12, 12, 12, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, 12, 36, 12, 12, 12, 12, 12, 36, 12, 36, 12, 12, - 12, 36, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -}; - -pub fn decodeCheck(state: u8, byte: u8) u8 { - const char_type: u32 = utf8d[byte]; - // we dont care about the codep - // codep = if (*state != UTF8_ACCEPT) (byte & 0x3f) | (*codep << 6) else (0xff >> char_type) & (byte); - - const value = @as(u32, 256) + state + char_type; - if (value >= utf8d.len) return UTF8_REJECT; - return utf8d[value]; -} - -// #define U16_LEAD(supplementary) (UChar)(((supplementary)>>10)+0xd7c0) -pub fn u16Lead(supplementary: anytype) callconv(bun.callconv_inline) u16 { - return @intCast((supplementary >> 10) + 0xd7c0); -} - -// #define U16_TRAIL(supplementary) (UChar)(((supplementary)&0x3ff)|0xdc00) -pub fn u16Trail(supplementary: anytype) callconv(bun.callconv_inline) u16 { - return @intCast((supplementary & 0x3ff) | 0xdc00); -} - -// #define U16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00) -pub fn u16IsTrail(supplementary: u16) callconv(bun.callconv_inline) bool { - return (@as(u32, @intCast(supplementary)) & 0xfffffc00) == 0xdc00; -} - -// #define U16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800) -pub fn u16IsLead(supplementary: u16) callconv(bun.callconv_inline) bool { - return (@as(u32, @intCast(supplementary)) & 0xfffffc00) == 0xd800; -} - -// #define U16_GET_SUPPLEMENTARY(lead, trail) \ -// (((UChar32)(lead)<<10UL)+(UChar32)(trail)-U16_SURROGATE_OFFSET) -pub fn u16GetSupplementary(lead: u32, trail: u32) callconv(bun.callconv_inline) u32 { - const shifted = lead << 10; - return (shifted + trail) - u16_surrogate_offset; -} - -// #define U16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000) -pub const u16_surrogate_offset = 56613888; - -pub inline fn utf8ByteSequenceLength(first_byte: u8) u3_fast { - return switch (first_byte) { - 0b0000_0000...0b0111_1111 => 1, - 0b1100_0000...0b1101_1111 => 2, - 0b1110_0000...0b1110_1111 => 3, - 0b1111_0000...0b1111_0111 => 4, - else => 0, - }; -} - -/// Same as `utf8ByteSequenceLength`, but assumes the byte is valid UTF-8. -/// -/// You should only use this function if you know the string you are getting the byte from is valid UTF-8. -pub inline fn utf8ByteSequenceLengthUnsafe(first_byte: u8) u3_fast { - return switch (first_byte) { - 0b0000_0000...0b0111_1111 => 1, - 0b1100_0000...0b1101_1111 => 2, - 0b1110_0000...0b1110_1111 => 3, - 0b1111_0000...0b1111_0111 => 4, - else => unreachable, - }; -} - -/// This will simply ignore invalid UTF-8 and just do it -pub fn convertUTF8toUTF16InBuffer( - buf: []u16, - input: []const u8, -) []u16 { - // TODO(@paperclover): implement error handling here. - // for now this will cause invalid utf-8 to be ignored and become empty. - // this is lame because of https://github.com/oven-sh/bun/issues/8197 - // it will cause process.env.whatever to be len=0 instead of the data - // but it's better than failing the run entirely - // - // the reason i didn't implement the fallback is purely because our - // code in this file is too chaotic. it is left as a TODO - if (input.len == 0) return buf[0..0]; - const result = bun.simdutf.convert.utf8.to.utf16.le(input, buf); - return buf[0..result]; -} - -pub fn convertUTF8toUTF16InBufferZ( - buf: []u16, - input: []const u8, -) [:0]u16 { - // TODO: see convertUTF8toUTF16InBuffer - if (input.len == 0) { - buf[0] = 0; - return buf[0..0 :0]; - } - const result = bun.simdutf.convert.utf8.to.utf16.le(input, buf); - buf[result] = 0; - return buf[0..result :0]; -} - -pub fn convertUTF16toUTF8InBuffer( - buf: []u8, - input: []const u16, -) ![]const u8 { - // See above - if (input.len == 0) return &[_]u8{}; - const result = bun.simdutf.convert.utf16.to.utf8.le(input, buf); - // switch (result.status) { - // .success => return buf[0..result.count], - // // TODO(@paperclover): handle surrogate - // .surrogate => @panic("TODO: handle surrogate in convertUTF8toUTF16"), - // else => @panic("TODO: handle error in convertUTF16toUTF8InBuffer"), - // } - return buf[0..result]; -} - -pub fn cp1252ToCodepointAssumeNotASCII(char: u8, comptime CodePointType: type) CodePointType { - return @as( - CodePointType, - @intCast(cp1252ToCodepointBytesAssumeNotASCII16(char)), - ); -} - -const cp1252_to_utf16_conversion_table = [256]u16{ - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, // 00-07 - 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, // 08-0F - 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, // 10-17 - 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, // 18-1F - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20-27 - 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, // 28-2F - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30-37 - 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, // 38-3F - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40-47 - 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, // 48-4F - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50-57 - 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, // 58-5F - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60-67 - 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, // 68-6F - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70-77 - 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, // 78-7F - 0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, // 80-87 - 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F, // 88-8F - 0x0090, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, // 90-97 - 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x009D, 0x017E, 0x0178, // 98-9F - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, // A0-A7 - 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, // A8-AF - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, // B0-B7 - 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, // B8-BF - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, // C0-C7 - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, // C8-CF - 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, // D0-D7 - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, // D8-DF - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, // E0-E7 - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, // E8-EF - 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, // F0-F7 - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, // F8-FF -}; - -pub fn latin1ToCodepointBytesAssumeNotASCII(char: u32) [2]u8 { - var bytes = [4]u8{ 0, 0, 0, 0 }; - _ = encodeWTF8Rune(&bytes, @as(i32, @intCast(char))); - return bytes[0..2].*; -} - -pub fn cp1252ToCodepointBytesAssumeNotASCII16(char: u32) u16 { - return cp1252_to_utf16_conversion_table[@as(u8, @truncate(char))]; -} - -/// Copy a UTF-16 string as UTF-8 into `buf` -/// -/// This may not encode everything if `buf` is not big enough. -pub fn copyUTF16IntoUTF8(buf: []u8, utf16: []const u16) EncodeIntoResult { - return copyUTF16IntoUTF8Impl(buf, utf16, false); -} - -/// See comment on `copyUTF16IntoUTF8WithBufferImpl` on what `allow_truncated_utf8_sequence` should do -pub fn copyUTF16IntoUTF8Impl(buf: []u8, utf16: []const u16, comptime allow_truncated_utf8_sequence: bool) EncodeIntoResult { - if (bun.FeatureFlags.use_simdutf) { - if (utf16.len == 0) - return .{ .read = 0, .written = 0 }; - const trimmed = bun.simdutf.trim.utf16(utf16); - if (trimmed.len == 0) - return .{ .read = 0, .written = 0 }; - - const out_len = if (buf.len <= (trimmed.len * 3 + 2)) - bun.simdutf.length.utf8.from.utf16.le(trimmed) - else - buf.len; - - return copyUTF16IntoUTF8WithBufferImpl(buf, utf16, out_len, allow_truncated_utf8_sequence); - } - - return copyUTF16IntoUTF8WithBufferImpl(buf, utf16, utf16.len, allow_truncated_utf8_sequence); -} - -/// Q: What does the `allow_truncated_utf8_sequence` parameter do? -/// A: If the output buffer can't fit everything, this function will write -/// incomplete utf-8 byte sequences if `allow_truncated_utf8_sequence` is -/// enabled. -/// -/// Q: Doesn't that mean this function would output invalid utf-8? Why would you -/// ever want to do that? -/// A: Yes. This is needed for writing a UTF-16 string to a node Buffer that -/// doesn't have enough space for all the bytes: -/// -/// ```js -/// let buffer = Buffer.allocUnsafe(1); -/// buffer.fill("\u0222"); -/// expect(buffer[0]).toBe(0xc8); -/// ``` -pub fn copyUTF16IntoUTF8WithBufferImpl(buf: []u8, utf16: []const u16, out_len: usize, comptime allow_truncated_utf8_sequence: bool) EncodeIntoResult { - var remaining = buf; - var utf16_remaining = utf16; - var ended_on_non_ascii = false; - - brk: { - if (bun.FeatureFlags.use_simdutf) { - log("UTF16 {d} -> UTF8 {d}", .{ utf16.len, out_len }); - if (remaining.len >= out_len) { - const result = bun.simdutf.convert.utf16.to.utf8.with_errors.le(utf16, remaining); - if (result.status == .surrogate) break :brk; - - return EncodeIntoResult{ - .read = @as(u32, @truncate(utf16.len)), - .written = @as(u32, @truncate(result.count)), - }; - } - } - } - - while (firstNonASCII16(utf16_remaining)) |i| { - const end = @min(i, remaining.len); - if (end > 0) copyU16IntoU8(remaining, utf16_remaining[0..end]); - remaining = remaining[end..]; - utf16_remaining = utf16_remaining[end..]; - - if (@min(utf16_remaining.len, remaining.len) == 0) - break; - - const replacement = utf16CodepointWithFFFD(utf16_remaining); - - const width: usize = replacement.utf8Width(); - bun.assert(width > 1); - if (width > remaining.len) { - ended_on_non_ascii = width > 1; - if (comptime allow_truncated_utf8_sequence) switch (width) { - 2 => { - if (remaining.len > 0) { - //only first will be written - remaining[0] = @as(u8, @truncate(0xC0 | (replacement.code_point >> 6))); - remaining = remaining[remaining.len..]; - } - }, - 3 => { - //only first to second written - switch (remaining.len) { - 1 => { - remaining[0] = @as(u8, @truncate(0xE0 | (replacement.code_point >> 12))); - remaining = remaining[remaining.len..]; - }, - 2 => { - remaining[0] = @as(u8, @truncate(0xE0 | (replacement.code_point >> 12))); - remaining[1] = @as(u8, @truncate(0x80 | (replacement.code_point >> 6) & 0x3F)); - remaining = remaining[remaining.len..]; - }, - else => {}, - } - }, - 4 => { - //only 1 to 3 written - switch (remaining.len) { - 1 => { - remaining[0] = @as(u8, @truncate(0xF0 | (replacement.code_point >> 18))); - remaining = remaining[remaining.len..]; - }, - 2 => { - remaining[0] = @as(u8, @truncate(0xF0 | (replacement.code_point >> 18))); - remaining[1] = @as(u8, @truncate(0x80 | (replacement.code_point >> 12) & 0x3F)); - remaining = remaining[remaining.len..]; - }, - 3 => { - remaining[0] = @as(u8, @truncate(0xF0 | (replacement.code_point >> 18))); - remaining[1] = @as(u8, @truncate(0x80 | (replacement.code_point >> 12) & 0x3F)); - remaining[2] = @as(u8, @truncate(0x80 | (replacement.code_point >> 6) & 0x3F)); - remaining = remaining[remaining.len..]; - }, - else => {}, - } - }, - - else => {}, - }; - break; - } - - utf16_remaining = utf16_remaining[replacement.len..]; - _ = encodeWTF8RuneT(remaining.ptr[0..4], u32, @as(u32, replacement.code_point)); - remaining = remaining[width..]; - } - - if (remaining.len > 0 and !ended_on_non_ascii and utf16_remaining.len > 0) { - const len = @min(remaining.len, utf16_remaining.len); - copyU16IntoU8(remaining[0..len], utf16_remaining[0..len]); - utf16_remaining = utf16_remaining[len..]; - remaining = remaining[len..]; - } - - return .{ - .read = @as(u32, @truncate(utf16.len - utf16_remaining.len)), - .written = @as(u32, @truncate(buf.len - remaining.len)), - }; -} - -pub fn elementLengthUTF16IntoUTF8(utf16: []const u16) usize { - if (bun.FeatureFlags.use_simdutf) { - return bun.simdutf.length.utf8.from.utf16.le(utf16); - } - - var utf16_remaining = utf16; - var count: usize = 0; - - while (firstNonASCII16(utf16_remaining)) |i| { - count += i; - - utf16_remaining = utf16_remaining[i..]; - - const replacement = utf16Codepoint(utf16_remaining); - - count += replacement.utf8Width(); - utf16_remaining = utf16_remaining[replacement.len..]; - } - - return count + utf16_remaining.len; -} - -pub fn elementLengthUTF8IntoUTF16(utf8: []const u8) usize { - var utf8_remaining = utf8; - var count: usize = 0; - - if (bun.FeatureFlags.use_simdutf) { - return bun.simdutf.length.utf16.from.utf8(utf8); - } - - while (firstNonASCII(utf8_remaining)) |i| { - count += i; - - utf8_remaining = utf8_remaining[i..]; - - const replacement = utf16Codepoint(utf8_remaining); - - count += replacement.len; - utf8_remaining = utf8_remaining[@min(replacement.utf8Width(), utf8_remaining.len)..]; - } - - return count + utf8_remaining.len; -} - -// Check utf16 string equals utf8 string without allocating extra memory -pub fn utf16EqlString(text: []const u16, str: string) bool { - if (text.len > str.len) { - // Strings can't be equal if UTF-16 encoding is longer than UTF-8 encoding - return false; - } - - var temp = [4]u8{ 0, 0, 0, 0 }; - const n = text.len; - var j: usize = 0; - var i: usize = 0; - // TODO: is it safe to just make this u32 or u21? - var r1: i32 = undefined; - while (i < n) : (i += 1) { - r1 = text[i]; - if (r1 >= 0xD800 and r1 <= 0xDBFF and i + 1 < n) { - const r2: i32 = text[i + 1]; - if (r2 >= 0xDC00 and r2 <= 0xDFFF) { - r1 = (r1 - 0xD800) << 10 | (r2 - 0xDC00) + 0x10000; - i += 1; - } - } - - const width = encodeWTF8Rune(&temp, r1); - if (j + width > str.len) { - return false; - } - for (0..width) |k| { - if (temp[k] != str[j]) { - return false; - } - j += 1; - } - } - - return j == str.len; -} - -pub fn encodeUTF8Comptime(comptime cp: u32) []const u8 { - const HEADER_CONT_BYTE: u8 = 0b10000000; - const HEADER_2BYTE: u8 = 0b11000000; - const HEADER_3BYTE: u8 = 0b11100000; - const HEADER_4BYTE: u8 = 0b11100000; - - return switch (cp) { - 0x0...0x7F => return &[_]u8{@intCast(cp)}, - 0x80...0x7FF => { - return &[_]u8{ - HEADER_2BYTE | @as(u8, cp >> 6), - HEADER_CONT_BYTE | @as(u8, cp & 0b00111111), - }; - }, - 0x800...0xFFFF => { - return &[_]u8{ - HEADER_3BYTE | @as(u8, cp >> 12), - HEADER_CONT_BYTE | @as(u8, (cp >> 6) & 0b00111111), - HEADER_CONT_BYTE | @as(u8, cp & 0b00111111), - }; - }, - 0x10000...0x10FFFF => { - return &[_]u8{ - HEADER_4BYTE | @as(u8, cp >> 18), - HEADER_CONT_BYTE | @as(u8, (cp >> 12) & 0b00111111), - HEADER_CONT_BYTE | @as(u8, (cp >> 6) & 0b00111111), - HEADER_CONT_BYTE | @as(u8, cp & 0b00111111), - }; - }, - else => @compileError("Invalid UTF-8 codepoint!"), - }; -} - -// This is a clone of golang's "utf8.EncodeRune" that has been modified to encode using -// WTF-8 instead. See https://simonsapin.github.io/wtf-8/ for more info. -pub fn encodeWTF8Rune(p: *[4]u8, r: i32) u3_fast { - return encodeWTF8RuneT(p, u32, @intCast(r)); -} - -pub fn encodeWTF8RuneT(p: *[4]u8, comptime R: type, r: R) u3_fast { - switch (r) { - 0...0x7F => { - p[0] = @as(u8, @intCast(r)); - return 1; - }, - (0x7F + 1)...0x7FF => { - p[0] = @as(u8, @truncate(0xC0 | ((r >> 6)))); - p[1] = @as(u8, @truncate(0x80 | (r & 0x3F))); - return 2; - }, - (0x7FF + 1)...0xFFFF => { - p[0] = @as(u8, @truncate(0xE0 | ((r >> 12)))); - p[1] = @as(u8, @truncate(0x80 | ((r >> 6) & 0x3F))); - p[2] = @as(u8, @truncate(0x80 | (r & 0x3F))); - return 3; - }, - else => { - p[0] = @as(u8, @truncate(0xF0 | ((r >> 18)))); - p[1] = @as(u8, @truncate(0x80 | ((r >> 12) & 0x3F))); - p[2] = @as(u8, @truncate(0x80 | ((r >> 6) & 0x3F))); - p[3] = @as(u8, @truncate(0x80 | (r & 0x3F))); - return 4; - }, - } -} - -pub fn wtf8Sequence(code_point: u32) [4]u8 { - return switch (code_point) { - 0...0x7f => .{ - @intCast(code_point), - 0, - 0, - 0, - }, - (0x7f + 1)...0x7ff => .{ - @truncate(0xc0 | (code_point >> 6)), - @truncate(0x80 | (code_point & 0x3f)), - 0, - 0, - }, - (0x7ff + 1)...0xffff => .{ - @truncate(0xe0 | (code_point >> 12)), - @truncate(0x80 | ((code_point >> 6) & 0x3f)), - @truncate(0x80 | (code_point & 0x3f)), - 0, - }, - else => .{ - @truncate(0xf0 | (code_point >> 18)), - @truncate(0x80 | ((code_point >> 12) & 0x3f)), - @truncate(0x80 | ((code_point >> 6) & 0x3f)), - @truncate(0x80 | (code_point & 0x3f)), - }, - }; -} - -pub inline fn wtf8ByteSequenceLength(first_byte: u8) u8 { - return switch (first_byte) { - 0...0x80 - 1 => 1, - else => if ((first_byte & 0xE0) == 0xC0) - 2 - else if ((first_byte & 0xF0) == 0xE0) - 3 - else if ((first_byte & 0xF8) == 0xF0) - 4 - else - 1, - }; -} - -/// 0 == invalid -pub inline fn wtf8ByteSequenceLengthWithInvalid(first_byte: u8) u8 { - return switch (first_byte) { - 0...0x80 - 1 => 1, - else => if ((first_byte & 0xE0) == 0xC0) - 2 - else if ((first_byte & 0xF0) == 0xE0) - 3 - else if ((first_byte & 0xF8) == 0xF0) - 4 - else - 1, - }; -} - -/// Convert potentially ill-formed UTF-8 or UTF-16 bytes to a Unicode Codepoint. -/// Invalid codepoints are replaced with `zero` parameter -/// This is a clone of esbuild's decodeWTF8Rune -/// which was a clone of golang's "utf8.DecodeRune" that was modified to decode using WTF-8 instead. -/// Asserts a multi-byte codepoint -pub inline fn decodeWTF8RuneTMultibyte(p: *const [4]u8, len: u3_fast, comptime T: type, comptime zero: T) T { - if (comptime Environment.allow_assert) assert(len > 1); - - const s1 = p[1]; - if ((s1 & 0xC0) != 0x80) return zero; - - if (len == 2) { - const cp = @as(T, p[0] & 0x1F) << 6 | @as(T, s1 & 0x3F); - if (cp < 0x80) return zero; - return cp; - } - - const s2 = p[2]; - - if ((s2 & 0xC0) != 0x80) return zero; - - if (len == 3) { - const cp = (@as(T, p[0] & 0x0F) << 12) | (@as(T, s1 & 0x3F) << 6) | (@as(T, s2 & 0x3F)); - if (cp < 0x800) return zero; - return cp; - } - - const s3 = p[3]; - - if ((s3 & 0xC0) != 0x80) return zero; - - { - const cp = (@as(T, p[0] & 0x07) << 18) | (@as(T, s1 & 0x3F) << 12) | (@as(T, s2 & 0x3F) << 6) | (@as(T, s3 & 0x3F)); - if (cp < 0x10000 or cp > 0x10FFFF) return zero; - return cp; - } - - unreachable; -} - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const CodePoint = bun.CodePoint; -const Environment = bun.Environment; -const OOM = bun.OOM; -const assert = bun.assert; -const js_lexer = bun.js_lexer; - -const strings = bun.strings; -const AsciiVector = strings.AsciiVector; -const ascii_vector_size = strings.ascii_vector_size; -const eqlComptimeIgnoreLen = strings.eqlComptimeIgnoreLen; -const firstNonASCII = strings.firstNonASCII; -const firstNonASCII16 = strings.firstNonASCII16; -const log = strings.log; -const u3_fast = strings.u3_fast; -const unicode_replacement = strings.unicode_replacement; diff --git a/src/bun_core/tty.zig b/src/bun_core/tty.zig deleted file mode 100644 index b83288e5e149..000000000000 --- a/src/bun_core/tty.zig +++ /dev/null @@ -1,11 +0,0 @@ -pub const Mode = enum(c_int) { - normal = 0, - raw = 1, - io = 2, -}; - -pub fn setMode(fd: c_int, mode: Mode) c_int { - return Bun__ttySetMode(fd, @intFromEnum(mode)); -} - -extern fn Bun__ttySetMode(fd: c_int, mode: c_int) c_int; diff --git a/src/bun_core/util.zig b/src/bun_core/util.zig deleted file mode 100644 index de083d57da48..000000000000 --- a/src/bun_core/util.zig +++ /dev/null @@ -1,235 +0,0 @@ -// Things that maybe should go in Zig standard library at some point - -pub fn Key(comptime Map: type) type { - return FieldType(Map.KV, "key").?; -} - -pub fn Value(comptime Map: type) type { - return FieldType(Map.KV, "value").?; -} - -pub fn fromEntries( - comptime Map: type, - allocator: std.mem.Allocator, - comptime EntryType: type, - entries: EntryType, -) !Map { - var map: Map = undefined; - if (@hasField(Map, "allocator")) { - map = Map.init(allocator); - } else { - map = Map{}; - } - - if (comptime bun.trait.isIndexable(EntryType)) { - if (comptime !needsAllocator(Map.ensureUnusedCapacity)) { - try map.ensureUnusedCapacity(entries.len); - } else { - try map.ensureUnusedCapacity(allocator, entries.len); - } - - inline for (entries) |entry| { - map.putAssumeCapacity(entry[0], entry[1]); - } - - return map; - } else if (std.meta.hasFn(EntryType, "count")) { - if (comptime !needsAllocator(Map.ensureUnusedCapacity)) { - try map.ensureUnusedCapacity(entries.count()); - } else { - try map.ensureUnusedCapacity(allocator, entries.count()); - } - - if (comptime @hasDecl(EntryType, "iterator")) { - var iter = entries.iterator(); - while (iter.next()) |entry| { - map.putAssumeCapacity(entry[0], entry[1]); - } - - return map; - } - } else if (comptime bun.trait.isContainer(EntryType) and std.meta.fields(EntryType).len > 0) { - if (comptime !needsAllocator(Map.ensureUnusedCapacity)) { - try map.ensureUnusedCapacity(std.meta.fields(EntryType).len); - } else { - try map.ensureUnusedCapacity(allocator, std.meta.fields(EntryType).len); - } - - inline for (comptime std.meta.fieldNames(@TypeOf(EntryType))) |entry| { - map.putAssumeCapacity(entry[0], entry[1]); - } - - return map; - } else if (comptime bun.trait.isConstPtr(EntryType) and std.meta.fields(std.meta.Child(EntryType)).len > 0) { - if (comptime !needsAllocator(Map.ensureUnusedCapacity)) { - try map.ensureUnusedCapacity(std.meta.fields(std.meta.Child(EntryType)).len); - } else { - try map.ensureUnusedCapacity(allocator, std.meta.fields(std.meta.Child(EntryType)).len); - } - - inline for (entries) |entry| { - map.putAssumeCapacity(entry[0], entry[1]); - } - - return map; - } - - @compileError("Cannot construct Map from entries of type " ++ @typeName(EntryType)); -} - -pub fn fromMapLike( - comptime Map: type, - allocator: std.mem.Allocator, - entries: []const struct { @FieldType(Map.KV, "key"), @FieldType(Map.KV, "value") }, -) !Map { - var map: Map = undefined; - if (comptime @hasField(Map, "allocator")) { - map = Map.init(allocator); - } else { - map = Map{}; - } - - try map.ensureUnusedCapacity(allocator, entries.len); - - for (entries) |entry| { - map.putAssumeCapacityNoClobber(entry[0], entry[1]); - } - - return map; -} - -pub fn FieldType(comptime Map: type, comptime name: []const u8) ?type { - const i = std.meta.fieldIndex(Map, name) orelse return null; - const field = std.meta.fields(Map)[i]; - return field.field_type; -} - -pub fn Of(comptime ArrayLike: type) type { - if (bun.trait.isSlice(ArrayLike)) { - return std.meta.Child(ArrayLike); - } - - if (comptime @hasDecl(ArrayLike, "Elem")) { - return ArrayLike.Elem; - } - - if (comptime @hasField(ArrayLike, "items")) { - return std.meta.Child(FieldType(ArrayLike, "items").?); - } - - if (comptime @hasField(ArrayLike, "ptr")) { - return std.meta.Child(FieldType(ArrayLike, "ptr").?); - } - - @compileError("Cannot infer type within " ++ @typeName(ArrayLike)); -} - -pub inline fn from( - comptime Array: type, - allocator: std.mem.Allocator, - default: anytype, -) !Array { - const DefaultType = @TypeOf(default); - if (comptime bun.trait.isSlice(DefaultType)) { - return fromSlice(Array, allocator, DefaultType, default); - } - - if (comptime bun.trait.isContainer(DefaultType)) { - if (comptime bun.trait.isContainer(Array) and @hasDecl(DefaultType, "put")) { - return fromMapLike(Array, allocator, default); - } - - if (comptime @hasField(DefaultType, "items")) { - if (Of(FieldType(DefaultType, "items").?) == Of(Array)) { - return fromSlice(Array, allocator, @TypeOf(default.items), default.items); - } - } - } - - if (comptime bun.trait.isContainer(Array) and @hasDecl(Array, "put")) { - if (comptime bun.trait.isConstPtr(DefaultType) and std.meta.fields(std.meta.Child(DefaultType)).len > 0) { - return fromEntries(Array, allocator, @TypeOf(default.*), default.*); - } - return fromEntries(Array, allocator, DefaultType, default); - } - - if (comptime @typeInfo(DefaultType) == .@"struct") { - return fromSlice(Array, allocator, DefaultType, default); - } - - if (comptime @typeInfo(DefaultType) == .array) { - return fromSlice(Array, allocator, []const Of(Array), @as([]const Of(Array), &default)); - } - - return fromSlice(Array, allocator, []const Of(Array), @as([]const Of(Array), default)); -} - -pub fn fromSlice( - comptime Array: type, - allocator: std.mem.Allocator, - comptime DefaultType: type, - default: DefaultType, -) !Array { - var map: Array = undefined; - if (comptime bun.trait.isSlice(Array)) {} else if (comptime @hasField(Array, "allocator")) { - map = Array.init(allocator); - } else { - map = Array{}; - } - - // is it a MultiArrayList? - if (comptime !bun.trait.isSlice(Array) and @hasField(Array, "bytes")) { - try map.ensureUnusedCapacity(allocator, default.len); - for (default) |elem| { - map.appendAssumeCapacity(elem); - } - - return map; - } else { - var slice: []Of(Array) = undefined; - if (comptime !bun.trait.isSlice(Array)) { - // is it an ArrayList with an allocator? - if (comptime !needsAllocator(Array.ensureUnusedCapacity)) { - try map.ensureUnusedCapacity(default.len); - // is it an ArrayList without an allocator? - } else { - try map.ensureUnusedCapacity(allocator, default.len); - } - if (comptime @hasField(Array, "items")) { - map.items.len = default.len; - slice = map.items; - } else if (comptime @hasField(Array, "len")) { - map.len = @as(u32, @intCast(default.len)); - slice = map.slice(); - } else { - @compileError("Cannot set length of " ++ @typeName(Array)); - } - } else if (comptime std.meta.trait.isSlice(Array)) { - slice = try allocator.alloc(Of(Array), default.len); - } else if (comptime @hasField(map, "ptr")) { - slice = try allocator.alloc(Of(Array), default.len); - map = .{ - .ptr = slice.ptr, - .len = @as(u32, @truncate(default.len)), - .cap = @as(u32, @truncate(default.len)), - }; - } - - const in = std.mem.sliceAsBytes(default); - var out = std.mem.sliceAsBytes(slice); - @memcpy(out[0..in.len], in); - - if (bun.trait.isSlice(Array)) { - return slice; - } - - return map; - } -} - -fn needsAllocator(comptime Fn: anytype) bool { - return std.meta.fields(std.meta.ArgsTuple(@TypeOf(Fn))).len > 2; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bun_core_macros/comptime_string_map.rs b/src/bun_core_macros/comptime_string_map.rs index 5f3e396b6229..8137a839f178 100644 --- a/src/bun_core_macros/comptime_string_map.rs +++ b/src/bun_core_macros/comptime_string_map.rs @@ -1,6 +1,6 @@ //! `comptime_string_map!` / `comptime_string_set!` expansion. //! -//! Port of `src/collections/comptime_string_map.zig`: keys are grouped by +//! Port of Zig's `ComptimeStringMap`: keys are grouped by //! length at expansion time so a lookup is one `match key.len()` (a jump //! table) followed by constant-length byte-slice compares, which LLVM lowers //! to word-sized loads compared against immediates — no hashing, no memcmp diff --git a/src/bundler/AstBuilder.zig b/src/bundler/AstBuilder.zig deleted file mode 100644 index bca886b0db85..000000000000 --- a/src/bundler/AstBuilder.zig +++ /dev/null @@ -1,375 +0,0 @@ -/// Utility to construct `Ast`s intended for generated code, such as the -/// boundary modules when dealing with server components. This is a saner -/// alternative to building a string, then sending it through `js_parser` -/// -/// For in-depth details on the fields, most of these are documented -/// inside of `js_parser` -pub const AstBuilder = struct { - allocator: std.mem.Allocator, - source: *const Logger.Source, - source_index: u31, - stmts: std.ArrayListUnmanaged(Stmt), - scopes: std.ArrayListUnmanaged(*Scope), - symbols: std.ArrayListUnmanaged(Symbol), - import_records: std.ArrayListUnmanaged(ImportRecord), - named_imports: js_ast.Ast.NamedImports, - named_exports: js_ast.Ast.NamedExports, - import_records_for_current_part: std.ArrayListUnmanaged(u32), - export_star_import_records: std.ArrayListUnmanaged(u32), - current_scope: *Scope, - log: Logger.Log, - module_ref: Ref, - declared_symbols: js_ast.DeclaredSymbol.List, - /// When set, codegen is altered - hot_reloading: bool, - hmr_api_ref: Ref, - - // stub fields for ImportScanner duck typing - comptime options: js_parser.Parser.Options = .{ - .jsx = .{}, - .bundle = true, - }, - comptime import_items_for_namespace: struct { - pub fn get(_: @This(), _: Ref) ?js_parser.ImportItemForNamespaceMap { - return null; - } - } = .{}, - pub const parser_features = struct { - pub const typescript = false; - }; - - pub fn init(allocator: std.mem.Allocator, source: *const Logger.Source, hot_reloading: bool) !AstBuilder { - const scope = try allocator.create(Scope); - scope.* = .{ - .kind = .entry, - .label_ref = null, - .parent = null, - .generated = .{}, - }; - var ab: AstBuilder = .{ - .allocator = allocator, - .current_scope = scope, - .source = source, - .source_index = @intCast(source.index.get()), - .stmts = .{}, - .scopes = .{}, - .symbols = .{}, - .import_records = .{}, - .import_records_for_current_part = .{}, - .named_imports = .{}, - .named_exports = .{}, - .log = Logger.Log.init(allocator), - .export_star_import_records = .{}, - .declared_symbols = .{}, - .hot_reloading = hot_reloading, - .module_ref = undefined, - .hmr_api_ref = undefined, - }; - ab.module_ref = try ab.newSymbol(.other, "module"); - ab.hmr_api_ref = try ab.newSymbol(.other, "hmr"); - return ab; - } - - pub fn pushScope(p: *AstBuilder, kind: Scope.Kind) *js_ast.Scope { - try p.scopes.ensureUnusedCapacity(p.allocator, 1); - try p.current_scope.children.ensureUnusedCapacity(p.allocator, 1); - const scope = try p.allocator.create(Scope); - scope.* = .{ - .kind = kind, - .label_ref = null, - .parent = p.current_scope, - .generated = .{}, - }; - p.current_scope.children.appendAssumeCapacity(scope); - p.scopes.appendAssumeCapacity(p.current_scope); - p.current_scope = scope; - return scope; - } - - pub fn popScope(p: *AstBuilder) void { - p.current_scope = p.scopes.pop(); - } - - pub fn newSymbol(p: *AstBuilder, kind: Symbol.Kind, identifier: []const u8) !Ref { - const inner_index: Ref.Int = @intCast(p.symbols.items.len); - try p.symbols.append(p.allocator, .{ - .kind = kind, - .original_name = identifier, - }); - const ref: Ref = .{ - .inner_index = inner_index, - .source_index = p.source_index, - .tag = .symbol, - }; - try p.current_scope.generated.append(p.allocator, ref); - try p.declared_symbols.append(p.allocator, .{ - .ref = ref, - .is_top_level = p.scopes.items.len == 0 or p.current_scope == p.scopes.items[0], - }); - return ref; - } - - pub fn getSymbol(p: *AstBuilder, ref: Ref) *Symbol { - bun.assert(ref.source_index == p.source.index.get()); - return &p.symbols.items[ref.inner_index]; - } - - pub fn addImportRecord(p: *AstBuilder, path: []const u8, kind: ImportKind) !u32 { - const index = p.import_records.items.len; - try p.import_records.append(p.allocator, .{ - .path = bun.fs.Path.init(path), - .kind = kind, - .range = .{}, - }); - return @intCast(index); - } - - pub fn addImportStmt( - p: *AstBuilder, - path: []const u8, - identifiers_to_import: anytype, - ) ![identifiers_to_import.len]Expr { - var out: [identifiers_to_import.len]Expr = undefined; - - const record = try p.addImportRecord(path, .stmt); - - var path_name = bun.fs.PathName.init(path); - const name = try strings.append(p.allocator, "import_", try path_name.nonUniqueNameString(p.allocator)); - const namespace_ref = try p.newSymbol(.other, name); - - const clauses = try p.allocator.alloc(js_ast.ClauseItem, identifiers_to_import.len); - - inline for (identifiers_to_import, &out, clauses) |import_id_untyped, *out_ref, *clause| { - const import_id: []const u8 = import_id_untyped; // must be given '[N][]const u8' - const ref = try p.newSymbol(.import, import_id); - if (p.hot_reloading) { - p.getSymbol(ref).namespace_alias = .{ - .namespace_ref = namespace_ref, - .alias = import_id, - .import_record_index = record, - }; - } - out_ref.* = p.newExpr(E.ImportIdentifier{ .ref = ref }); - clause.* = .{ - .name = .{ .loc = Logger.Loc.Empty, .ref = ref }, - .original_name = import_id, - .alias = import_id, - }; - } - - try p.appendStmt(S.Import{ - .namespace_ref = namespace_ref, - .import_record_index = record, - .items = clauses, - .is_single_line = identifiers_to_import.len < 1, - }); - - return out; - } - - pub fn appendStmt(p: *AstBuilder, data: anytype) !void { - try p.stmts.ensureUnusedCapacity(p.allocator, 1); - p.stmts.appendAssumeCapacity(p.newStmt(data)); - } - - pub fn newStmt(p: *AstBuilder, data: anytype) Stmt { - _ = p; - return Stmt.alloc(@TypeOf(data), data, Logger.Loc.Empty); - } - - pub fn newExpr(p: *AstBuilder, data: anytype) Expr { - _ = p; - return Expr.init(@TypeOf(data), data, Logger.Loc.Empty); - } - - pub fn newExternalSymbol(p: *AstBuilder, name: []const u8) !Ref { - const ref = try p.newSymbol(.other, name); - const sym = p.getSymbol(ref); - sym.must_not_be_renamed = true; - return ref; - } - - pub fn toBundledAst(p: *AstBuilder, target: options.Target) !js_ast.BundledAst { - // TODO: missing import scanner - bun.assert(p.scopes.items.len == 0); - const module_scope = p.current_scope; - - var parts = try Part.List.initCapacity(p.allocator, 2); - parts.len = 2; - parts.mut(0).* = .{}; - parts.mut(1).* = .{ - .stmts = p.stmts.items, - .can_be_removed_if_unused = false, - - // pretend that every symbol was used - .symbol_uses = uses: { - var map: Part.SymbolUseMap = .{}; - try map.ensureTotalCapacity(p.allocator, p.symbols.items.len); - for (0..p.symbols.items.len) |i| { - map.putAssumeCapacity(Ref{ - .tag = .symbol, - .source_index = p.source_index, - .inner_index = @intCast(i), - }, .{ .count_estimate = 1 }); - } - break :uses map; - }, - }; - - const single_u32 = try BabyList(u32).fromSlice(p.allocator, &.{1}); - - var top_level_symbols_to_parts = js_ast.Ast.TopLevelSymbolToParts{}; - try top_level_symbols_to_parts.entries.setCapacity(p.allocator, module_scope.generated.len); - top_level_symbols_to_parts.entries.len = module_scope.generated.len; - const slice = top_level_symbols_to_parts.entries.slice(); - for ( - slice.items(.key), - slice.items(.value), - module_scope.generated.slice(), - ) |*k, *v, ref| { - k.* = ref; - v.* = single_u32; - } - try top_level_symbols_to_parts.reIndex(p.allocator); - - // For more details on this section, look at js_parser.toAST - // This is mimicking how it calls ImportScanner - if (p.hot_reloading) { - var hmr_transform_ctx = js_parser.ConvertESMExportsForHmr{ - .last_part = parts.last() orelse - unreachable, // was definitely allocated - .is_in_node_modules = p.source.path.isNodeModule(), - }; - try hmr_transform_ctx.stmts.ensureTotalCapacity(p.allocator, prealloc_count: { - // get a estimate on how many statements there are going to be - const count = p.stmts.items.len; - break :prealloc_count count + 2; - }); - - _ = try js_parser.ImportScanner.scan(AstBuilder, p, p.stmts.items, false, true, &hmr_transform_ctx); - - try hmr_transform_ctx.finalize(p, parts.slice()); - const new_parts = parts.slice(); - // preserve original capacity - parts.len = @intCast(new_parts.len); - bun.assert(new_parts.ptr == parts.ptr); - } else { - const result = try js_parser.ImportScanner.scan(AstBuilder, p, p.stmts.items, false, false, {}); - parts.mut(1).stmts = result.stmts; - } - - parts.mut(1).declared_symbols = p.declared_symbols; - parts.mut(1).scopes = p.scopes.items; - parts.mut(1).import_record_indices = BabyList(u32).moveFromList(&p.import_records_for_current_part); - - return .{ - .parts = parts, - .module_scope = module_scope.*, - .symbols = js_ast.Symbol.List.moveFromList(&p.symbols), - .exports_ref = Ref.None, - .wrapper_ref = Ref.None, - .module_ref = p.module_ref, - .import_records = ImportRecord.List.moveFromList(&p.import_records), - .export_star_import_records = &.{}, - .approximate_newline_count = 1, - .exports_kind = .esm, - .named_imports = p.named_imports, - .named_exports = p.named_exports, - .top_level_symbols_to_parts = top_level_symbols_to_parts, - .char_freq = .{}, - .flags = .{}, - .target = target, - .top_level_await_keyword = Logger.Range.None, - // .nested_scope_slot_counts = if (p.options.features.minify_identifiers) - // renamer.assignNestedScopeSlots(p.allocator, p.scopes.items[0], p.symbols.items) - // else - // js_ast.SlotCounts{}, - }; - } - - // stub methods for ImportScanner duck typing - - pub fn generateTempRef(ab: *AstBuilder, name: ?[]const u8) Ref { - return bun.handleOom(ab.newSymbol(.other, name orelse "temp")); - } - - pub fn recordExport(p: *AstBuilder, _: Logger.Loc, alias: []const u8, ref: Ref) !void { - if (p.named_exports.get(alias)) |_| { - // Duplicate exports are an error - Output.panic( - "In generated file, duplicate export \"{s}\"", - .{alias}, - ); - } else { - try p.named_exports.put(p.allocator, alias, .{ .alias_loc = Logger.Loc.Empty, .ref = ref }); - } - } - - pub fn recordExportedBinding(p: *AstBuilder, binding: Binding) void { - switch (binding.data) { - .b_missing => {}, - .b_identifier => |ident| { - p.recordExport(binding.loc, p.symbols.items[ident.ref.innerIndex()].original_name, ident.ref) catch unreachable; - }, - .b_array => |array| { - for (array.items) |prop| { - p.recordExportedBinding(prop.binding); - } - }, - .b_object => |obj| { - for (obj.properties) |prop| { - p.recordExportedBinding(prop.value); - } - }, - } - } - - pub fn ignoreUsage(p: *AstBuilder, ref: Ref) void { - _ = p; - _ = ref; - } - - pub fn panic(p: *AstBuilder, comptime fmt: []const u8, args: anytype) noreturn { - _ = p; - Output.panic(fmt, args); - } - - pub fn @"module.exports"(p: *AstBuilder, loc: Logger.Loc) Expr { - return p.newExpr(E.Dot{ .name = "exports", .name_loc = loc, .target = p.newExpr(E.Identifier{ .ref = p.module_ref }) }); - } -}; - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const string = []const u8; - -const options = @import("./options.zig"); -const std = @import("std"); - -const Logger = @import("../logger/logger.zig"); -const Loc = Logger.Loc; - -const bun = @import("bun"); -const ImportKind = bun.ImportKind; -const ImportRecord = bun.ImportRecord; -const Output = bun.Output; -const js_parser = bun.js_parser; -const renamer = bun.renamer; -const strings = bun.strings; -const BabyList = bun.collections.BabyList; - -const js_ast = bun.ast; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const Part = js_ast.Part; -const S = js_ast.S; -const Scope = js_ast.Scope; -const Stmt = js_ast.Stmt; -const Symbol = js_ast.Symbol; diff --git a/src/bundler/BundleThread.zig b/src/bundler/BundleThread.zig deleted file mode 100644 index 179f01f79575..000000000000 --- a/src/bundler/BundleThread.zig +++ /dev/null @@ -1,195 +0,0 @@ -/// Used to keep the bundle thread from spinning on Windows -pub fn timerCallback(_: *bun.windows.libuv.Timer) callconv(.c) void {} - -/// Originally, bake.DevServer required a separate bundling thread, but that was -/// later removed. The bundling thread's scheduling logic is generalized over -/// the completion structure. -/// -/// CompletionStruct's interface: -/// -/// - `configureBundler` is used to configure `Bundler`. -/// - `completeOnBundleThread` is used to tell the task that it is done. -pub fn BundleThread(CompletionStruct: type) type { - return struct { - const Self = @This(); - - waker: bun.Async.Waker, - ready_event: std.Thread.ResetEvent, - queue: bun.UnboundedQueue(CompletionStruct, .next), - generation: bun.Generation = 0, - - /// To initialize, put this somewhere in memory, and then call `spawn()` - pub const uninitialized: Self = .{ - .waker = undefined, - .queue = .{}, - .generation = 0, - .ready_event = .{}, - }; - - pub fn spawn(instance: *Self) !std.Thread { - const thread = try std.Thread.spawn(.{}, threadMain, .{instance}); - instance.ready_event.wait(); - return thread; - } - - /// Lazily-initialized singleton. This is used for `Bun.build` since the - /// bundle thread may not be needed. - pub const singleton = struct { - var once = std.once(loadOnceImpl); - var instance: ?*Self = null; - - // Blocks the calling thread until the bun build thread is created. - // std.once also blocks other callers of this function until the first caller is done. - fn loadOnceImpl() void { - const bundle_thread = bun.handleOom(bun.default_allocator.create(Self)); - bundle_thread.* = uninitialized; - instance = bundle_thread; - - // 2. Spawn the bun build thread. - const os_thread = bundle_thread.spawn() catch - Output.panic("Failed to spawn bun build thread", .{}); - os_thread.detach(); - } - - pub fn get() *Self { - once.call(); - return instance.?; - } - - pub fn enqueue(completion: *CompletionStruct) void { - get().enqueue(completion); - } - }; - - pub fn enqueue(instance: *Self, completion: *CompletionStruct) void { - instance.queue.push(completion); - instance.waker.wake(); - } - - fn threadMain(instance: *Self) void { - Output.Source.configureNamedThread("Bundler"); - - instance.waker = bun.Async.Waker.init() catch @panic("Failed to create waker"); - - // Unblock the calling thread so it can continue. - instance.ready_event.set(); - - var timer: bun.windows.libuv.Timer = undefined; - if (bun.Environment.isWindows) { - timer.init(instance.waker.loop.uv_loop); - timer.start(std.math.maxInt(u64), std.math.maxInt(u64), &timerCallback); - } - - var has_bundled = false; - while (true) { - while (instance.queue.pop()) |completion| { - generateInNewThread(completion, instance.generation) catch |err| { - completion.result = .{ .err = err }; - completion.completeOnBundleThread(); - }; - has_bundled = true; - } - instance.generation +|= 1; - - if (has_bundled) { - bun.mimalloc.mi_collect(false); - has_bundled = false; - } - - _ = instance.waker.wait(); - } - } - - /// This is called from `Bun.build` in JavaScript. - fn generateInNewThread(completion: *CompletionStruct, generation: bun.Generation) !void { - var heap = ThreadLocalArena.init(); - defer heap.deinit(); - - const allocator = heap.allocator(); - var ast_memory_allocator = try allocator.create(js_ast.ASTMemoryAllocator); - ast_memory_allocator.* = .{ .allocator = allocator }; - ast_memory_allocator.reset(); - ast_memory_allocator.push(); - - const transpiler = try allocator.create(bun.Transpiler); - - try completion.configureBundler(transpiler, allocator); - - transpiler.resolver.generation = generation; - - const this = try BundleV2.init( - transpiler, - null, // TODO: Kit - allocator, - jsc.AnyEventLoop.init(allocator), - false, - jsc.WorkPool.get(), - heap, - ); - - this.plugins = completion.plugins; - this.completion = switch (CompletionStruct) { - BundleV2.JSBundleCompletionTask => completion, - else => @compileError("Unknown completion struct: " ++ CompletionStruct), - }; - // Set the file_map pointer for in-memory file support - this.file_map = if (completion.config.files.map.count() > 0) - &completion.config.files - else - null; - completion.transpiler = this; - - defer { - ast_memory_allocator.pop(); - this.deinitWithoutFreeingArena(); - } - - errdefer { - // Wait for wait groups to finish. There still may be ongoing work. - this.linker.source_maps.line_offset_wait_group.wait(); - this.linker.source_maps.quoted_contents_wait_group.wait(); - - var out_log = Logger.Log.init(bun.default_allocator); - bun.handleOom(this.transpiler.log.appendToWithRecycled(&out_log, true)); - completion.log = out_log; - } - - completion.result = .{ .value = try this.runFromJSInNewThread(transpiler.options.entry_points) }; - - var out_log = Logger.Log.init(bun.default_allocator); - bun.handleOom(this.transpiler.log.appendToWithRecycled(&out_log, true)); - completion.log = out_log; - completion.completeOnBundleThread(); - } - }; -} - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const Logger = @import("../logger/logger.zig"); -const Timer = @import("../perf/system_timer.zig"); -const linker = @import("./linker.zig"); -const options = @import("./options.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const Async = bun.Async; -const Environment = bun.Environment; -const Output = bun.Output; -const Transpiler = bun.Transpiler; -const bake = bun.bake; -const default_allocator = bun.default_allocator; -const js_ast = bun.ast; -const jsc = bun.jsc; - -const allocators = bun.allocators; -const ThreadLocalArena = bun.allocators.MimallocArena; - -const bundler = bun.bundle_v2; -const BundleV2 = bundler.BundleV2; diff --git a/src/bundler/Cargo.toml b/src/bundler/Cargo.toml index 3a1dd44a151a..cad26949b4f6 100644 --- a/src/bundler/Cargo.toml +++ b/src/bundler/Cargo.toml @@ -61,7 +61,7 @@ bun_threading.workspace = true bun_url.workspace = true bun_watcher.workspace = true bun_wyhash.workspace = true -# `bundle_v2.zig:ContentHasher` uses `std.hash.XxHash64`. Streaming xxh64 comes +# `bundle_v2.rs:ContentHasher` uses xxh64. Streaming xxh64 comes # from `bun_hash::XxHash64Streaming` (the C++/Highway kernel) so the workspace # has exactly one xxhash implementation. bun_hash.workspace = true diff --git a/src/bundler/Chunk.zig b/src/bundler/Chunk.zig deleted file mode 100644 index a097b0793628..000000000000 --- a/src/bundler/Chunk.zig +++ /dev/null @@ -1,853 +0,0 @@ -pub const ChunkImport = struct { - chunk_index: u32, - import_kind: ImportKind, -}; - -pub const Chunk = struct { - /// This is a random string and is used to represent the output path of this - /// chunk before the final output path has been computed. See OutputPiece - /// for more info on this technique. - unique_key: string = "", - - /// Maps source index to bytes contributed to this chunk's output (for metafile). - /// The value is updated during chunk generation to track bytesInOutput. - files_with_parts_in_chunk: std.AutoArrayHashMapUnmanaged(Index.Int, usize) = .{}, - - /// We must not keep pointers to this type until all chunks have been allocated. - entry_bits: AutoBitSet = undefined, - - final_rel_path: string = "", - /// The path template used to generate `final_rel_path` - template: PathTemplate = .{}, - - /// For code splitting - cross_chunk_imports: BabyList(ChunkImport) = .{}, - - content: Content, - - entry_point: Chunk.EntryPoint = .{}, - - output_source_map: SourceMap.SourceMapPieces, - - intermediate_output: IntermediateOutput = .{ .empty = {} }, - isolated_hash: u64 = std.math.maxInt(u64), - - renamer: renamer.Renamer = undefined, - - compile_results_for_chunk: []CompileResult = &.{}, - - /// Pre-built JSON fragment for this chunk's metafile output entry. - /// Generated during parallel chunk generation, joined at the end. - metafile_chunk_json: []const u8 = "", - - /// Pack boolean flags to reduce padding overhead. - /// Previously 3 separate bool fields caused ~21 bytes of padding waste. - flags: Flags = .{}, - - pub const Flags = packed struct(u8) { - is_executable: bool = false, - has_html_chunk: bool = false, - is_browser_chunk_from_server_build: bool = false, - _padding: u5 = 0, - }; - - pub inline fn isEntryPoint(this: *const Chunk) bool { - return this.entry_point.is_entry_point; - } - - /// Returns the HTML closing tag that must be escaped when this chunk's content - /// is inlined into a standalone HTML file (e.g. " " " unreachable, - }; - } - - pub fn getJSChunkForHTML(this: *const Chunk, chunks: []Chunk) ?*Chunk { - const entry_point_id = this.entry_point.entry_point_id; - for (chunks) |*other| { - if (other.content == .javascript) { - if (other.entry_point.entry_point_id == entry_point_id) { - return other; - } - } - } - return null; - } - - pub fn getCSSChunkForHTML(this: *const Chunk, chunks: []Chunk) ?*Chunk { - // Look up the CSS chunk via the JS chunk's css_chunks indices. - // This correctly handles deduplicated CSS chunks that are shared - // across multiple HTML entry points (see issue #23668). - if (this.getJSChunkForHTML(chunks)) |js_chunk| { - const css_chunk_indices = js_chunk.content.javascript.css_chunks; - if (css_chunk_indices.len > 0) { - return &chunks[css_chunk_indices[0]]; - } - } - // Fallback: match by entry_point_id for cases without a JS chunk. - const entry_point_id = this.entry_point.entry_point_id; - for (chunks) |*other| { - if (other.content == .css) { - if (other.entry_point.entry_point_id == entry_point_id) { - return other; - } - } - } - return null; - } - - pub inline fn entryBits(this: *const Chunk) *const AutoBitSet { - return &this.entry_bits; - } - - pub const Order = struct { - source_index: Index.Int = 0, - distance: u32 = 0, - tie_breaker: u32 = 0, - - pub fn lessThan(_: @This(), a: Order, b: Order) bool { - return (a.distance < b.distance) or - (a.distance == b.distance and a.tie_breaker < b.tie_breaker); - } - - /// Sort so files closest to an entry point come first. If two files are - /// equidistant to an entry point, then break the tie by sorting on the - /// stable source index derived from the DFS over all entry points. - pub fn sort(a: []Order) void { - std.sort.pdq(Order, a, Order{}, lessThan); - } - }; - - /// TODO: rewrite this - /// This implementation is just slow. - /// Can we make the JSPrinter itself track this without increasing - /// complexity a lot? - pub const IntermediateOutput = union(enum) { - /// If the chunk has references to other chunks, then "pieces" contains - /// the contents of the chunk. Another joiner will have to be - /// constructed later when merging the pieces together. - /// - /// See OutputPiece's documentation comment for more details. - pieces: bun.BabyList(OutputPiece), - - /// If the chunk doesn't have any references to other chunks, then - /// `joiner` contains the contents of the chunk. This is more efficient - /// because it avoids doing a join operation twice. - joiner: StringJoiner, - - empty: void, - - pub fn allocatorForSize(size: usize) std.mem.Allocator { - if (size >= 512 * 1024) - return std.heap.page_allocator - else - return bun.default_allocator; - } - - /// Count occurrences of a closing HTML tag (e.g. `= tag_suffix.len and - strings.eqlCaseInsensitiveASCIIIgnoreLength(remaining[0..tag_suffix.len], tag_suffix)) - { - count += 1; - remaining = remaining[tag_suffix.len..]; - } - } - return count; - } - - /// Copy `content` into `dest`, escaping occurrences of `close_tag` by - /// replacing `= tag_suffix.len and - strings.eqlCaseInsensitiveASCIIIgnoreLength(remaining[0..tag_suffix.len], tag_suffix)) - { - dest[dst] = '<'; - dest[dst + 1] = '\\'; - dest[dst + 2] = '/'; - dst += 3; - } else { - dest[dst] = '<'; - dest[dst + 1] = '/'; - dst += 2; - } - } - @memcpy(dest[dst..][0..remaining.len], remaining); - dst += remaining.len; - return dst; - } - - pub const CodeResult = struct { - buffer: []u8, - shifts: []SourceMap.SourceMapShifts, - }; - - pub fn getSize(this: *const IntermediateOutput) usize { - return switch (this.*) { - .pieces => |pieces| brk: { - var total: usize = 0; - for (pieces.slice()) |piece| { - total += piece.data_len; - } - break :brk total; - }, - .joiner => |*joiner| joiner.len, - .empty => 0, - }; - } - - pub fn code( - this: *IntermediateOutput, - allocator_to_use: ?std.mem.Allocator, - parse_graph: *const Graph, - linker_graph: *const LinkerGraph, - import_prefix: []const u8, - chunk: *Chunk, - chunks: []Chunk, - display_size: ?*usize, - force_absolute_path: bool, - enable_source_map_shifts: bool, - ) bun.OOM!CodeResult { - return switch (enable_source_map_shifts) { - inline else => |source_map_shifts| this.codeWithSourceMapShifts( - allocator_to_use, - parse_graph, - linker_graph, - import_prefix, - chunk, - chunks, - display_size, - force_absolute_path, - source_map_shifts, - null, - ), - }; - } - - /// Like `code()` but with standalone HTML support. - /// When `standalone_chunk_contents` is provided, chunk piece references are - /// resolved to inline code content instead of file paths. Asset references - /// are resolved to data: URIs from url_for_css. - pub fn codeStandalone( - this: *IntermediateOutput, - allocator_to_use: ?std.mem.Allocator, - parse_graph: *const Graph, - linker_graph: *const LinkerGraph, - import_prefix: []const u8, - chunk: *Chunk, - chunks: []Chunk, - display_size: ?*usize, - force_absolute_path: bool, - enable_source_map_shifts: bool, - standalone_chunk_contents: []const ?[]const u8, - ) bun.OOM!CodeResult { - return switch (enable_source_map_shifts) { - inline else => |source_map_shifts| this.codeWithSourceMapShifts( - allocator_to_use, - parse_graph, - linker_graph, - import_prefix, - chunk, - chunks, - display_size, - force_absolute_path, - source_map_shifts, - standalone_chunk_contents, - ), - }; - } - - pub fn codeWithSourceMapShifts( - this: *IntermediateOutput, - allocator_to_use: ?std.mem.Allocator, - graph: *const Graph, - linker_graph: *const LinkerGraph, - import_prefix: []const u8, - chunk: *Chunk, - chunks: []Chunk, - display_size: ?*usize, - force_absolute_path: bool, - comptime enable_source_map_shifts: bool, - standalone_chunk_contents: ?[]const ?[]const u8, - ) bun.OOM!CodeResult { - const additional_files = graph.input_files.items(.additional_files); - const unique_key_for_additional_files = graph.input_files.items(.unique_key_for_additional_file); - const relative_platform_buf = bun.path_buffer_pool.get(); - defer bun.path_buffer_pool.put(relative_platform_buf); - switch (this.*) { - .pieces => |*pieces| { - const entry_point_chunks_for_scb = linker_graph.files.items(.entry_point_chunk_index); - - var shift = if (enable_source_map_shifts) - SourceMap.SourceMapShifts{ - .after = .{}, - .before = .{}, - }; - var shifts = if (enable_source_map_shifts) - try std.ArrayList(SourceMap.SourceMapShifts).initCapacity(bun.default_allocator, pieces.len + 1); - - if (enable_source_map_shifts) - shifts.appendAssumeCapacity(shift); - - var count: usize = 0; - var from_chunk_dir = std.fs.path.dirnamePosix(chunk.final_rel_path) orelse ""; - if (strings.eqlComptime(from_chunk_dir, ".")) - from_chunk_dir = ""; - - const urls_for_css = if (standalone_chunk_contents != null) graph.ast.items(.url_for_css) else &[_][]const u8{}; - - for (pieces.slice()) |piece| { - count += piece.data_len; - - switch (piece.query.kind) { - .chunk, .asset, .scb, .html_import => { - const index = piece.query.index; - - // In standalone mode, inline chunk content and asset data URIs - if (standalone_chunk_contents) |scc| { - switch (piece.query.kind) { - .chunk => { - if (scc[index]) |content| { - // Account for escaping { - // Use data: URI from url_for_css if available - if (index < urls_for_css.len and urls_for_css[index].len > 0) { - count += urls_for_css[index].len; - continue; - } - }, - else => {}, - } - } - - const file_path = switch (piece.query.kind) { - .asset => brk: { - const files = additional_files[index]; - if (!(files.len > 0)) { - Output.panic("Internal error: missing asset file", .{}); - } - - const output_file = files.last().?.output_file; - - break :brk graph.additional_output_files.items[output_file].dest_path; - }, - .chunk => chunks[index].final_rel_path, - .scb => chunks[entry_point_chunks_for_scb[index]].final_rel_path, - .html_import => { - count += std.fmt.count("{f}", .{HTMLImportManifest.formatEscapedJSON(.{ - .index = index, - .graph = graph, - .chunks = chunks, - .linker_graph = linker_graph, - })}); - continue; - }, - .none => unreachable, - }; - - const cheap_normalizer = cheapPrefixNormalizer( - import_prefix, - if (from_chunk_dir.len == 0 or force_absolute_path) - file_path - else - bun.path.relativePlatformBuf(relative_platform_buf, from_chunk_dir, file_path, .posix, false), - ); - count += cheap_normalizer[0].len + cheap_normalizer[1].len; - }, - .none => {}, - } - } - - if (display_size) |amt| { - amt.* = count; - } - - const debug_id_len = if (enable_source_map_shifts and FeatureFlags.source_map_debug_id) - std.fmt.count("\n//# debugId={f}\n", .{bun.SourceMap.DebugIDFormatter{ .id = chunk.isolated_hash }}) - else - 0; - - const total_buf = try (allocator_to_use orelse allocatorForSize(count)).alloc(u8, count + debug_id_len); - var remain = total_buf; - - for (pieces.slice()) |piece| { - const data = piece.data(); - - if (enable_source_map_shifts) { - var data_offset = SourceMap.LineColumnOffset{}; - data_offset.advance(data); - shift.before.add(data_offset); - shift.after.add(data_offset); - } - - if (data.len > 0) - @memcpy(remain[0..data.len], data); - - remain = remain[data.len..]; - - switch (piece.query.kind) { - .asset, .chunk, .scb, .html_import => { - const index = piece.query.index; - - // In standalone mode, inline chunk content and asset data URIs - if (standalone_chunk_contents) |scc| { - const inline_content: ?[]const u8 = switch (piece.query.kind) { - .chunk => scc[index], - .asset => if (index < urls_for_css.len and urls_for_css[index].len > 0) urls_for_css[index] else null, - else => null, - }; - if (inline_content) |content| { - if (enable_source_map_shifts) { - switch (piece.query.kind) { - .chunk => shift.before.advance(chunks[index].unique_key), - .asset => shift.before.advance(unique_key_for_additional_files[index]), - else => {}, - } - shift.after.advance(content); - shifts.appendAssumeCapacity(shift); - } - // For chunk content, escape closing tags ( brk: { - const files = additional_files[index]; - bun.assert(files.len > 0); - - const output_file = files.last().?.output_file; - - if (enable_source_map_shifts) { - shift.before.advance(unique_key_for_additional_files[index]); - } - - break :brk graph.additional_output_files.items[output_file].dest_path; - }, - .chunk => brk: { - const piece_chunk = chunks[index]; - - if (enable_source_map_shifts) { - shift.before.advance(piece_chunk.unique_key); - } - - break :brk piece_chunk.final_rel_path; - }, - .scb => brk: { - const piece_chunk = chunks[entry_point_chunks_for_scb[index]]; - - if (enable_source_map_shifts) { - shift.before.advance(piece_chunk.unique_key); - } - - break :brk piece_chunk.final_rel_path; - }, - .html_import => { - var fixed_buffer_stream = std.io.fixedBufferStream(remain); - const writer = fixed_buffer_stream.writer(); - - HTMLImportManifest.writeEscapedJSON(index, graph, linker_graph, chunks, writer) catch unreachable; - remain = remain[fixed_buffer_stream.pos..]; - - if (enable_source_map_shifts) { - shift.before.advance(chunk.unique_key); - shifts.appendAssumeCapacity(shift); - } - continue; - }, - else => unreachable, - }; - - // normalize windows paths to '/' - bun.path.platformToPosixInPlace(u8, @constCast(file_path)); - const cheap_normalizer = cheapPrefixNormalizer( - import_prefix, - if (from_chunk_dir.len == 0 or force_absolute_path) - file_path - else - bun.path.relativePlatformBuf(relative_platform_buf, from_chunk_dir, file_path, .posix, false), - ); - - if (cheap_normalizer[0].len > 0) { - @memcpy(remain[0..cheap_normalizer[0].len], cheap_normalizer[0]); - remain = remain[cheap_normalizer[0].len..]; - if (enable_source_map_shifts) - shift.after.advance(cheap_normalizer[0]); - } - - if (cheap_normalizer[1].len > 0) { - @memcpy(remain[0..cheap_normalizer[1].len], cheap_normalizer[1]); - remain = remain[cheap_normalizer[1].len..]; - if (enable_source_map_shifts) - shift.after.advance(cheap_normalizer[1]); - } - - if (enable_source_map_shifts) - shifts.appendAssumeCapacity(shift); - }, - .none => {}, - } - } - - if (enable_source_map_shifts and FeatureFlags.source_map_debug_id) { - // This comment must go before the //# sourceMappingURL comment - remain = remain[(std.fmt.bufPrint( - remain, - "\n//# debugId={f}\n", - .{bun.SourceMap.DebugIDFormatter{ .id = chunk.isolated_hash }}, - ) catch |err| switch (err) { - error.NoSpaceLeft => std.debug.panic( - "unexpected NoSpaceLeft error from bufPrint", - .{}, - ), - }).len..]; - } - - bun.assert(remain.len == 0); - bun.assert(total_buf.len == count + debug_id_len); - - return .{ - .buffer = total_buf, - .shifts = if (enable_source_map_shifts) - shifts.items - else - &[_]SourceMap.SourceMapShifts{}, - }; - }, - .joiner => |*joiner| { - const allocator = allocator_to_use orelse allocatorForSize(joiner.len); - - if (display_size) |amt| { - amt.* = joiner.len; - } - - const buffer = brk: { - if (enable_source_map_shifts and FeatureFlags.source_map_debug_id) { - // This comment must go before the //# sourceMappingURL comment - const debug_id_fmt = std.fmt.allocPrint( - graph.heap.allocator(), - "\n//# debugId={f}\n", - .{bun.SourceMap.DebugIDFormatter{ .id = chunk.isolated_hash }}, - ) catch |err| bun.handleOom(err); - - break :brk try joiner.doneWithEnd(allocator, debug_id_fmt); - } - - break :brk try joiner.done(allocator); - }; - - return .{ - .buffer = buffer, - .shifts = &[_]SourceMap.SourceMapShifts{}, - }; - }, - .empty => return .{ - .buffer = "", - .shifts = &[_]SourceMap.SourceMapShifts{}, - }, - } - } - }; - - /// An issue with asset files and server component boundaries is they - /// contain references to output paths, but those paths are not known until - /// very late in the bundle. The solution is to have a magic word in the - /// bundle text (BundleV2.unique_key, a random u64; impossible to guess). - /// When a file wants a path to an emitted chunk, it emits the unique key - /// in hex followed by the kind of path it wants: - /// - /// `74f92237f4a85a6aA00000009` --> `./some-asset.png` - /// ^--------------^|^------- .query.index - /// unique_key .query.kind - /// - /// An output piece is the concatenation of source code text and an output - /// path, in that order. An array of pieces makes up an entire file. - pub const OutputPiece = struct { - /// Pointer and length split to reduce struct size - data_ptr: [*]const u8, - data_len: u32, - query: Query, - - pub fn data(this: OutputPiece) []const u8 { - return this.data_ptr[0..this.data_len]; - } - - pub const Query = packed struct(u32) { - index: u29, - kind: Kind, - - pub const Kind = enum(u3) { - /// The last piece in an array uses this to indicate it is just data - none, - /// Given a source index, print the asset's output - asset, - /// Given a chunk index, print the chunk's output path - chunk, - /// Given a server component boundary index, print the chunk's output path - scb, - /// Given an HTML import index, print the manifest - html_import, - }; - - pub const none: Query = .{ .index = 0, .kind = .none }; - }; - - pub fn init(data_slice: []const u8, query: Query) OutputPiece { - return .{ - .data_ptr = data_slice.ptr, - .data_len = @intCast(data_slice.len), - .query = query, - }; - } - }; - - pub const OutputPieceIndex = OutputPiece.Query; - - pub const EntryPoint = packed struct(u64) { - /// Index into `Graph.input_files` - source_index: u32 = 0, - entry_point_id: ID = 0, - is_entry_point: bool = false, - is_html: bool = false, - - /// so `EntryPoint` can be a u64 - pub const ID = u30; - }; - - pub const JavaScriptChunk = struct { - files_in_chunk_order: []const Index.Int = &.{}, - parts_in_chunk_in_order: []const PartRange = &.{}, - - // for code splitting - exports_to_other_chunks: std.ArrayHashMapUnmanaged(Ref, string, Ref.ArrayHashCtx, false) = .{}, - imports_from_other_chunks: ImportsFromOtherChunks = .{}, - cross_chunk_prefix_stmts: BabyList(Stmt) = .{}, - cross_chunk_suffix_stmts: BabyList(Stmt) = .{}, - - /// Indexes to CSS chunks. Currently this will only ever be zero or one - /// items long, but smarter css chunking will allow multiple js entry points - /// share a css file, or have an entry point contain multiple css files. - /// - /// Mutated while sorting chunks in `computeChunks` - css_chunks: []u32 = &.{}, - - /// Serialized ModuleInfo for ESM bytecode (--compile --bytecode --format=esm) - module_info_bytes: ?[]const u8 = null, - /// Unserialized ModuleInfo for deferred serialization (after chunk paths are resolved) - module_info: ?*analyze_transpiled_module.ModuleInfo = null, - }; - - pub const CssChunk = struct { - imports_in_chunk_in_order: BabyList(CssImportOrder), - /// When creating a chunk, this is to be an uninitialized slice with - /// length of `imports_in_chunk_in_order` - /// - /// Multiple imports may refer to the same file/stylesheet, but may need to - /// wrap them in conditions (e.g. a layer). - /// - /// When we go through the `prepareCssAstsForChunk()` step, each import will - /// create a shallow copy of the file's AST (just dereferencing the pointer). - asts: []bun.css.BundlerStyleSheet, - }; - - const CssImportKind = enum { - source_index, - external_path, - import_layers, - }; - - pub const CssImportOrder = struct { - conditions: BabyList(bun.css.ImportConditions) = .{}, - condition_import_records: BabyList(ImportRecord) = .{}, - - kind: union(enum) { - /// Represents earlier imports that have been made redundant by later ones (see `isConditionalImportRedundant`) - /// We don't want to redundantly print the rules of these redundant imports - /// BUT, the imports may include layers. - /// We'll just print layer name declarations so that the original ordering is preserved. - layers: Layers, - external_path: bun.fs.Path, - source_index: Index, - }, - - pub const Layers = bun.ptr.Cow(bun.BabyList(bun.css.LayerName), struct { - const Self = bun.BabyList(bun.css.LayerName); - pub fn copy(self: *const Self, allocator: std.mem.Allocator) Self { - return self.deepCloneInfallible(allocator); - } - - pub fn deinit(self: *Self, a: std.mem.Allocator) void { - // do shallow deinit since `LayerName` has - // allocations in arena - self.clearAndFree(a); - } - }); - - pub fn hash(this: *const CssImportOrder, hasher: anytype) void { - // TODO: conditions, condition_import_records - - bun.writeAnyToHasher(hasher, std.meta.activeTag(this.kind)); - switch (this.kind) { - .layers => |layers| { - for (layers.inner().sliceConst()) |layer| { - for (layer.v.slice(), 0..) |layer_name, i| { - const is_last = i == layers.inner().len - 1; - if (is_last) { - hasher.update(layer_name); - } else { - hasher.update(layer_name); - hasher.update("."); - } - } - } - hasher.update("\x00"); - }, - .external_path => |path| hasher.update(path.text), - .source_index => |idx| bun.writeAnyToHasher(hasher, idx), - } - } - - pub fn fmt(this: *const CssImportOrder, ctx: *LinkerContext) CssImportOrderDebug { - return .{ - .inner = this, - .ctx = ctx, - }; - } - - pub const CssImportOrderDebug = struct { - inner: *const CssImportOrder, - ctx: *LinkerContext, - - pub fn format(this: *const CssImportOrderDebug, writer: *std.Io.Writer) !void { - try writer.print("{s} = ", .{@tagName(this.inner.kind)}); - switch (this.inner.kind) { - .layers => |layers| { - try writer.print("[", .{}); - const l = layers.inner(); - for (l.sliceConst(), 0..) |*layer, i| { - if (i > 0) try writer.print(", ", .{}); - try writer.print("\"{f}\"", .{layer}); - } - - try writer.print("]", .{}); - }, - .external_path => |path| { - try writer.print("\"{s}\"", .{path.pretty}); - }, - .source_index => |source_index| { - const source = this.ctx.parse_graph.input_files.items(.source)[source_index.get()]; - try writer.print("{d} ({s})", .{ source_index.get(), source.path.text }); - }, - } - } - }; - }; - - pub const ImportsFromOtherChunks = std.AutoArrayHashMapUnmanaged(Index.Int, CrossChunkImport.Item.List); - - pub const Content = union(enum) { - javascript: JavaScriptChunk, - css: CssChunk, - html, - - pub fn sourcemap(this: *const Content, default: options.SourceMapOption) options.SourceMapOption { - return switch (this.*) { - .javascript => default, - .css => .none, // TODO: css source maps - .html => .none, - }; - } - - pub fn loader(this: *const Content) Loader { - return switch (this.*) { - .javascript => .js, - .css => .css, - .html => .html, - }; - } - - pub fn ext(this: *const Content) string { - return switch (this.*) { - .javascript => "js", - .css => "css", - .html => "html", - }; - } - }; -}; - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const string = []const u8; - -const HTMLImportManifest = @import("./HTMLImportManifest.zig"); -const analyze_transpiled_module = @import("./analyze_transpiled_module.zig"); -const std = @import("std"); - -const options = @import("./options.zig"); -const Loader = options.Loader; - -const bun = @import("bun"); -const FeatureFlags = bun.FeatureFlags; -const ImportKind = bun.ImportKind; -const ImportRecord = bun.ImportRecord; -const Output = bun.Output; -const SourceMap = bun.SourceMap; -const StringJoiner = bun.StringJoiner; -const default_allocator = bun.default_allocator; -const renamer = bun.renamer; -const strings = bun.strings; -const AutoBitSet = bun.bit_set.AutoBitSet; -const BabyList = bun.collections.BabyList; - -const js_ast = bun.ast; -const Stmt = js_ast.Stmt; - -const bundler = bun.bundle_v2; -const BundleV2 = bundler.BundleV2; -const CompileResult = bundler.CompileResult; -const CrossChunkImport = bundler.CrossChunkImport; -const EntryPoint = bundler.EntryPoint; -const Graph = bundler.Graph; -const LinkerContext = bundler.LinkerContext; -const LinkerGraph = bundler.LinkerGraph; -const PartRange = bundler.PartRange; -const PathTemplate = bundler.PathTemplate; -const cheapPrefixNormalizer = bundler.cheapPrefixNormalizer; diff --git a/src/bundler/DeferredBatchTask.zig b/src/bundler/DeferredBatchTask.zig deleted file mode 100644 index 32ac3b01e6d0..000000000000 --- a/src/bundler/DeferredBatchTask.zig +++ /dev/null @@ -1,52 +0,0 @@ -/// This task is run once all parse and resolve tasks have been complete -/// and we have deferred onLoad plugins that we need to resume -/// -/// It enqueues a task to be run on the JS thread which resolves the promise -/// for every onLoad callback which called `.defer()`. -pub const DeferredBatchTask = @This(); - -running: if (Environment.isDebug) bool else u0 = if (Environment.isDebug) false else 0, - -pub fn init(this: *DeferredBatchTask) void { - if (comptime Environment.isDebug) bun.debugAssert(!this.running); - this.* = .{ - .running = if (comptime Environment.isDebug) false else 0, - }; -} - -pub fn getBundleV2(this: *DeferredBatchTask) *bun.BundleV2 { - return @alignCast(@fieldParentPtr("drain_defer_task", this)); -} - -pub fn schedule(this: *DeferredBatchTask) void { - if (comptime Environment.isDebug) { - bun.assert(!this.running); - this.running = false; - } - this.getBundleV2().jsLoopForPlugins().enqueueTaskConcurrent(jsc.ConcurrentTask.create(jsc.Task.init(this))); -} - -pub fn deinit(this: *DeferredBatchTask) void { - if (comptime Environment.isDebug) { - this.running = false; - } -} - -pub fn runOnJSThread(this: *DeferredBatchTask) void { - defer this.deinit(); - var bv2 = this.getBundleV2(); - bv2.plugins.?.drainDeferred( - if (bv2.completion) |completion| - completion.result == .err - else - false, - ) catch return; -} - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -const bun = @import("bun"); -const Environment = bun.Environment; -const jsc = bun.jsc; diff --git a/src/bundler/Graph.zig b/src/bundler/Graph.zig deleted file mode 100644 index a063f146f0b0..000000000000 --- a/src/bundler/Graph.zig +++ /dev/null @@ -1,140 +0,0 @@ -const Graph = @This(); - -pool: *ThreadPool, -heap: ThreadLocalArena, - -/// Mapping user-specified entry points to their Source Index -entry_points: std.ArrayListUnmanaged(Index) = .{}, -/// Maps entry point source indices to their original specifiers (for virtual entries resolved by plugins) -entry_point_original_names: IndexStringMap = .{}, -/// Every source index has an associated InputFile -input_files: MultiArrayList(InputFile) = .{}, -/// Every source index has an associated Ast -/// When a parse is in progress / queued, it is `Ast.empty` -ast: MultiArrayList(JSAst) = .{}, - -/// During the scan + parse phase, this value keeps a count of the remaining -/// tasks. Once it hits zero, the scan phase ends and linking begins. Note -/// that if `deferred_pending > 0`, it means there are plugin callbacks -/// to invoke before linking, which can initiate another scan phase. -/// -/// Increment and decrement this via `incrementScanCounter` and -/// `decrementScanCounter`, as asynchronous bundles check for `0` in the -/// decrement function, instead of at the top of the event loop. -/// -/// - Parsing a file (ParseTask and ServerComponentParseTask) -/// - onResolve and onLoad functions -/// - Resolving an onDefer promise -pending_items: u32 = 0, -/// When an `onLoad` plugin calls `.defer()`, the count from `pending_items` -/// is "moved" into this counter (pending_items -= 1; deferred_pending += 1) -/// -/// When `pending_items` hits zero and there are deferred pending tasks, those -/// tasks will be run, and the count is "moved" back to `pending_items` -deferred_pending: u32 = 0, - -/// A map of build targets to their corresponding module graphs. -build_graphs: std.EnumArray(options.Target, PathToSourceIndexMap), - -/// When Server Components is enabled, this holds a list of all boundary -/// files. This happens for all files with a "use " directive. -server_component_boundaries: ServerComponentBoundary.List = .{}, - -/// Track HTML imports from server-side code -/// Each entry represents a server file importing an HTML file that needs a client build -/// -/// OutputPiece.Kind.HTMLManifest corresponds to indices into the array. -html_imports: struct { - /// Source index of the server file doing the import - server_source_indices: BabyList(Index.Int) = .{}, - /// Source index of the HTML file being imported - html_source_indices: BabyList(Index.Int) = .{}, -} = .{}, - -estimated_file_loader_count: usize = 0, - -/// For Bake, a count of the CSS asts is used to make precise -/// pre-allocations without re-iterating the file listing. -css_file_count: usize = 0, - -additional_output_files: std.ArrayListUnmanaged(options.OutputFile) = .{}, - -kit_referenced_server_data: bool, -kit_referenced_client_data: bool, - -/// Do any input_files have a secondary_path.len > 0? -/// -/// Helps skip a loop. -has_any_secondary_paths: bool = false, - -pub const InputFile = struct { - source: Logger.Source, - secondary_path: []const u8 = "", - loader: options.Loader = options.Loader.file, - side_effects: _resolver.SideEffects, - allocator: std.mem.Allocator = bun.default_allocator, - additional_files: BabyList(AdditionalFile) = .{}, - unique_key_for_additional_file: string = "", - content_hash_for_additional_file: u64 = 0, - flags: Flags = .{}, - - pub const Flags = packed struct(u8) { - is_plugin_file: bool = false, - /// Set when a barrel-eligible file has `export * from` this file. - is_export_star_target: bool = false, - _: u6 = 0, - }; -}; - -pub inline fn pathToSourceIndexMap(this: *Graph, target: options.Target) *PathToSourceIndexMap { - return this.build_graphs.getPtr(target); -} - -/// Schedule a task to be run on the JS thread which resolves the promise of -/// each `.defer()` called in an onLoad plugin. -/// -/// Returns true if there were more tasks queued. -pub fn drainDeferredTasks(this: *Graph, transpiler: *BundleV2) bool { - transpiler.thread_lock.assertLocked(); - - if (this.deferred_pending > 0) { - this.pending_items += this.deferred_pending; - this.deferred_pending = 0; - - transpiler.drain_defer_task.init(); - transpiler.drain_defer_task.schedule(); - - return true; - } - - return false; -} - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -const string = []const u8; - -const IndexStringMap = @import("./IndexStringMap.zig"); -const Logger = @import("../logger/logger.zig"); -const _resolver = @import("../resolver/resolver.zig"); -const std = @import("std"); - -const options = @import("./options.zig"); -const Loader = options.Loader; - -const bun = @import("bun"); -const MultiArrayList = bun.MultiArrayList; -const BabyList = bun.collections.BabyList; -const ThreadLocalArena = bun.allocators.MimallocArena; - -const js_ast = bun.ast; -const JSAst = js_ast.BundledAst; -const ServerComponentBoundary = js_ast.ServerComponentBoundary; - -const AdditionalFile = bun.bundle_v2.AdditionalFile; -const BundleV2 = bun.bundle_v2.BundleV2; -const ParseTask = bun.bundle_v2.ParseTask; -const PathToSourceIndexMap = bun.bundle_v2.PathToSourceIndexMap; -const ThreadPool = bun.bundle_v2.ThreadPool; diff --git a/src/bundler/HTMLImportManifest.zig b/src/bundler/HTMLImportManifest.zig deleted file mode 100644 index fbd16d52de47..000000000000 --- a/src/bundler/HTMLImportManifest.zig +++ /dev/null @@ -1,276 +0,0 @@ -//! HTMLImportManifest generates JSON manifests for HTML imports in Bun's bundler. -//! -//! When you import an HTML file in JavaScript: -//! ```javascript -//! import index from "./index.html"; -//! console.log(index); -//! ``` -//! -//! Bun transforms this into a call to `__jsonParse()` with a JSON manifest containing -//! metadata about all the files generated from the HTML import: -//! -//! ```javascript -//! var src_default = __jsonParse( -//! '{"index":"./index.html","files":[{"input":"index.html","path":"./index-f2me3qnf.js","loader":"js","isEntry":true,"headers":{"etag": "eet6gn75","content-type": "text/javascript;charset=utf-8"}},{"input":"index.html","path":"./index.html","loader":"html","isEntry":true,"headers":{"etag": "r9njjakd","content-type": "text/html;charset=utf-8"}},{"input":"index.html","path":"./index-gysa5fmk.css","loader":"css","isEntry":true,"headers":{"etag": "50zb7x61","content-type": "text/css;charset=utf-8"}},{"input":"logo.svg","path":"./logo-kygw735p.svg","loader":"file","isEntry":false,"headers":{"etag": "kygw735p","content-type": "application/octet-stream"}},{"input":"react.svg","path":"./react-ck11dneg.svg","loader":"file","isEntry":false,"headers":{"etag": "ck11dneg","content-type": "application/octet-stream"}}]}' -//! ); -//! ``` -//! -//! The manifest JSON structure contains: -//! - `index`: The original HTML file path -//! - `files`: Array of all generated files with metadata: -//! - `input`: Original source file path -//! - `path`: Generated output file path (with content hash) -//! - `loader`: File type/loader used (js, css, html, file, etc.) -//! - `isEntry`: Whether this file is an entry point -//! - `headers`: HTTP headers including ETag and Content-Type -//! -//! This enables applications to: -//! 1. Know all files generated from an HTML import -//! 2. Get proper MIME types and ETags for serving files -//! 3. Implement proper caching strategies -//! 4. Handle assets referenced by the HTML file -//! -//! The manifest is generated during the linking phase and serialized as a JSON string -//! that gets embedded directly into the JavaScript output. - -const HTMLImportManifest = @This(); - -index: u32, -graph: *const Graph, -chunks: []Chunk, -linker_graph: *const LinkerGraph, - -pub fn format(this: HTMLImportManifest, writer: *std.Io.Writer) bun.OOM!void { - return write(this.index, this.graph, this.linker_graph, this.chunks, writer) catch |err| switch (err) { - // We use std.fmt.count for this - error.NoSpaceLeft => unreachable, - error.OutOfMemory => return error.OutOfMemory, - else => unreachable, - }; -} - -fn writeEntryItem( - writer: anytype, - input: []const u8, - path: []const u8, - hash: u64, - loader: options.Loader, - kind: bun.jsc.API.BuildArtifact.OutputKind, -) !void { - try writer.writeAll("{"); - - if (input.len > 0) { - try writer.writeAll("\"input\":"); - try bun.js_printer.writeJSONString(input, @TypeOf(writer), writer, .utf8); - try writer.writeAll(","); - } - - try writer.writeAll("\"path\":"); - try bun.js_printer.writeJSONString(path, @TypeOf(writer), writer, .utf8); - - try writer.writeAll(",\"loader\":\""); - try writer.writeAll(@tagName(loader)); - try writer.writeAll("\",\"isEntry\":"); - try writer.writeAll(if (kind == .@"entry-point") "true" else "false"); - try writer.writeAll(",\"headers\":{"); - - if (hash > 0) { - var base64_buf: [bun.base64.encodeLenFromSize(@sizeOf(@TypeOf(hash))) + 2]u8 = undefined; - const base64 = base64_buf[0..bun.base64.encodeURLSafe(&base64_buf, &std.mem.toBytes(hash))]; - try writer.print( - \\"etag":"{s}", - , .{base64}); - } - - try writer.print( - \\"content-type":"{s}" - , .{ - // Valid mime types are valid headers, which do not need to be escaped in JSON. - loader.toMimeType(&.{ - path, - }).value, - }); - - try writer.writeAll("}}"); -} - -// Extremely unfortunate, but necessary due to E.String not accepting pre-rescaped input and this happening at the very end. -pub fn writeEscapedJSON(index: u32, graph: *const Graph, linker_graph: *const LinkerGraph, chunks: []const Chunk, writer: anytype) !void { - var stack = std.heap.stackFallback(4096, bun.default_allocator); - const allocator = stack.get(); - var bytes = std.array_list.Managed(u8).init(allocator); - defer bytes.deinit(); - try write(index, graph, linker_graph, chunks, bytes.writer()); - try bun.js_printer.writePreQuotedString(bytes.items, @TypeOf(writer), writer, '"', false, true, .utf8); -} - -fn escapedJSONFormatter(this: HTMLImportManifest, writer: *std.Io.Writer) std.Io.Writer.Error!void { - return writeEscapedJSON(this.index, this.graph, this.linker_graph, this.chunks, writer) catch |err| switch (err) { - // We use std.fmt.count for this - error.WriteFailed => unreachable, - error.OutOfMemory => return error.WriteFailed, - else => unreachable, - }; -} - -pub fn formatEscapedJSON(this: HTMLImportManifest) std.fmt.Alt(HTMLImportManifest, escapedJSONFormatter) { - return .{ .data = this }; -} - -pub fn write(index: u32, graph: *const Graph, linker_graph: *const LinkerGraph, chunks: []const Chunk, writer: anytype) !void { - const browser_source_index = graph.html_imports.html_source_indices.slice()[index]; - const server_source_index = graph.html_imports.server_source_indices.slice()[index]; - const sources: []const bun.logger.Source = graph.input_files.items(.source); - const bv2: *const BundleV2 = @alignCast(@fieldParentPtr("graph", graph)); - var entry_point_bits = try bun.bit_set.AutoBitSet.initEmpty(bun.default_allocator, graph.entry_points.items.len); - defer entry_point_bits.deinit(bun.default_allocator); - - const root_dir = if (bv2.transpiler.options.root_dir.len > 0) bv2.transpiler.options.root_dir else bun.fs.FileSystem.instance.top_level_dir; - - try writer.writeAll("{"); - - const inject_compiler_filesystem_prefix = bv2.transpiler.options.compile; - // Use the server-side public path here. - const public_path = bv2.transpiler.options.public_path; - var temp_buffer = std.array_list.Managed(u8).init(bun.default_allocator); - defer temp_buffer.deinit(); - - for (chunks) |*ch| { - if (ch.entry_point.source_index == browser_source_index and ch.entry_point.is_entry_point) { - entry_point_bits.set(ch.entry_point.entry_point_id); - - if (ch.content == .html) { - try writer.writeAll("\"index\":"); - if (inject_compiler_filesystem_prefix) { - temp_buffer.clearRetainingCapacity(); - try temp_buffer.appendSlice(public_path); - try temp_buffer.appendSlice(bun.strings.removeLeadingDotSlash(ch.final_rel_path)); - try bun.js_printer.writeJSONString(temp_buffer.items, @TypeOf(writer), writer, .utf8); - } else { - try bun.js_printer.writeJSONString(ch.final_rel_path, @TypeOf(writer), writer, .utf8); - } - try writer.writeAll(","); - } - } - } - - // Start the files array - - try writer.writeAll("\"files\":["); - - var first = true; - - const additional_output_files = graph.additional_output_files.items; - const file_entry_bits: []const AutoBitSet = linker_graph.files.items(.entry_bits); - var already_visited_output_file = try bun.bit_set.AutoBitSet.initEmpty(bun.default_allocator, additional_output_files.len); - defer already_visited_output_file.deinit(bun.default_allocator); - - // Write all chunks that have files associated with this entry point. - // Also include browser chunks from server builds (lazy-loaded chunks from dynamic imports). - // When there's only one HTML import, all browser chunks belong to that manifest. - // When there are multiple HTML imports, only include chunks that intersect with this entry's bits. - const has_single_html_import = graph.html_imports.html_source_indices.len == 1; - for (chunks) |*ch| { - if (ch.entryBits().hasIntersection(&entry_point_bits) or - (has_single_html_import and ch.flags.is_browser_chunk_from_server_build)) - { - if (!first) try writer.writeAll(","); - first = false; - - try writeEntryItem( - writer, - brk: { - if (!ch.entry_point.is_entry_point) break :brk ""; - var path_for_key = bun.path.relativeNormalized( - root_dir, - sources[ch.entry_point.source_index].path.text, - .posix, - false, - ); - - path_for_key = bun.strings.removeLeadingDotSlash(path_for_key); - - break :brk path_for_key; - }, - brk: { - if (inject_compiler_filesystem_prefix) { - temp_buffer.clearRetainingCapacity(); - try temp_buffer.appendSlice(public_path); - try temp_buffer.appendSlice(bun.strings.removeLeadingDotSlash(ch.final_rel_path)); - break :brk temp_buffer.items; - } - break :brk ch.final_rel_path; - }, - // The HTML chunk's body embeds the hashed paths of its JS/CSS - // chunks, so its etag must change when those do. `isolated_hash` - // by design excludes those substitutions; the placeholder hash - // folds them in via `appendIsolatedHashesForImportedChunks`. - ch.template.placeholder.hash orelse ch.isolated_hash, - ch.content.loader(), - if (ch.entry_point.is_entry_point) - .@"entry-point" - else - .chunk, - ); - } - } - - for (additional_output_files, 0..) |*output_file, i| { - // Only print the file once. - if (already_visited_output_file.isSet(i)) continue; - - if (output_file.source_index.unwrap()) |source_index| { - if (source_index.get() == server_source_index) continue; - const bits: *const AutoBitSet = &file_entry_bits[source_index.get()]; - - if (bits.hasIntersection(&entry_point_bits)) { - already_visited_output_file.set(i); - if (!first) try writer.writeAll(","); - first = false; - - var path_for_key = bun.path.relativeNormalized( - root_dir, - sources[source_index.get()].path.text, - .posix, - false, - ); - path_for_key = bun.strings.removeLeadingDotSlash(path_for_key); - - try writeEntryItem( - writer, - path_for_key, - brk: { - if (inject_compiler_filesystem_prefix) { - temp_buffer.clearRetainingCapacity(); - try temp_buffer.appendSlice(public_path); - try temp_buffer.appendSlice(bun.strings.removeLeadingDotSlash(output_file.dest_path)); - break :brk temp_buffer.items; - } - break :brk output_file.dest_path; - }, - output_file.hash, - output_file.loader, - output_file.output_kind, - ); - } - } - } - - try writer.writeAll("]}"); -} - -const std = @import("std"); - -const options = @import("./options.zig"); -const Loader = options.Loader; - -const bun = @import("bun"); -const default_allocator = bun.default_allocator; -const strings = bun.strings; -const AutoBitSet = bun.bit_set.AutoBitSet; - -const bundler = bun.bundle_v2; -const BundleV2 = bundler.BundleV2; -const Chunk = bundler.Chunk; -const Graph = bundler.Graph; -const LinkerGraph = bundler.LinkerGraph; diff --git a/src/bundler/HTMLScanner.zig b/src/bundler/HTMLScanner.zig deleted file mode 100644 index 3b9a20a51208..000000000000 --- a/src/bundler/HTMLScanner.zig +++ /dev/null @@ -1,308 +0,0 @@ -const HTMLScanner = @This(); - -allocator: std.mem.Allocator, -import_records: ImportRecord.List = .{}, -log: *logger.Log, -source: *const logger.Source, - -pub fn init(allocator: std.mem.Allocator, log: *logger.Log, source: *const logger.Source) HTMLScanner { - return .{ - .allocator = allocator, - .import_records = .{}, - .log = log, - .source = source, - }; -} - -pub fn deinit(this: *HTMLScanner) void { - for (this.import_records.slice()) |*record| { - this.allocator.free(record.path.text); - } - this.import_records.deinit(this.allocator); -} - -fn createImportRecord(this: *HTMLScanner, input_path: []const u8, kind: ImportKind) !void { - // In HTML, sometimes people do /src/index.js - // In that case, we don't want to use the absolute filesystem path, we want to use the path relative to the project root - const path_to_use = if (input_path.len > 1 and input_path[0] == '/') - bun.path.joinAbsString(bun.fs.FileSystem.instance.top_level_dir, &[_][]const u8{input_path[1..]}, .auto) - - // Check if imports to (e.g) "App.tsx" are actually relative imoprts w/o the "./" - else if (input_path.len > 2 and input_path[0] != '.' and input_path[1] != '/') blk: { - const index_of_dot = std.mem.lastIndexOfScalar(u8, input_path, '.') orelse break :blk input_path; - const ext = input_path[index_of_dot..]; - if (ext.len > 4) break :blk input_path; - // /foo/bar/index.html -> /foo/bar - const dirname: []const u8 = std.fs.path.dirname(this.source.path.text) orelse break :blk input_path; - const resolved = bun.path.joinAbsString(dirname, &[_][]const u8{input_path}, .auto); - break :blk if (bun.sys.exists(resolved)) resolved else input_path; - } else input_path; - - const record = ImportRecord{ - .path = fs.Path.init(try this.allocator.dupeZ(u8, path_to_use)), - .kind = kind, - .range = logger.Range.None, - }; - - try this.import_records.append(this.allocator, record); -} - -const debug = bun.Output.scoped(.HTMLScanner, .hidden); - -pub fn onWriteHTML(_: *HTMLScanner, bytes: []const u8) void { - _ = bytes; // bytes are not written in scan phase -} - -pub fn onHTMLParseError(this: *HTMLScanner, message: []const u8) void { - this.log.addError( - this.source, - logger.Loc.Empty, - message, - ) catch |err| bun.handleOom(err); -} - -pub fn onTag(this: *HTMLScanner, _: *lol.Element, path: []const u8, url_attribute: []const u8, kind: ImportKind) void { - _ = url_attribute; - this.createImportRecord(path, kind) catch {}; -} - -const processor = HTMLProcessor(HTMLScanner, false); - -pub fn scan(this: *HTMLScanner, input: []const u8) !void { - try processor.run(this, input); -} - -pub fn HTMLProcessor( - comptime T: type, - /// If the visitor should visit html, head, body - comptime visit_document_tags: bool, -) type { - return struct { - const TagHandler = struct { - /// CSS selector to match elements - selector: []const u8, - /// Whether this tag can have text content that needs to be processed - has_content: bool = false, - /// The attribute to extract the URL from - url_attribute: []const u8, - /// The kind of import to create - kind: ImportKind, - - is_head_or_html: bool = false, - }; - - const tag_handlers = [_]TagHandler{ - // Module scripts with src - .{ - .selector = "script[src]", - .has_content = false, - .url_attribute = "src", - .kind = .stmt, - }, - // CSS Stylesheets - .{ - .selector = "link[rel='stylesheet'][href]", - .url_attribute = "href", - .kind = .at, - }, - - // CSS Assets - .{ - .selector = "link[as='style'][href]", - .url_attribute = "href", - .kind = .at, - }, - // Font files - .{ - .selector = "link[as='font'][href], link[type^='font/'][href]", - .url_attribute = "href", - .kind = .url, - }, - // Image assets - .{ - .selector = "link[as='image'][href]", - .url_attribute = "href", - .kind = .url, - }, - // Audio/Video assets - .{ - .selector = "link[as='video'][href], link[as='audio'][href]", - .url_attribute = "href", - .kind = .url, - }, - // Web Workers - .{ - .selector = "link[as='worker'][href]", - .url_attribute = "href", - .kind = .stmt, - }, - // Manifest files - .{ - .selector = "link[rel='manifest'][href]", - .url_attribute = "href", - .kind = .url, - }, - // Icons - .{ - .selector = "link[rel='icon'][href], link[rel='apple-touch-icon'][href]", - .url_attribute = "href", - .kind = .url, - }, - // Images with src - .{ - .selector = "img[src]", - .url_attribute = "src", - .kind = .url, - }, - // Images with srcset - .{ - .selector = "img[srcset]", - .url_attribute = "srcset", - .kind = .url, - }, - // Videos with src - .{ - .selector = "video[src]", - .url_attribute = "src", - .kind = .url, - }, - // Videos with poster - .{ - .selector = "video[poster]", - .url_attribute = "poster", - .kind = .url, - }, - // Audio with src - .{ - .selector = "audio[src]", - .url_attribute = "src", - .kind = .url, - }, - // Source elements with src - .{ - .selector = "source[src]", - .url_attribute = "src", - .kind = .url, - }, - // Source elements with srcset - .{ - .selector = "source[srcset]", - .url_attribute = "srcset", - .kind = .url, - }, - // // Iframes - // .{ - // .selector = "iframe[src]", - // .url_attribute = "src", - // .kind = .url, - // }, - }; - - fn generateHandlerForTag(comptime tag_info: TagHandler) fn (*T, *lol.Element) bool { - const Handler = struct { - pub fn handle(this: *T, element: *lol.Element) bool { - // Handle URL attribute if present - if (tag_info.url_attribute.len > 0) { - if (element.hasAttribute(tag_info.url_attribute) catch false) { - const value = element.getAttribute(tag_info.url_attribute); - defer value.deinit(); - if (value.len > 0) { - debug("{s} {s}", .{ tag_info.selector, value.slice() }); - T.onTag(this, element, value.slice(), tag_info.url_attribute, tag_info.kind); - } - } - } - return false; - } - }; - return Handler.handle; - } - - pub fn run(this: *T, input: []const u8) !void { - var builder = lol.HTMLRewriter.Builder.init(); - defer builder.deinit(); - - var selectors: bun.BoundedArray(*lol.HTMLSelector, tag_handlers.len + if (visit_document_tags) 3 else 0) = .{}; - defer for (selectors.slice()) |selector| { - selector.deinit(); - }; - - // Add handlers for each tag type - inline for (tag_handlers) |tag_info| { - const selector = try lol.HTMLSelector.parse(tag_info.selector); - selectors.appendAssumeCapacity(selector); - try builder.addElementContentHandlers( - selector, - T, - comptime generateHandlerForTag(tag_info), - this, - void, - null, - null, - void, - null, - null, - ); - } - - if (visit_document_tags) { - inline for (.{ "body", "head", "html" }, &.{ T.onBodyTag, T.onHeadTag, T.onHtmlTag }) |tag, cb| { - const head_selector = try lol.HTMLSelector.parse(tag); - selectors.appendAssumeCapacity(head_selector); - try builder.addElementContentHandlers( - head_selector, - T, - cb, - this, - void, - null, - null, - void, - null, - null, - ); - } - } - - const memory_settings = lol.MemorySettings{ - .preallocated_parsing_buffer_size = @max(input.len / 4, 1024), - .max_allowed_memory_usage = 1024 * 1024 * 10, - }; - - errdefer { - const last_error = lol.HTMLString.lastError(); - defer last_error.deinit(); - - if (last_error.len > 0) { - this.onHTMLParseError(last_error.slice()); - } - } - - var rewriter = try builder.build( - .UTF8, - memory_settings, - false, - T, - this, - T.onWriteHTML, - struct { - fn done(_: *T) void {} - }.done, - ); - defer rewriter.deinit(); - - try rewriter.write(input); - try rewriter.end(); - } - }; -} - -const lol = @import("../lolhtml_sys/lol_html.zig"); -const std = @import("std"); - -const ImportKind = @import("../options_types/import_record.zig").ImportKind; -const ImportRecord = @import("../options_types/import_record.zig").ImportRecord; - -const bun = @import("bun"); -const fs = bun.fs; -const logger = bun.logger; diff --git a/src/bundler/IndexStringMap.zig b/src/bundler/IndexStringMap.zig deleted file mode 100644 index d80a21ee5b53..000000000000 --- a/src/bundler/IndexStringMap.zig +++ /dev/null @@ -1,25 +0,0 @@ -const IndexStringMap = @This(); - -pub const Index = bun.ast.Index; - -map: std.AutoArrayHashMapUnmanaged(Index.Int, []const u8) = .{}, - -pub fn deinit(self: *IndexStringMap, allocator: std.mem.Allocator) void { - for (self.map.values()) |value| { - allocator.free(value); - } - self.map.deinit(allocator); -} - -pub fn get(self: *const IndexStringMap, index: Index.Int) ?[]const u8 { - return self.map.get(index); -} - -pub fn put(self: *IndexStringMap, allocator: std.mem.Allocator, index: Index.Int, value: []const u8) !void { - const duped = try allocator.dupe(u8, value); - errdefer allocator.free(duped); - try self.map.put(allocator, index, duped); -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bundler/LinkerContext.zig b/src/bundler/LinkerContext.zig deleted file mode 100644 index 633aeaf78da4..000000000000 --- a/src/bundler/LinkerContext.zig +++ /dev/null @@ -1,2782 +0,0 @@ -pub const LinkerContext = struct { - pub const debug = Output.scoped(.LinkerCtx, .visible); - pub const CompileResult = bundler.CompileResult; - - pub const OutputFileListBuilder = @import("./linker_context/OutputFileListBuilder.zig"); - pub const StaticRouteVisitor = @import("./linker_context/StaticRouteVisitor.zig"); - pub const MetafileBuilder = @import("./linker_context/MetafileBuilder.zig"); - - parse_graph: *Graph = undefined, - graph: LinkerGraph = undefined, - log: *Logger.Log = undefined, - - resolver: *Resolver = undefined, - cycle_detector: std.array_list.Managed(ImportTracker) = undefined, - - /// We may need to refer to the "__esm" and/or "__commonJS" runtime symbols - cjs_runtime_ref: Ref = Ref.None, - esm_runtime_ref: Ref = Ref.None, - - /// We may need to refer to the CommonJS "module" symbol for exports - unbound_module_ref: Ref = Ref.None, - - /// We may need to refer to the "__promiseAll" runtime symbol - promise_all_runtime_ref: Ref = Ref.None, - - options: LinkerOptions = .{}, - - loop: EventLoop, - - /// string buffer containing pre-formatted unique keys - unique_key_buf: []u8 = "", - - /// string buffer containing prefix for each unique keys - unique_key_prefix: string = "", - - source_maps: SourceMapData = .{}, - - /// This will eventually be used for reference-counting LinkerContext - /// to know whether or not we can free it safely. - pending_task_count: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), - - /// - has_any_css_locals: std.atomic.Value(u32) = std.atomic.Value(u32).init(0), - - /// Used by Bake to extract []CompileResult before it is joined - dev_server: ?*bun.bake.DevServer = null, - framework: ?*const bake.Framework = null, - - mangled_props: MangledProps = .{}, - - pub fn allocator(this: *const LinkerContext) std.mem.Allocator { - return this.graph.allocator; - } - - pub fn pathWithPrettyInitialized(this: *LinkerContext, path: Fs.Path) !Fs.Path { - return bundler.genericPathWithPrettyInitialized(path, this.options.target, this.resolver.fs.top_level_dir, this.allocator()); - } - - pub const LinkerOptions = struct { - generate_bytecode_cache: bool = false, - output_format: options.Format = .esm, - ignore_dce_annotations: bool = false, - emit_dce_annotations: bool = true, - tree_shaking: bool = true, - minify_whitespace: bool = false, - minify_syntax: bool = false, - minify_identifiers: bool = false, - banner: []const u8 = "", - footer: []const u8 = "", - css_chunking: bool = false, - compile_to_standalone_html: bool = false, - source_maps: options.SourceMapOption = .none, - target: options.Target = .browser, - compile: bool = false, - metafile: bool = false, - /// Path to write JSON metafile (for Bun.build API) - metafile_json_path: []const u8 = "", - /// Path to write markdown metafile (for Bun.build API) - metafile_markdown_path: []const u8 = "", - - mode: Mode = .bundle, - - public_path: []const u8 = "", - - pub const Mode = enum { - passthrough, - bundle, - }; - }; - - pub const SourceMapData = struct { - line_offset_wait_group: sync.WaitGroup = .init(), - line_offset_tasks: []Task = &.{}, - - quoted_contents_wait_group: sync.WaitGroup = .init(), - quoted_contents_tasks: []Task = &.{}, - - pub const Task = struct { - ctx: *LinkerContext, - source_index: Index.Int, - thread_task: ThreadPoolLib.Task = .{ .callback = &runLineOffset }, - - pub fn runLineOffset(thread_task: *ThreadPoolLib.Task) void { - var task: *Task = @fieldParentPtr("thread_task", thread_task); - defer { - task.ctx.markPendingTaskDone(); - task.ctx.source_maps.line_offset_wait_group.finish(); - } - - const worker = ThreadPool.Worker.get(@fieldParentPtr("linker", task.ctx)); - defer worker.unget(); - SourceMapData.computeLineOffsets(task.ctx, worker.allocator, task.source_index); - } - - pub fn runQuotedSourceContents(thread_task: *ThreadPoolLib.Task) void { - var task: *Task = @fieldParentPtr("thread_task", thread_task); - defer { - task.ctx.markPendingTaskDone(); - task.ctx.source_maps.quoted_contents_wait_group.finish(); - } - - const worker = ThreadPool.Worker.get(@fieldParentPtr("linker", task.ctx)); - defer worker.unget(); - - // Use the default allocator when using DevServer and the file - // was generated. This will be preserved so that remapping - // stack traces can show the source code, even after incremental - // rebuilds occur. - const alloc = if (worker.ctx.transpiler.options.dev_server) |dev| - dev.allocator() - else - worker.allocator; - - SourceMapData.computeQuotedSourceContents(task.ctx, alloc, task.source_index); - } - }; - - pub fn computeLineOffsets(this: *LinkerContext, alloc: std.mem.Allocator, source_index: Index.Int) void { - debug("Computing LineOffsetTable: {d}", .{source_index}); - const line_offset_table: *bun.SourceMap.LineOffsetTable.List = &this.graph.files.items(.line_offset_table)[source_index]; - - const source: *const Logger.Source = &this.parse_graph.input_files.items(.source)[source_index]; - const loader: options.Loader = this.parse_graph.input_files.items(.loader)[source_index]; - - if (!loader.canHaveSourceMap()) { - // This is not a file which we support generating source maps for - line_offset_table.* = .{}; - return; - } - - const approximate_line_count = this.graph.ast.items(.approximate_newline_count)[source_index]; - - line_offset_table.* = bun.SourceMap.LineOffsetTable.generate( - alloc, - source.contents, - - // We don't support sourcemaps for source files with more than 2^31 lines - @as(i32, @intCast(@as(u31, @truncate(approximate_line_count)))), - ); - } - - pub fn computeQuotedSourceContents(this: *LinkerContext, _: std.mem.Allocator, source_index: Index.Int) void { - debug("Computing Quoted Source Contents: {d}", .{source_index}); - const quoted_source_contents = &this.graph.files.items(.quoted_source_contents)[source_index]; - quoted_source_contents.reset(); - - const loader: options.Loader = this.parse_graph.input_files.items(.loader)[source_index]; - if (!loader.canHaveSourceMap()) { - return; - } - - const source: *const Logger.Source = &this.parse_graph.input_files.items(.source)[source_index]; - var mutable = MutableString.initEmpty(bun.default_allocator); - bun.handleOom(js_printer.quoteForJSON(source.contents, &mutable, false)); - var mutableOwned = mutable.toDefaultOwned(); - quoted_source_contents.* = mutableOwned.toOptional(); - } - }; - - pub fn isExternalDynamicImport(this: *LinkerContext, record: *const ImportRecord, source_index: u32) bool { - return this.graph.code_splitting and - record.kind == .dynamic and - this.graph.files.items(.entry_point_kind)[record.source_index.get()].isEntryPoint() and - record.source_index.get() != source_index; - } - - pub fn shouldIncludePart(c: *LinkerContext, source_index: Index.Int, part: Part) bool { - // As an optimization, ignore parts containing a single import statement to - // an internal non-wrapped file. These will be ignored anyway and it's a - // performance hit to include the part only to discover it's unnecessary later. - if (part.stmts.len == 1) { - if (part.stmts[0].data == .s_import) { - const record = c.graph.ast.items(.import_records)[source_index].at(part.stmts[0].data.s_import.import_record_index); - if (record.source_index.isValid() and c.graph.meta.items(.flags)[record.source_index.get()].wrap == .none) { - return false; - } - } - } - - return true; - } - - pub fn load( - this: *LinkerContext, - bundle: *BundleV2, - entry_points: []Index, - server_component_boundaries: ServerComponentBoundary.List, - reachable: []Index, - ) !void { - const trace = bun.perf.trace("Bundler.CloneLinkerGraph"); - defer trace.end(); - this.parse_graph = &bundle.graph; - - this.graph.code_splitting = bundle.transpiler.options.code_splitting; - this.log = bundle.transpiler.log; - - this.resolver = &bundle.transpiler.resolver; - this.cycle_detector = std.array_list.Managed(ImportTracker).init(this.allocator()); - - this.graph.reachable_files = reachable; - - const sources: []const Logger.Source = this.parse_graph.input_files.items(.source); - - try this.graph.load(entry_points, sources, server_component_boundaries, bundle.dynamic_import_entry_points.keys(), &this.parse_graph.entry_point_original_names); - bundle.dynamic_import_entry_points.deinit(); - - var runtime_named_exports = &this.graph.ast.items(.named_exports)[Index.runtime.get()]; - - this.esm_runtime_ref = runtime_named_exports.get("__esm").?.ref; - this.cjs_runtime_ref = runtime_named_exports.get("__commonJS").?.ref; - this.promise_all_runtime_ref = runtime_named_exports.get("__promiseAll").?.ref; - - if (this.options.output_format == .cjs) { - this.unbound_module_ref = this.graph.generateNewSymbol(Index.runtime.get(), .unbound, "module"); - } - - if (this.options.output_format == .cjs or this.options.output_format == .iife) { - const exports_kind = this.graph.ast.items(.exports_kind); - const ast_flags_list = this.graph.ast.items(.flags); - const meta_flags_list = this.graph.meta.items(.flags); - - for (entry_points) |entry_point| { - var ast_flags: js_ast.BundledAst.Flags = ast_flags_list[entry_point.get()]; - - // Loaders default to CommonJS when they are the entry point and the output - // format is not ESM-compatible since that avoids generating the ESM-to-CJS - // machinery. - if (ast_flags.has_lazy_export) { - exports_kind[entry_point.get()] = .cjs; - } - - // Entry points with ES6 exports must generate an exports object when - // targeting non-ES6 formats. Note that the IIFE format only needs this - // when the global name is present, since that's the only way the exports - // can actually be observed externally. - if (ast_flags.uses_export_keyword) { - ast_flags.uses_exports_ref = true; - ast_flags_list[entry_point.get()] = ast_flags; - meta_flags_list[entry_point.get()].force_include_exports_for_entry_point = true; - } - } - } - } - - pub fn computeDataForSourceMap( - this: *LinkerContext, - reachable: []const Index.Int, - ) void { - bun.assert(this.options.source_maps != .none); - this.source_maps.line_offset_wait_group = .initWithCount(reachable.len); - this.source_maps.quoted_contents_wait_group = .initWithCount(reachable.len); - this.source_maps.line_offset_tasks = this.allocator().alloc(SourceMapData.Task, reachable.len) catch unreachable; - this.source_maps.quoted_contents_tasks = this.allocator().alloc(SourceMapData.Task, reachable.len) catch unreachable; - - var batch = ThreadPoolLib.Batch{}; - var second_batch = ThreadPoolLib.Batch{}; - for (reachable, this.source_maps.line_offset_tasks, this.source_maps.quoted_contents_tasks) |source_index, *line_offset, *quoted| { - line_offset.* = .{ - .ctx = this, - .source_index = source_index, - .thread_task = .{ .callback = &SourceMapData.Task.runLineOffset }, - }; - quoted.* = .{ - .ctx = this, - .source_index = source_index, - .thread_task = .{ .callback = &SourceMapData.Task.runQuotedSourceContents }, - }; - batch.push(.from(&line_offset.thread_task)); - second_batch.push(.from("ed.thread_task)); - } - - // line offsets block sooner and are faster to compute, so we should schedule those first - batch.push(second_batch); - - this.scheduleTasks(batch); - } - - pub fn scheduleTasks(this: *LinkerContext, batch: ThreadPoolLib.Batch) void { - _ = this.pending_task_count.fetchAdd(@as(u32, @intCast(batch.len)), .monotonic); - this.parse_graph.pool.worker_pool.schedule(batch); - } - - pub fn markPendingTaskDone(this: *LinkerContext) void { - _ = this.pending_task_count.fetchSub(1, .monotonic); - } - - fn processHtmlImportFiles(this: *LinkerContext) void { - const server_source_indices = &this.parse_graph.html_imports.server_source_indices; - const html_source_indices = &this.parse_graph.html_imports.html_source_indices; - if (server_source_indices.len > 0) { - const input_files: []const Logger.Source = this.parse_graph.input_files.items(.source); - const map = this.parse_graph.pathToSourceIndexMap(.browser); - const parts: []const BabyList(js_ast.Part) = this.graph.ast.items(.parts); - const actual_ref = this.graph.runtimeFunction("__jsonParse"); - - for (server_source_indices.slice()) |html_import| { - const source = &input_files[html_import]; - const source_index = map.get(source.path.text) orelse { - @panic("Assertion failed: HTML import file not found in pathToSourceIndexMap"); - }; - - bun.handleOom(html_source_indices.append(this.allocator(), source_index)); - - // S.LazyExport is a call to __jsonParse. - const original_ref = parts[html_import] - .at(1) - .stmts[0] - .data - .s_lazy_export - .e_call - .target - .data - .e_import_identifier - .ref; - - // Make the __jsonParse in that file point to the __jsonParse in the runtime chunk. - this.graph.symbols.get(original_ref).?.link = actual_ref; - - // When --splitting is enabled, we have to make sure we import the __jsonParse function. - this.graph.generateSymbolImportAndUse( - html_import, - Index.part(1).get(), - actual_ref, - 1, - Index.runtime, - ) catch |err| bun.handleOom(err); - } - } - } - - const LinkError = OOM || error{ - BuildFailed, - ImportResolutionFailed, - }; - - pub noinline fn link( - this: *LinkerContext, - bundle: *BundleV2, - entry_points: []Index, - server_component_boundaries: ServerComponentBoundary.List, - reachable: []Index, - ) LinkError![]Chunk { - try this.load( - bundle, - entry_points, - server_component_boundaries, - reachable, - ); - - if (this.options.source_maps != .none) { - this.computeDataForSourceMap(@as([]Index.Int, @ptrCast(reachable))); - } - - this.processHtmlImportFiles(); - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.checkForMemoryCorruption(); - } - - // Validate top-level await for all files first. - if (bundle.has_any_top_level_await_modules) { - const import_records_list: []ImportRecord.List = this.graph.ast.items(.import_records); - const tla_keywords = this.parse_graph.ast.items(.top_level_await_keyword); - const tla_checks = this.parse_graph.ast.items(.tla_check); - const input_files = this.parse_graph.input_files.items(.source); - const flags: []JSMeta.Flags = this.graph.meta.items(.flags); - const css_asts: []?*bun.css.BundlerStyleSheet = this.graph.ast.items(.css); - - // Process all files in source index order, like esbuild does - var source_index: u32 = 0; - while (source_index < this.graph.files.len) : (source_index += 1) { - - // Skip runtime - if (source_index == Index.runtime.get()) continue; - - // Skip if not a JavaScript AST - if (source_index >= import_records_list.len) continue; - - // Skip CSS files - if (css_asts[source_index] != null) continue; - - const import_records = import_records_list[source_index].slice(); - - _ = try this.validateTLA(source_index, tla_keywords, tla_checks, input_files, import_records, flags, import_records_list); - } - - // after validation propagate async through all importers. - try this.graph.propagateAsyncDependencies(); - } - - try this.scanImportsAndExports(); - - // Stop now if there were errors - if (this.log.hasErrors()) { - return error.BuildFailed; - } - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.checkForMemoryCorruption(); - } - - try this.treeShakingAndCodeSplitting(); - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.checkForMemoryCorruption(); - } - - const chunks = try this.computeChunks(bundle.unique_key); - - if (this.log.hasErrors()) { - return error.BuildFailed; - } - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.checkForMemoryCorruption(); - } - - try this.computeCrossChunkDependencies(chunks); - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.checkForMemoryCorruption(); - } - - this.graph.symbols.followAll(); - - return chunks; - } - - pub fn checkForMemoryCorruption(this: *LinkerContext) void { - // For this to work, you need mimalloc's debug build enabled. - // make mimalloc-debug - this.parse_graph.heap.helpCatchMemoryIssues(); - } - - pub const computeChunks = @import("./linker_context/computeChunks.zig").computeChunks; - - pub const findAllImportedPartsInJSOrder = @import("./linker_context/findAllImportedPartsInJSOrder.zig").findAllImportedPartsInJSOrder; - pub const findImportedPartsInJSOrder = @import("./linker_context/findAllImportedPartsInJSOrder.zig").findImportedPartsInJSOrder; - pub const findImportedFilesInCSSOrder = @import("./linker_context/findImportedFilesInCSSOrder.zig").findImportedFilesInCSSOrder; - pub const findImportedCSSFilesInJSOrder = @import("./linker_context/findImportedCSSFilesInJSOrder.zig").findImportedCSSFilesInJSOrder; - - pub fn generateNamedExportInFile(this: *LinkerContext, source_index: Index.Int, module_ref: Ref, name: []const u8, alias: []const u8) bun.OOM!struct { Ref, u32 } { - const ref = this.graph.generateNewSymbol(source_index, .other, name); - const part_index = try this.graph.addPartToFile(source_index, .{ - .declared_symbols = try js_ast.DeclaredSymbol.List.fromSlice( - this.allocator(), - &[_]js_ast.DeclaredSymbol{ - .{ .ref = ref, .is_top_level = true }, - }, - ), - .can_be_removed_if_unused = true, - }); - - try this.graph.generateSymbolImportAndUse(source_index, part_index, module_ref, 1, Index.init(source_index)); - var top_level = &this.graph.meta.items(.top_level_symbol_to_parts_overlay)[source_index]; - var parts_list = try this.allocator().alloc(u32, 1); - parts_list[0] = part_index; - - try top_level.put(this.allocator(), ref, BabyList(u32).fromOwnedSlice(parts_list)); - - var resolved_exports = &this.graph.meta.items(.resolved_exports)[source_index]; - try resolved_exports.put(this.allocator(), alias, ExportData{ - .data = ImportTracker{ - .source_index = Index.init(source_index), - .import_ref = ref, - }, - }); - return .{ ref, part_index }; - } - - pub const generateCodeForLazyExport = @import("./linker_context/generateCodeForLazyExport.zig").generateCodeForLazyExport; - pub const scanImportsAndExports = @import("./linker_context/scanImportsAndExports.zig").scanImportsAndExports; - pub const doStep5 = @import("./linker_context/doStep5.zig").doStep5; - pub const createExportsForFile = @import("./linker_context/doStep5.zig").createExportsForFile; - - pub fn scanCSSImports( - this: *LinkerContext, - file_source_index: u32, - file_import_records: []ImportRecord, - // slices from Graph - css_asts: []const ?*bun.css.BundlerStyleSheet, - sources: []const Logger.Source, - loaders: []const Loader, - log: *Logger.Log, - ) enum { ok, errors } { - for (file_import_records) |*record| { - if (record.source_index.isValid()) { - // Other file is not CSS - if (css_asts[record.source_index.get()] == null) { - const source = &sources[file_source_index]; - const loader = loaders[record.source_index.get()]; - - switch (loader) { - .jsx, .js, .ts, .tsx, .napi, .sqlite, .json, .jsonc, .json5, .yaml, .html, .sqlite_embedded, .md => { - log.addErrorFmt( - source, - record.range.loc, - this.allocator(), - "Cannot import a \".{s}\" file into a CSS file", - .{@tagName(loader)}, - ) catch |err| bun.handleOom(err); - }, - .css, .file, .toml, .wasm, .base64, .dataurl, .text, .bunsh => {}, - } - } - } - } - return if (log.errors > 0) .errors else .ok; - } - - const MatchImport = struct { - alias: string = "", - kind: MatchImport.Kind = MatchImport.Kind.ignore, - namespace_ref: Ref = Ref.None, - source_index: u32 = 0, - name_loc: Logger.Loc = Logger.Loc.Empty, // Optional, goes with sourceIndex, ignore if zero, - other_source_index: u32 = 0, - other_name_loc: Logger.Loc = Logger.Loc.Empty, // Optional, goes with otherSourceIndex, ignore if zero, - ref: Ref = Ref.None, - - pub const Kind = enum { - /// The import is either external or undefined - ignore, - - /// "sourceIndex" and "ref" are in use - normal, - - /// "namespaceRef" and "alias" are in use - namespace, - - /// Both "normal" and "namespace" - normal_and_namespace, - - /// The import could not be evaluated due to a cycle - cycle, - - /// The import is missing but came from a TypeScript file - probably_typescript_type, - - /// The import resolved to multiple symbols via "export * from" - ambiguous, - }; - }; - - pub fn getSource(c: *LinkerContext, index: usize) *const Logger.Source { - return &c.parse_graph.input_files.items(.source)[index]; - } - - pub fn treeShakingAndCodeSplitting(c: *LinkerContext) OOM!void { - const trace = bun.perf.trace("Bundler.treeShakingAndCodeSplitting"); - defer trace.end(); - - const parts = c.graph.ast.items(.parts); - const import_records = c.graph.ast.items(.import_records); - const css_reprs = c.graph.ast.items(.css); - const side_effects = c.parse_graph.input_files.items(.side_effects); - const entry_point_kinds = c.graph.files.items(.entry_point_kind); - const entry_points = c.graph.entry_points.items(.source_index); - const distances = c.graph.files.items(.distance_from_entry_point); - - { - const trace2 = bun.perf.trace("Bundler.markFileLiveForTreeShaking"); - defer trace2.end(); - - // Tree shaking: Each entry point marks all files reachable from itself - for (entry_points) |entry_point| { - c.markFileLiveForTreeShaking( - entry_point, - side_effects, - parts, - import_records, - entry_point_kinds, - css_reprs, - ); - } - } - - { - const trace2 = bun.perf.trace("Bundler.markFileReachableForCodeSplitting"); - defer trace2.end(); - - const file_entry_bits: []AutoBitSet = c.graph.files.items(.entry_bits); - // AutoBitSet needs to be initialized if it is dynamic - if (AutoBitSet.needsDynamic(entry_points.len)) { - for (file_entry_bits) |*bits| { - bits.* = try AutoBitSet.initEmpty(c.allocator(), entry_points.len); - } - } else if (file_entry_bits.len > 0) { - // assert that the tag is correct - bun.assert(file_entry_bits[0] == .static); - } - - // Code splitting: Determine which entry points can reach which files. This - // has to happen after tree shaking because there is an implicit dependency - // between live parts within the same file. All liveness has to be computed - // first before determining which entry points can reach which files. - for (entry_points, 0..) |entry_point, i| { - c.markFileReachableForCodeSplitting( - entry_point, - i, - distances, - 0, - parts, - import_records, - file_entry_bits, - css_reprs, - ); - } - } - } - - pub const ChunkMeta = struct { - imports: Map, - exports: Map, - dynamic_imports: std.AutoArrayHashMap(Index.Int, void), - - pub const Map = std.AutoArrayHashMap(Ref, void); - }; - - pub const computeCrossChunkDependencies = @import("./linker_context/computeCrossChunkDependencies.zig").computeCrossChunkDependencies; - - pub const GenerateChunkCtx = struct { - c: *LinkerContext, - chunks: []Chunk, - chunk: *Chunk, - }; - - pub const postProcessJSChunk = @import("./linker_context/postProcessJSChunk.zig").postProcessJSChunk; - pub const postProcessCSSChunk = @import("./linker_context/postProcessCSSChunk.zig").postProcessCSSChunk; - pub const postProcessHTMLChunk = @import("./linker_context/postProcessHTMLChunk.zig").postProcessHTMLChunk; - pub fn generateChunk(ctx: GenerateChunkCtx, chunk: *Chunk, chunk_index: usize) void { - const worker = ThreadPool.Worker.get(@fieldParentPtr("linker", ctx.c)); - defer worker.unget(); - switch (chunk.content) { - .javascript => postProcessJSChunk(ctx, worker, chunk, chunk_index) catch |err| Output.panic("TODO: handle error: {s}", .{@errorName(err)}), - .css => postProcessCSSChunk(ctx, worker, chunk) catch |err| Output.panic("TODO: handle error: {s}", .{@errorName(err)}), - .html => postProcessHTMLChunk(ctx, worker, chunk) catch |err| Output.panic("TODO: handle error: {s}", .{@errorName(err)}), - } - } - - pub const renameSymbolsInChunk = @import("./linker_context/renameSymbolsInChunk.zig").renameSymbolsInChunk; - - pub fn generateJSRenamer(ctx: GenerateChunkCtx, chunk: *Chunk, chunk_index: usize) void { - var worker = ThreadPool.Worker.get(@fieldParentPtr("linker", ctx.c)); - defer worker.unget(); - switch (chunk.content) { - .javascript => generateJSRenamer_(ctx, worker, chunk, chunk_index), - .css => {}, - .html => {}, - } - } - - fn generateJSRenamer_(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, chunk: *Chunk, chunk_index: usize) void { - _ = chunk_index; - chunk.renamer = ctx.c.renameSymbolsInChunk( - worker.allocator, - chunk, - chunk.content.javascript.files_in_chunk_order, - ) catch @panic("TODO: handle error"); - } - - pub const generateChunksInParallel = @import("./linker_context/generateChunksInParallel.zig").generateChunksInParallel; - pub const generateCompileResultForJSChunk = @import("./linker_context/generateCompileResultForJSChunk.zig").generateCompileResultForJSChunk; - pub const generateCompileResultForCssChunk = @import("./linker_context/generateCompileResultForCssChunk.zig").generateCompileResultForCssChunk; - pub const generateCompileResultForHtmlChunk = @import("./linker_context/generateCompileResultForHtmlChunk.zig").generateCompileResultForHtmlChunk; - - pub const prepareCssAstsForChunk = @import("./linker_context/prepareCssAstsForChunk.zig").prepareCssAstsForChunk; - pub const PrepareCssAstTask = @import("./linker_context/prepareCssAstsForChunk.zig").PrepareCssAstTask; - - pub fn generateSourceMapForChunk( - c: *LinkerContext, - isolated_hash: u64, - worker: *ThreadPool.Worker, - results: std.MultiArrayList(CompileResultForSourceMap), - chunk_abs_dir: string, - can_have_shifts: bool, - ) !SourceMap.SourceMapPieces { - const trace = bun.perf.trace("Bundler.generateSourceMapForChunk"); - defer trace.end(); - - var j = StringJoiner{ .allocator = worker.allocator }; - - const sources = c.parse_graph.input_files.items(.source); - const quoted_source_map_contents = c.graph.files.items(.quoted_source_contents); - - // Entries in `results` do not 1:1 map to source files, the mapping - // is actually many to one, where a source file can have multiple chunks - // in the sourcemap. - // - // This hashmap is going to map: - // `source_index` (per compilation) in a chunk - // --> - // Which source index in the generated sourcemap, referred to - // as the "mapping source index" within this function to be distinct. - var source_id_map = std.AutoArrayHashMap(u32, i32).init(worker.allocator); - defer source_id_map.deinit(); - - const source_indices = results.items(.source_index); - - j.pushStatic( - \\{ - \\ "version": 3, - \\ "sources": [ - ); - if (source_indices.len > 0) { - { - const index = source_indices[0]; - var path = sources[index].path; - try source_id_map.putNoClobber(index, 0); - - if (path.isFile()) { - const rel_path = try bun.path.relativeAlloc(worker.allocator, chunk_abs_dir, path.text); - path.pretty = rel_path; - } - - var quote_buf = try MutableString.init(worker.allocator, path.pretty.len + 2); - try js_printer.quoteForJSON(path.pretty, "e_buf, false); - j.pushStatic(quote_buf.slice()); // freed by arena - } - - var next_mapping_source_index: i32 = 1; - for (source_indices[1..]) |index| { - const gop = try source_id_map.getOrPut(index); - if (gop.found_existing) continue; - - gop.value_ptr.* = next_mapping_source_index; - next_mapping_source_index += 1; - - var path = sources[index].path; - - if (path.isFile()) { - const rel_path = try bun.path.relativeAlloc(worker.allocator, chunk_abs_dir, path.text); - path.pretty = rel_path; - } - - var quote_buf = try MutableString.init(worker.allocator, path.pretty.len + ", ".len + 2); - quote_buf.appendAssumeCapacity(", "); - try js_printer.quoteForJSON(path.pretty, "e_buf, false); - j.pushStatic(quote_buf.slice()); // freed by arena - } - } - - j.pushStatic( - \\], - \\ "sourcesContent": [ - ); - - const source_indices_for_contents = source_id_map.keys(); - if (source_indices_for_contents.len > 0) { - j.pushStatic("\n "); - j.pushStatic( - quoted_source_map_contents[source_indices_for_contents[0]].get() orelse "", - ); - - for (source_indices_for_contents[1..]) |index| { - j.pushStatic(",\n "); - j.pushStatic(quoted_source_map_contents[index].get() orelse ""); - } - } - j.pushStatic( - \\ - \\ ], - \\ "mappings": " - ); - - const mapping_start = j.len; - var prev_end_state = SourceMap.SourceMapState{}; - var prev_column_offset: i32 = 0; - const source_map_chunks = results.items(.source_map_chunk); - const offsets = results.items(.generated_offset); - for (source_map_chunks, offsets, source_indices) |chunk, offset, current_source_index| { - const mapping_source_index = source_id_map.get(current_source_index) orelse - unreachable; // the pass above during printing of "sources" must add the index - - var start_state = SourceMap.SourceMapState{ - .source_index = mapping_source_index, - .generated_line = offset.lines.zeroBased(), - .generated_column = offset.columns.zeroBased(), - }; - - if (offset.lines.zeroBased() == 0) { - start_state.generated_column += prev_column_offset; - } - - try SourceMap.appendSourceMapChunk(&j, worker.allocator, prev_end_state, start_state, chunk.buffer.list.items); - - prev_end_state = chunk.end_state; - prev_end_state.source_index = mapping_source_index; - prev_column_offset = chunk.final_generated_column; - - if (prev_end_state.generated_line == 0) { - prev_end_state.generated_column += start_state.generated_column; - prev_column_offset += start_state.generated_column; - } - } - const mapping_end = j.len; - - if (comptime FeatureFlags.source_map_debug_id) { - j.pushStatic("\",\n \"debugId\": \""); - j.push( - try std.fmt.allocPrint(worker.allocator, "{f}", .{bun.SourceMap.DebugIDFormatter{ .id = isolated_hash }}), - worker.allocator, - ); - j.pushStatic("\",\n \"names\": []\n}"); - } else { - j.pushStatic("\",\n \"names\": []\n}"); - } - - const done = try j.done(worker.allocator); - bun.assert(done[0] == '{'); - - var pieces = SourceMap.SourceMapPieces.init(worker.allocator); - if (can_have_shifts) { - try pieces.prefix.appendSlice(done[0..mapping_start]); - try pieces.mappings.appendSlice(done[mapping_start..mapping_end]); - try pieces.suffix.appendSlice(done[mapping_end..]); - } else { - try pieces.prefix.appendSlice(done); - } - - return pieces; - } - - pub fn generateIsolatedHash(c: *LinkerContext, chunk: *const Chunk) u64 { - const trace = bun.perf.trace("Bundler.generateIsolatedHash"); - defer trace.end(); - - var hasher = ContentHasher{}; - - // Mix the file names and part ranges of all of the files in this chunk into - // the hash. Objects that appear identical but that live in separate files or - // that live in separate parts in the same file must not be merged. This only - // needs to be done for JavaScript files, not CSS files. - if (chunk.content == .javascript) { - const sources = c.parse_graph.input_files.items(.source); - for (chunk.content.javascript.parts_in_chunk_in_order) |part_range| { - const source: *Logger.Source = &sources[part_range.source_index.get()]; - - const file_path = brk: { - if (source.path.isFile()) { - // Use the pretty path as the file name since it should be platform- - // independent (relative paths and the "/" path separator) - if (source.path.text.ptr == source.path.pretty.ptr) { - source.path = bun.handleOom(c.pathWithPrettyInitialized(source.path)); - } - source.path.assertPrettyIsValid(); - - break :brk source.path.pretty; - } else { - // If this isn't in the "file" namespace, just use the full path text - // verbatim. This could be a source of cross-platform differences if - // plugins are storing platform-specific information in here, but then - // that problem isn't caused by esbuild itself. - break :brk source.path.text; - } - }; - - // Include the path namespace in the hash - hasher.write(source.path.namespace); - - // Then include the file path - hasher.write(file_path); - - // Then include the part range - hasher.writeInts(&[_]u32{ - part_range.part_index_begin, - part_range.part_index_end, - }); - } - } - - // Hash the output path template as part of the content hash because we want - // any import to be considered different if the import's output path has changed. - hasher.write(chunk.template.data); - - const public_path = if (chunk.flags.is_browser_chunk_from_server_build) - @as(*bundler.BundleV2, @fieldParentPtr("linker", c)).transpilerForTarget(.browser).options.public_path - else - c.options.public_path; - - // Also hash the public path. If provided, this is used whenever files - // reference each other such as cross-chunk imports, asset file references, - // and source map comments. We always include the hash in all chunks instead - // of trying to figure out which chunks will include the public path for - // simplicity and for robustness to code changes in the future. - if (public_path.len > 0) { - hasher.write(public_path); - } - - // Include the generated output content in the hash. This excludes the - // randomly-generated import paths (the unique keys) and only includes the - // data in the spans between them. - if (chunk.intermediate_output == .pieces) { - for (chunk.intermediate_output.pieces.slice()) |piece| { - hasher.write(piece.data()); - } - } else { - var el = chunk.intermediate_output.joiner.head; - while (el) |e| : (el = e.next) { - hasher.write(e.slice); - } - } - - // Also include the source map data in the hash. The source map is named the - // same name as the chunk name for ease of discovery. So we want the hash to - // change if the source map data changes even if the chunk data doesn't change. - // Otherwise the output path for the source map wouldn't change and the source - // map wouldn't end up being updated. - // - // Note that this means the contents of all input files are included in the - // hash because of "sourcesContent", so changing a comment in an input file - // can now change the hash of the output file. This only happens when you - // have source maps enabled (and "sourcesContent", which is on by default). - // - // The generated positions in the mappings here are in the output content - // *before* the final paths have been substituted. This may seem weird. - // However, I think this shouldn't cause issues because a) the unique key - // values are all always the same length so the offsets are deterministic - // and b) the final paths will be folded into the final hash later. - hasher.write(chunk.output_source_map.prefix.items); - hasher.write(chunk.output_source_map.mappings.items); - hasher.write(chunk.output_source_map.suffix.items); - - return hasher.digest(); - } - - pub fn validateTLA( - c: *LinkerContext, - source_index: Index.Int, - tla_keywords: []const Logger.Range, - tla_checks: []js_ast.TlaCheck, - input_files: []const Logger.Source, - import_records: []const ImportRecord, - meta_flags: []JSMeta.Flags, - ast_import_records: []const bun.BabyList(ImportRecord), - ) OOM!js_ast.TlaCheck { - var result_tla_check: *js_ast.TlaCheck = &tla_checks[source_index]; - - if (result_tla_check.depth == 0) { - result_tla_check.depth = 1; - if (tla_keywords[source_index].len > 0) { - result_tla_check.parent = source_index; - } - - for (import_records, 0..) |record, import_record_index| { - if (Index.isValid(record.source_index) and (record.kind == .require or record.kind == .stmt)) { - const parent = try c.validateTLA( - record.source_index.get(), - tla_keywords, - tla_checks, - input_files, - ast_import_records[record.source_index.get()].slice(), - meta_flags, - ast_import_records, - ); - if (Index.isInvalid(Index.init(parent.parent))) { - continue; - } - - // Follow any import chains - if (record.kind == .stmt and (Index.isInvalid(Index.init(result_tla_check.parent)) or parent.depth < result_tla_check.depth)) { - result_tla_check.depth = parent.depth + 1; - result_tla_check.parent = record.source_index.get(); - result_tla_check.import_record_index = @intCast(import_record_index); - continue; - } - - // Require of a top-level await chain is forbidden - if (record.kind == .require) { - var notes = std.array_list.Managed(Logger.Data).init(c.allocator()); - - var tla_pretty_path: string = ""; - var other_source_index = record.source_index.get(); - - // Build up a chain of notes for all of the imports - while (true) { - const parent_result_tla_keyword = tla_keywords[other_source_index]; - const parent_tla_check = tla_checks[other_source_index]; - const parent_source_index = other_source_index; - - if (parent_result_tla_keyword.len > 0) { - const source = &input_files[other_source_index]; - tla_pretty_path = source.path.pretty; - notes.append(Logger.Data{ - .text = bun.handleOom(std.fmt.allocPrint(c.allocator(), "The top-level await in {s} is here:", .{tla_pretty_path})), - .location = .initOrNull(source, parent_result_tla_keyword), - }) catch |err| bun.handleOom(err); - break; - } - - if (!Index.isValid(Index.init(parent_tla_check.parent))) { - try notes.append(Logger.Data{ - .text = "unexpected invalid index", - }); - break; - } - - other_source_index = parent_tla_check.parent; - - try notes.append(Logger.Data{ - .text = try std.fmt.allocPrint(c.allocator(), "The file {s} imports the file {s} here:", .{ - input_files[parent_source_index].path.pretty, - input_files[other_source_index].path.pretty, - }), - .location = .initOrNull(&input_files[parent_source_index], ast_import_records[parent_source_index].slice()[tla_checks[parent_source_index].import_record_index].range), - }); - } - - const source: *const Logger.Source = &input_files[source_index]; - const imported_pretty_path = source.path.pretty; - const text: string = if (strings.eql(imported_pretty_path, tla_pretty_path)) - try std.fmt.allocPrint(c.allocator(), "This require call is not allowed because the imported file \"{s}\" contains a top-level await", .{imported_pretty_path}) - else - try std.fmt.allocPrint(c.allocator(), "This require call is not allowed because the transitive dependency \"{s}\" contains a top-level await", .{tla_pretty_path}); - - try c.log.addRangeErrorWithNotes(source, record.range, text, notes.items); - } - } - } - - // Make sure that if we wrap this module in a closure, the closure is also - // async. This happens when you call "import()" on this module and code - // splitting is off. - if (Index.isValid(Index.init(result_tla_check.parent))) { - meta_flags[source_index].is_async_or_has_async_dependency = true; - } - } - - return result_tla_check.*; - } - - pub const StmtList = struct { - const InsideWrapperPrefix = struct { - allocator: std.mem.Allocator, - stmts: std.ArrayListUnmanaged(Stmt), - - sync_dependencies_end: usize, - - // if true it will exist at `sync_dependencies_end` - has_async_dependency: bool, - - pub fn init(alloc: std.mem.Allocator) InsideWrapperPrefix { - return .{ .stmts = .{}, .allocator = alloc, .sync_dependencies_end = 0, .has_async_dependency = false }; - } - - pub fn deinit(this: *InsideWrapperPrefix) void { - this.stmts.deinit(this.allocator); - this.sync_dependencies_end = 0; - this.has_async_dependency = false; - } - - pub fn reset(this: *InsideWrapperPrefix) void { - this.stmts.clearRetainingCapacity(); - this.sync_dependencies_end = 0; - this.has_async_dependency = false; - } - - pub fn appendNonDependency(this: *InsideWrapperPrefix, stmt: Stmt) OOM!void { - try this.stmts.append(this.allocator, stmt); - } - - pub fn appendNonDependencySlice(this: *InsideWrapperPrefix, stmts: []const Stmt) OOM!void { - try this.stmts.appendSlice(this.allocator, stmts); - } - - pub fn appendSyncDependency(this: *InsideWrapperPrefix, call_expr: Expr) OOM!void { - try this.stmts.insert(this.allocator, this.sync_dependencies_end, Stmt.alloc(S.SExpr, .{ .value = call_expr }, call_expr.loc)); - this.sync_dependencies_end += 1; - } - - pub fn appendAsyncDependency(this: *InsideWrapperPrefix, call_expr: Expr, promise_all_ref: Ref) OOM!void { - if (!this.has_async_dependency) { - this.has_async_dependency = true; - try this.stmts.insert( - this.allocator, - this.sync_dependencies_end, - Stmt.alloc(S.SExpr, .{ .value = Expr.init(E.Await, .{ .value = call_expr }, .Empty) }, .Empty), - ); - return; - } - - const first_dep_call_expr = this.stmts.items[this.sync_dependencies_end].data.s_expr.value.data.e_await.value; - const call = first_dep_call_expr.data.e_call; - - if (call.target.data.e_identifier.ref.eql(promise_all_ref)) { - // `await __promiseAll` already in place, append to the array argument - try call.args.at(0).data.e_array.items.append(this.allocator, call_expr); - } else { - // convert single `await init_` to `await __promiseAll([init_1(), init_2()])` - - const promise_all = Expr.init(E.Identifier, .{ .ref = promise_all_ref }, .Empty); - - var items: BabyList(Expr) = try .initCapacity(this.allocator, 2); - items.appendSliceAssumeCapacity(&.{ first_dep_call_expr, call_expr }); - - var args: BabyList(Expr) = try .initCapacity(this.allocator, 1); - args.appendAssumeCapacity(Expr.init(E.Array, .{ .items = items }, .Empty)); - - const promise_all_call = Expr.init(E.Call, .{ .target = promise_all, .args = args }, .Empty); - - // replace the `await init_` expr with `await __promiseAll` - this.stmts.items[this.sync_dependencies_end] = Stmt.alloc(S.SExpr, .{ .value = Expr.init(E.Await, .{ .value = promise_all_call }, .Empty) }, .Empty); - } - } - }; - - allocator: std.mem.Allocator, - inside_wrapper_prefix: InsideWrapperPrefix, - outside_wrapper_prefix: std.ArrayListUnmanaged(Stmt), - inside_wrapper_suffix: std.ArrayListUnmanaged(Stmt), - all_stmts: std.ArrayListUnmanaged(Stmt), - - pub fn reset(this: *StmtList) void { - this.inside_wrapper_prefix.reset(); - this.outside_wrapper_prefix.clearRetainingCapacity(); - this.inside_wrapper_suffix.clearRetainingCapacity(); - this.all_stmts.clearRetainingCapacity(); - } - - pub fn deinit(this: *StmtList) void { - this.inside_wrapper_prefix.deinit(this.allocator); - this.outside_wrapper_prefix.deinit(this.allocator); - this.inside_wrapper_suffix.deinit(this.allocator); - this.all_stmts.deinit(this.allocator); - } - - pub fn init(alloc: std.mem.Allocator) StmtList { - return .{ - .allocator = alloc, - .inside_wrapper_prefix = .init(alloc), - .outside_wrapper_prefix = .{}, - .inside_wrapper_suffix = .{}, - .all_stmts = .{}, - }; - } - - const List = enum { - outside_wrapper_prefix, - inside_wrapper_suffix, - all_stmts, - }; - - pub fn appendSlice(this: *StmtList, list: List, stmts: []const Stmt) OOM!void { - try switch (list) { - .outside_wrapper_prefix => this.outside_wrapper_prefix.appendSlice(this.allocator, stmts), - .inside_wrapper_suffix => this.inside_wrapper_suffix.appendSlice(this.allocator, stmts), - .all_stmts => this.all_stmts.appendSlice(this.allocator, stmts), - }; - } - - pub fn append(this: *StmtList, list: List, stmt: Stmt) OOM!void { - try switch (list) { - .outside_wrapper_prefix => this.outside_wrapper_prefix.append(this.allocator, stmt), - .inside_wrapper_suffix => this.inside_wrapper_suffix.append(this.allocator, stmt), - .all_stmts => this.all_stmts.append(this.allocator, stmt), - }; - } - }; - - pub fn shouldRemoveImportExportStmt( - c: *LinkerContext, - stmts: *StmtList, - loc: Logger.Loc, - namespace_ref: Ref, - import_record_index: u32, - alloc: std.mem.Allocator, - ast: *const JSAst, - ) !bool { - const record = ast.import_records.at(import_record_index); - // Barrel optimization: deferred import records should be dropped - if (record.flags.is_unused) { - return true; - } - // Is this an external import? - if (!record.source_index.isValid()) { - // Keep the "import" statement if import statements are supported - if (c.options.output_format.keepES6ImportExportSyntax()) { - return false; - } - - // Otherwise, replace this statement with a call to "require()" - stmts.inside_wrapper_prefix.appendNonDependency( - Stmt.alloc( - S.Local, - S.Local{ - .decls = G.Decl.List.fromSlice( - alloc, - &.{ - .{ - .binding = Binding.alloc( - alloc, - B.Identifier{ - .ref = namespace_ref, - }, - loc, - ), - .value = Expr.init( - E.RequireString, - E.RequireString{ - .import_record_index = import_record_index, - }, - loc, - ), - }, - }, - ) catch unreachable, - }, - record.range.loc, - ), - ) catch unreachable; - return true; - } - - // We don't need a call to "require()" if this is a self-import inside a - // CommonJS-style module, since we can just reference the exports directly. - if (ast.exports_kind == .cjs and c.graph.symbols.follow(namespace_ref).eql(ast.exports_ref)) { - return true; - } - - const other_flags = c.graph.meta.items(.flags)[record.source_index.get()]; - switch (other_flags.wrap) { - .none => {}, - .cjs => { - // Replace the statement with a call to "require()" since the other module is CJS-wrapped - try stmts.inside_wrapper_prefix.appendNonDependency( - Stmt.alloc(S.Local, .{ - .decls = try G.Decl.List.fromSlice( - alloc, - &.{ - .{ - .binding = Binding.alloc(alloc, B.Identifier{ - .ref = namespace_ref, - }, loc), - .value = Expr.init(E.RequireString, .{ - .import_record_index = import_record_index, - }, loc), - }, - }, - ), - }, loc), - ); - }, - .esm => { - // Ignore this file if it's not included in the bundle. This can happen for - // wrapped ESM files but not for wrapped CommonJS files because we allow - // tree shaking inside wrapped ESM files. - if (!c.graph.files_live.isSet(record.source_index.get())) { - return true; - } - - const wrapper_ref = c.graph.ast.items(.wrapper_ref)[record.source_index.get()]; - if (wrapper_ref.isEmpty()) { - return true; - } - - // Replace the statement with a call to "init()" - const init_call = Expr.init(E.Call, .{ - .target = Expr.initIdentifier( - wrapper_ref, - loc, - ), - }, loc); - - if (other_flags.is_async_or_has_async_dependency) { - try stmts.inside_wrapper_prefix.appendAsyncDependency(init_call, c.promise_all_runtime_ref); - } else { - try stmts.inside_wrapper_prefix.appendSyncDependency(init_call); - } - }, - } - - return true; - } - - pub const convertStmtsForChunk = @import("./linker_context/convertStmtsForChunk.zig").convertStmtsForChunk; - pub const convertStmtsForChunkForDevServer = @import("./linker_context/convertStmtsForChunkForDevServer.zig").convertStmtsForChunkForDevServer; - - pub fn runtimeFunction(c: *LinkerContext, name: []const u8) Ref { - return c.graph.runtimeFunction(name); - } - - pub const generateCodeForFileInChunkJS = @import("./linker_context/generateCodeForFileInChunkJS.zig").generateCodeForFileInChunkJS; - - pub fn printCodeForFileInChunkJS( - c: *LinkerContext, - r: renamer.Renamer, - alloc: std.mem.Allocator, - writer: *js_printer.BufferWriter, - out_stmts: []Stmt, - ast: *const js_ast.BundledAst, - flags: JSMeta.Flags, - to_esm_ref: Ref, - to_commonjs_ref: Ref, - runtime_require_ref: ?Ref, - source_index: Index, - source: *const bun.logger.Source, - ) js_printer.PrintResult { - const parts_to_print = &[_]Part{ - .{ .stmts = out_stmts }, - }; - - const print_options = js_printer.Options{ - .bundling = true, - // TODO: IIFE - .indent = .{}, - .commonjs_named_exports = ast.commonjs_named_exports, - .commonjs_named_exports_ref = ast.exports_ref, - .commonjs_module_ref = if (ast.flags.uses_module_ref) - ast.module_ref - else - Ref.None, - .commonjs_named_exports_deoptimized = flags.wrap == .cjs, - .commonjs_module_exports_assigned_deoptimized = ast.flags.commonjs_module_exports_assigned_deoptimized, - // .const_values = c.graph.const_values, - .ts_enums = c.graph.ts_enums, - - .minify_whitespace = c.options.minify_whitespace, - .minify_syntax = c.options.minify_syntax, - .input_module_type = ast.exports_kind.toModuleType(), - .module_type = c.options.output_format, - .print_dce_annotations = c.options.emit_dce_annotations, - .has_run_symbol_renamer = true, - - .allocator = alloc, - .source_map_allocator = if (c.dev_server != null and - c.parse_graph.input_files.items(.loader)[source_index.get()].isJavaScriptLike()) - // The loader check avoids globally allocating asset source maps - writer.buffer.allocator - else - alloc, - .to_esm_ref = to_esm_ref, - .to_commonjs_ref = to_commonjs_ref, - .require_ref = switch (c.options.output_format) { - .cjs => null, // use unbounded global - else => runtime_require_ref, - }, - .require_or_import_meta_for_source_callback = .init( - LinkerContext, - requireOrImportMetaForSource, - c, - ), - .line_offset_tables = c.graph.files.items(.line_offset_table)[source_index.get()], - .target = c.options.target, - - .hmr_ref = if (c.options.output_format == .internal_bake_dev) - ast.wrapper_ref - else - .None, - - .input_files_for_dev_server = if (c.options.output_format == .internal_bake_dev) - c.parse_graph.input_files.items(.source) - else - null, - .mangled_props = &c.mangled_props, - }; - - writer.buffer.reset(); - var printer = js_printer.BufferPrinter.init(writer.*); - defer writer.* = printer.ctx; - - switch (c.options.source_maps != .none and !source_index.isRuntime()) { - inline else => |enable_source_maps| { - return js_printer.printWithWriter( - *js_printer.BufferPrinter, - &printer, - ast.target, - ast.toAST(), - source, - print_options, - ast.import_records.slice(), - parts_to_print, - r, - enable_source_maps, - ); - }, - } - } - - pub const PendingPartRange = struct { - part_range: PartRange, - task: ThreadPoolLib.Task, - ctx: *GenerateChunkCtx, - i: u32 = 0, - }; - - pub fn requireOrImportMetaForSource( - c: *LinkerContext, - source_index: Index.Int, - was_unwrapped_require: bool, - ) js_printer.RequireOrImportMeta { - const flags = c.graph.meta.items(.flags)[source_index]; - return .{ - .exports_ref = if (flags.wrap == .esm or (was_unwrapped_require and c.graph.ast.items(.flags)[source_index].force_cjs_to_esm)) - c.graph.ast.items(.exports_ref)[source_index] - else - Ref.None, - .is_wrapper_async = flags.is_async_or_has_async_dependency, - .wrapper_ref = c.graph.ast.items(.wrapper_ref)[source_index], - - .was_unwrapped_require = was_unwrapped_require and c.graph.ast.items(.flags)[source_index].force_cjs_to_esm, - }; - } - - const SubstituteChunkFinalPathResult = struct { - j: StringJoiner, - shifts: []SourceMap.SourceMapShifts, - }; - - pub fn mangleLocalCss(c: *LinkerContext) void { - if (c.has_any_css_locals.load(.monotonic) == 0) return; - - const all_css_asts: []?*bun.css.BundlerStyleSheet = c.graph.ast.items(.css); - const all_symbols: []Symbol.List = c.graph.ast.items(.symbols); - const all_sources: []Logger.Source = c.parse_graph.input_files.items(.source); - - // Collect all local css names - var sfb = std.heap.stackFallback(512, c.allocator()); - const alloc = sfb.get(); - var local_css_names = std.AutoHashMap(bun.bundle_v2.Ref, void).init(alloc); - defer local_css_names.deinit(); - - for (all_css_asts, 0..) |maybe_css_ast, source_index| { - if (maybe_css_ast) |css_ast| { - if (css_ast.local_scope.count() == 0) continue; - const symbols = all_symbols[source_index]; - for (symbols.sliceConst(), 0..) |*symbol_, inner_index| { - var symbol = symbol_; - if (symbol.kind == .local_css) { - const ref = ref: { - var ref = Ref.init(@intCast(inner_index), @intCast(source_index), false); - ref.tag = .symbol; - while (symbol.hasLink()) { - ref = symbol.link; - symbol = all_symbols[ref.source_index].at(ref.inner_index); - } - break :ref ref; - }; - - const entry = bun.handleOom(local_css_names.getOrPut(ref)); - if (entry.found_existing) continue; - - const source = all_sources[ref.source_index]; - - const original_name = symbol.original_name; - const path_hash = bun.css.css_modules.hash( - alloc, - "{s}", - // use path relative to cwd for determinism - .{source.path.pretty}, - false, - ); - - const final_generated_name = bun.handleOom(std.fmt.allocPrint(c.allocator(), "{s}_{s}", .{ original_name, path_hash })); - bun.handleOom(c.mangled_props.put(c.allocator(), ref, final_generated_name)); - } - } - } - } - } - - pub fn appendIsolatedHashesForImportedChunks( - c: *LinkerContext, - hash: *ContentHasher, - chunks: []Chunk, - index: u32, - chunk_visit_map: *AutoBitSet, - ) void { - // Only visit each chunk at most once. This is important because there may be - // cycles in the chunk import graph. If there's a cycle, we want to include - // the hash of every chunk involved in the cycle (along with all of their - // dependencies). This depth-first traversal will naturally do that. - if (chunk_visit_map.isSet(index)) { - return; - } - chunk_visit_map.set(index); - - // Visit the other chunks that this chunk imports before visiting this chunk - const chunk = &chunks[index]; - for (chunk.cross_chunk_imports.slice()) |import| { - c.appendIsolatedHashesForImportedChunks( - hash, - chunks, - import.chunk_index, - chunk_visit_map, - ); - } - - // Mix in hashes for content referenced via output pieces. JS chunks - // express cross-chunk dependencies via `cross_chunk_imports` above, but - // HTML (and CSS) chunks only reference other chunks through pieces, so - // recurse on those too. - switch (chunk.intermediate_output) { - .pieces => |pieces| for (pieces.slice()) |piece| switch (piece.query.kind) { - .asset => { - var from_chunk_dir = std.fs.path.dirnamePosix(chunk.final_rel_path) orelse ""; - if (strings.eqlComptime(from_chunk_dir, ".")) - from_chunk_dir = ""; - - const source_index = piece.query.index; - const additional_files: []AdditionalFile = c.parse_graph.input_files.items(.additional_files)[source_index].slice(); - bun.assert(additional_files.len > 0); - switch (additional_files[0]) { - .output_file => |output_file_id| { - const path = c.parse_graph.additional_output_files.items[output_file_id].dest_path; - hash.write(bun.path.relativePlatform(from_chunk_dir, path, .posix, false)); - }, - .source_index => {}, - } - }, - .chunk => c.appendIsolatedHashesForImportedChunks(hash, chunks, piece.query.index, chunk_visit_map), - .scb => c.appendIsolatedHashesForImportedChunks( - hash, - chunks, - c.graph.files.items(.entry_point_chunk_index)[piece.query.index], - chunk_visit_map, - ), - .none, .html_import => {}, - }, - else => {}, - } - - // Mix in the hash for this chunk - hash.write(std.mem.asBytes(&chunk.isolated_hash)); - } - - pub const writeOutputFilesToDisk = @import("./linker_context/writeOutputFilesToDisk.zig").writeOutputFilesToDisk; - - // Sort cross-chunk exports by chunk name for determinism - pub fn sortedCrossChunkExportItems( - c: *LinkerContext, - export_refs: ChunkMeta.Map, - list: *std.array_list.Managed(StableRef), - ) void { - var result = list.*; - defer list.* = result; - result.clearRetainingCapacity(); - result.ensureTotalCapacity(export_refs.count()) catch unreachable; - result.items.len = export_refs.count(); - for (export_refs.keys(), result.items) |export_ref, *item| { - if (comptime Environment.allow_assert) - debugTreeShake("Export name: {s} (in {s})", .{ - c.graph.symbols.get(export_ref).?.original_name, - c.parse_graph.input_files.get(export_ref.sourceIndex()).source.path.text, - }); - item.* = .{ - .stable_source_index = c.graph.stable_source_indices[export_ref.sourceIndex()], - .ref = export_ref, - }; - } - std.sort.pdq(StableRef, result.items, {}, StableRef.isLessThan); - } - - pub fn markFileReachableForCodeSplitting( - c: *LinkerContext, - source_index: Index.Int, - entry_points_count: usize, - distances: []u32, - distance: u32, - parts: []bun.BabyList(Part), - import_records: []bun.BabyList(bun.ImportRecord), - file_entry_bits: []AutoBitSet, - css_reprs: []?*bun.css.BundlerStyleSheet, - ) void { - if (!c.graph.files_live.isSet(source_index)) - return; - - const cur_dist = distances[source_index]; - const traverse_again = distance < cur_dist; - if (traverse_again) { - distances[source_index] = distance; - } - const out_dist = distance + 1; - - var bits = &file_entry_bits[source_index]; - - // Don't mark this file more than once - if (bits.isSet(entry_points_count) and !traverse_again) - return; - - bits.set(entry_points_count); - - if (comptime bun.Environment.enable_logs) - debugTreeShake( - "markFileReachableForCodeSplitting(entry: {d}): {s} {s} ({d})", - .{ - entry_points_count, - c.parse_graph.input_files.items(.source)[source_index].path.pretty, - @tagName(c.parse_graph.ast.items(.target)[source_index].bakeGraph()), - out_dist, - }, - ); - - if (css_reprs[source_index] != null) { - for (import_records[source_index].slice()) |*record| { - if (record.source_index.isValid() and !c.isExternalDynamicImport(record, source_index)) { - c.markFileReachableForCodeSplitting( - record.source_index.get(), - entry_points_count, - distances, - out_dist, - parts, - import_records, - file_entry_bits, - css_reprs, - ); - } - } - return; - } - - for (import_records[source_index].slice()) |*record| { - if (record.source_index.isValid() and !c.isExternalDynamicImport(record, source_index)) { - c.markFileReachableForCodeSplitting( - record.source_index.get(), - entry_points_count, - distances, - out_dist, - parts, - import_records, - file_entry_bits, - css_reprs, - ); - } - } - - const parts_in_file = parts[source_index].slice(); - for (parts_in_file) |part| { - for (part.dependencies.slice()) |dependency| { - if (dependency.source_index.get() != source_index) { - c.markFileReachableForCodeSplitting( - dependency.source_index.get(), - entry_points_count, - distances, - out_dist, - parts, - import_records, - file_entry_bits, - css_reprs, - ); - } - } - } - } - - pub fn markFileLiveForTreeShaking( - c: *LinkerContext, - source_index: Index.Int, - side_effects: []_resolver.SideEffects, - parts: []bun.BabyList(Part), - import_records: []bun.BabyList(bun.ImportRecord), - entry_point_kinds: []EntryPoint.Kind, - css_reprs: []?*bun.css.BundlerStyleSheet, - ) void { - if (comptime bun.Environment.allow_assert) { - debugTreeShake("markFileLiveForTreeShaking({d}, {s} {s}) = {s}", .{ - source_index, - c.parse_graph.input_files.get(source_index).source.path.pretty, - @tagName(c.parse_graph.ast.items(.target)[source_index].bakeGraph()), - if (c.graph.files_live.isSet(source_index)) "already seen" else "first seen", - }); - } - - defer if (Environment.allow_assert) { - debugTreeShake("end()", .{}); - }; - - if (c.graph.files_live.isSet(source_index)) return; - c.graph.files_live.set(source_index); - - if (source_index >= c.graph.ast.len) { - bun.assert(false); - return; - } - - if (css_reprs[source_index] != null) { - for (import_records[source_index].slice()) |*record| { - const other_source_index = record.source_index.get(); - if (record.source_index.isValid()) { - c.markFileLiveForTreeShaking( - other_source_index, - side_effects, - parts, - import_records, - entry_point_kinds, - css_reprs, - ); - } - } - return; - } - - // HTML files can reference non-JS/CSS assets (favicons, images, etc.) - // via .url kind import records. Follow all import records for HTML files - // so these assets are marked live and included in the manifest. - if (c.parse_graph.input_files.items(.loader)[source_index] == .html) { - for (import_records[source_index].slice()) |*record| { - if (record.source_index.isValid()) { - c.markFileLiveForTreeShaking( - record.source_index.get(), - side_effects, - parts, - import_records, - entry_point_kinds, - css_reprs, - ); - } - } - return; - } - - for (parts[source_index].slice(), 0..) |part, part_index| { - var can_be_removed_if_unused = part.can_be_removed_if_unused; - - if (can_be_removed_if_unused and part.tag == .commonjs_named_export) { - if (c.graph.meta.items(.flags)[source_index].wrap == .cjs) { - can_be_removed_if_unused = false; - } - } - - // Also include any statement-level imports - for (part.import_record_indices.slice()) |import_index| { - const record = import_records[source_index].at(import_index); - if (record.kind != .stmt) - continue; - - if (record.source_index.isValid()) { - const other_source_index = record.source_index.get(); - - // Don't include this module for its side effects if it can be - // considered to have no side effects - const se = side_effects[other_source_index]; - - if (se != .has_side_effects and - !c.options.ignore_dce_annotations) - { - continue; - } - - // Otherwise, include this module for its side effects - c.markFileLiveForTreeShaking( - other_source_index, - side_effects, - parts, - import_records, - entry_point_kinds, - css_reprs, - ); - } else if (record.flags.is_external_without_side_effects) { - // This can be removed if it's unused - continue; - } - - // If we get here then the import was included for its side effects, so - // we must also keep this part - can_be_removed_if_unused = false; - } - - // Include all parts in this file with side effects, or just include - // everything if tree-shaking is disabled. Note that we still want to - // perform tree-shaking on the runtime even if tree-shaking is disabled. - if (!can_be_removed_if_unused or - (!part.force_tree_shaking and - !c.options.tree_shaking and - entry_point_kinds[source_index].isEntryPoint())) - { - c.markPartLiveForTreeShaking( - @intCast(part_index), - source_index, - side_effects, - parts, - import_records, - entry_point_kinds, - css_reprs, - ); - } - } - } - - pub fn markPartLiveForTreeShaking( - c: *LinkerContext, - part_index: Index.Int, - source_index: Index.Int, - side_effects: []_resolver.SideEffects, - parts: []bun.BabyList(Part), - import_records: []bun.BabyList(bun.ImportRecord), - entry_point_kinds: []EntryPoint.Kind, - css_reprs: []?*bun.css.BundlerStyleSheet, - ) void { - const part: *Part = &parts[source_index].slice()[part_index]; - - // only once - if (part.is_live) { - return; - } - part.is_live = true; - - if (comptime bun.Environment.isDebug) { - debugTreeShake("markPartLiveForTreeShaking({d}): {s}:{d} = {d}, {s}", .{ - source_index, - c.parse_graph.input_files.get(source_index).source.path.pretty, - part_index, - if (part.stmts.len > 0) part.stmts[0].loc.start else Logger.Loc.Empty.start, - if (part.stmts.len > 0) @tagName(part.stmts[0].data) else @tagName(Stmt.empty().data), - }); - } - - defer if (Environment.allow_assert) { - debugTreeShake("end()", .{}); - }; - - // Include the file containing this part - c.markFileLiveForTreeShaking( - source_index, - side_effects, - parts, - import_records, - entry_point_kinds, - css_reprs, - ); - - if (Environment.enable_logs and part.dependencies.slice().len == 0) { - logPartDependencyTree("markPartLiveForTreeShaking {d}:{d} | EMPTY", .{ - source_index, part_index, - }); - } - - for (part.dependencies.slice()) |dependency| { - if (Environment.enable_logs and source_index != 0 and dependency.source_index.get() != 0) { - logPartDependencyTree("markPartLiveForTreeShaking: {d}:{d} --> {d}:{d}\n", .{ - source_index, part_index, dependency.source_index.get(), dependency.part_index, - }); - } - - c.markPartLiveForTreeShaking( - dependency.part_index, - dependency.source_index.get(), - side_effects, - parts, - import_records, - entry_point_kinds, - css_reprs, - ); - } - } - - pub fn matchImportWithExport( - c: *LinkerContext, - init_tracker: ImportTracker, - re_exports: *std.array_list.Managed(js_ast.Dependency), - ) MatchImport { - const cycle_detector_top = c.cycle_detector.items.len; - defer c.cycle_detector.shrinkRetainingCapacity(cycle_detector_top); - - var tracker = init_tracker; - var ambiguous_results = std.array_list.Managed(MatchImport).init(c.allocator()); - defer ambiguous_results.clearAndFree(); - - var result: MatchImport = MatchImport{}; - const named_imports = c.graph.ast.items(.named_imports); - - loop: while (true) { - // Make sure we avoid infinite loops trying to resolve cycles: - // - // // foo.js - // export {a as b} from './foo.js' - // export {b as c} from './foo.js' - // export {c as a} from './foo.js' - // - // This uses a O(n^2) array scan instead of a O(n) map because the vast - // majority of cases have one or two elements - for (c.cycle_detector.items[cycle_detector_top..]) |prev_tracker| { - if (std.meta.eql(tracker, prev_tracker)) { - result = .{ .kind = .cycle }; - break :loop; - } - } - - if (tracker.source_index.isInvalid()) { - // External - break; - } - - const prev_source_index = tracker.source_index.get(); - bun.handleOom(c.cycle_detector.append(tracker)); - - // Resolve the import by one step - const advanced = c.advanceImportTracker(&tracker); - const next_tracker = advanced.value; - const status = advanced.status; - const potentially_ambiguous_export_star_refs = advanced.import_data; - - switch (status) { - .cjs, .cjs_without_exports, .disabled, .external => { - if (status == .external and c.options.output_format.keepES6ImportExportSyntax()) { - // Imports from external modules should not be converted to CommonJS - // if the output format preserves the original ES6 import statements - break; - } - - // If it's a CommonJS or external file, rewrite the import to a - // property access. Don't do this if the namespace reference is invalid - // though. This is the case for star imports, where the import is the - // namespace. - const named_import: js_ast.NamedImport = named_imports[prev_source_index].get(tracker.import_ref).?; - - if (named_import.namespace_ref != null and named_import.namespace_ref.?.isValid()) { - if (result.kind == .normal) { - result.kind = .normal_and_namespace; - result.namespace_ref = named_import.namespace_ref.?; - result.alias = named_import.alias.?; - } else { - result = .{ - .kind = .namespace, - .namespace_ref = named_import.namespace_ref.?, - .alias = named_import.alias.?, - }; - } - } - - // Warn about importing from a file that is known to not have any exports - if (status == .cjs_without_exports) { - const source = c.getSource(tracker.source_index.get()); - c.log.addRangeWarningFmt( - source, - source.rangeOfIdentifier(named_import.alias_loc.?), - c.allocator(), - "Import \"{s}\" will always be undefined because the file \"{s}\" has no exports", - .{ - named_import.alias.?, - source.path.pretty, - }, - ) catch unreachable; - } - }, - - .dynamic_fallback_interop_default => { - // if the file was rewritten from CommonJS into ESM - // and the developer imported an export that doesn't exist - // We don't do a runtime error since that CJS would have returned undefined. - const named_import: js_ast.NamedImport = named_imports[prev_source_index].get(tracker.import_ref).?; - - if (named_import.namespace_ref != null and named_import.namespace_ref.?.isValid()) { - const symbol = c.graph.symbols.get(tracker.import_ref).?; - symbol.import_item_status = .missing; - result.kind = .normal_and_namespace; - result.namespace_ref = tracker.import_ref; - result.alias = named_import.alias.?; - result.name_loc = named_import.alias_loc orelse Logger.Loc.Empty; - } - }, - - .dynamic_fallback => { - // If it's a file with dynamic export fallback, rewrite the import to a property access - const named_import: js_ast.NamedImport = named_imports[prev_source_index].get(tracker.import_ref).?; - if (named_import.namespace_ref != null and named_import.namespace_ref.?.isValid()) { - if (result.kind == .normal) { - result.kind = .normal_and_namespace; - result.namespace_ref = next_tracker.import_ref; - result.alias = named_import.alias.?; - } else { - result = .{ - .kind = .namespace, - .namespace_ref = next_tracker.import_ref, - .alias = named_import.alias.?, - }; - } - } - }, - .no_match => { - // Report mismatched imports and exports - const symbol = c.graph.symbols.get(tracker.import_ref).?; - const named_import: js_ast.NamedImport = named_imports[prev_source_index].get(tracker.import_ref).?; - const source = c.getSource(prev_source_index); - - const next_source = c.getSource(next_tracker.source_index.get()); - const r = source.rangeOfIdentifier(named_import.alias_loc.?); - - // Report mismatched imports and exports - if (symbol.import_item_status == .generated) { - // This is a debug message instead of an error because although it - // appears to be a named import, it's actually an automatically- - // generated named import that was originally a property access on an - // import star namespace object. Normally this property access would - // just resolve to undefined at run-time instead of failing at binding- - // time, so we emit a debug message and rewrite the value to the literal - // "undefined" instead of emitting an error. - symbol.import_item_status = .missing; - - if (c.resolver.opts.target == .browser and jsc.ModuleLoader.HardcodedModule.Alias.has(next_source.path.pretty, .bun, .{})) { - c.log.addRangeWarningFmtWithNote( - source, - r, - c.allocator(), - "Browser polyfill for module \"{s}\" doesn't have a matching export named \"{s}\"", - .{ - next_source.path.pretty, - named_import.alias.?, - }, - "Bun's bundler defaults to browser builds instead of node or bun builds. If you want to use node or bun builds, you can set the target to \"node\" or \"bun\" in the transpiler options.", - .{}, - r, - ) catch unreachable; - } else { - c.log.addRangeWarningFmt( - source, - r, - c.allocator(), - "Import \"{s}\" will always be undefined because there is no matching export in \"{s}\"", - .{ - named_import.alias.?, - next_source.path.pretty, - }, - ) catch unreachable; - } - } else if (c.resolver.opts.target == .browser and bun.strings.hasPrefixComptime(next_source.path.text, NodeFallbackModules.import_path)) { - c.log.addRangeErrorFmtWithNote( - source, - r, - c.allocator(), - "Browser polyfill for module \"{s}\" doesn't have a matching export named \"{s}\"", - .{ - next_source.path.pretty, - named_import.alias.?, - }, - "Bun's bundler defaults to browser builds instead of node or bun builds. If you want to use node or bun builds, you can set the target to \"node\" or \"bun\" in the transpiler options.", - .{}, - r, - ) catch unreachable; - } else { - c.log.addRangeErrorFmt( - source, - r, - c.allocator(), - "No matching export in \"{s}\" for import \"{s}\"", - .{ - next_source.path.pretty, - named_import.alias.?, - }, - ) catch unreachable; - } - }, - .probably_typescript_type => { - // Omit this import from any namespace export code we generate for - // import star statements (i.e. "import * as ns from 'path'") - result = .{ .kind = .probably_typescript_type }; - }, - .found => { - - // If there are multiple ambiguous results due to use of "export * from" - // statements, trace them all to see if they point to different things. - for (potentially_ambiguous_export_star_refs) |*ambiguous_tracker| { - // If this is a re-export of another import, follow the import - if (named_imports[ambiguous_tracker.data.source_index.get()].contains(ambiguous_tracker.data.import_ref)) { - const ambig = c.matchImportWithExport(ambiguous_tracker.data, re_exports); - ambiguous_results.append(ambig) catch unreachable; - } else { - ambiguous_results.append(.{ - .kind = .normal, - .source_index = ambiguous_tracker.data.source_index.get(), - .ref = ambiguous_tracker.data.import_ref, - .name_loc = ambiguous_tracker.data.name_loc, - }) catch unreachable; - } - } - - // Defer the actual binding of this import until after we generate - // namespace export code for all files. This has to be done for all - // import-to-export matches, not just the initial import to the final - // export, since all imports and re-exports must be merged together - // for correctness. - result = .{ - .kind = .normal, - .source_index = next_tracker.source_index.get(), - .ref = next_tracker.import_ref, - .name_loc = next_tracker.name_loc, - }; - - // Depend on the statement(s) that declared this import symbol in the - // original file - { - const deps = c.topLevelSymbolsToParts(prev_source_index, tracker.import_ref); - re_exports.ensureUnusedCapacity(deps.len) catch unreachable; - for (deps) |dep| { - re_exports.appendAssumeCapacity( - .{ - .part_index = dep, - .source_index = tracker.source_index, - }, - ); - } - } - - // If this is a re-export of another import, continue for another - // iteration of the loop to resolve that import as well - const next_id = next_tracker.source_index.get(); - if (named_imports[next_id].contains(next_tracker.import_ref)) { - tracker = next_tracker; - continue :loop; - } - }, - } - - break :loop; - } - - // If there is a potential ambiguity, all results must be the same - for (ambiguous_results.items) |ambig| { - if (!std.meta.eql(ambig, result)) { - if (result.kind == ambig.kind and - ambig.kind == .normal and - ambig.name_loc.start != 0 and - result.name_loc.start != 0) - { - return .{ - .kind = .ambiguous, - .source_index = result.source_index, - .name_loc = result.name_loc, - .other_source_index = ambig.source_index, - .other_name_loc = ambig.name_loc, - }; - } - - return .{ .kind = .ambiguous }; - } - } - - return result; - } - - pub fn topLevelSymbolsToParts(c: *LinkerContext, id: u32, ref: Ref) []u32 { - return c.graph.topLevelSymbolToParts(id, ref); - } - - pub fn topLevelSymbolsToPartsForRuntime(c: *LinkerContext, ref: Ref) []u32 { - return topLevelSymbolsToParts(c, Index.runtime.get(), ref); - } - - pub fn createWrapperForFile( - c: *LinkerContext, - wrap: WrapKind, - wrapper_ref: Ref, - wrapper_part_index: *Index, - source_index: Index.Int, - ) void { - switch (wrap) { - // If this is a CommonJS file, we're going to need to generate a wrapper - // for the CommonJS closure. That will end up looking something like this: - // - // var require_foo = __commonJS((exports, module) => { - // ... - // }); - // - // However, that generation is special-cased for various reasons and is - // done later on. Still, we're going to need to ensure that this file - // both depends on the "__commonJS" symbol and declares the "require_foo" - // symbol. Instead of special-casing this during the reachability analysis - // below, we just append a dummy part to the end of the file with these - // dependencies and let the general-purpose reachability analysis take care - // of it. - .cjs => { - const common_js_parts = c.topLevelSymbolsToPartsForRuntime(c.cjs_runtime_ref); - - for (common_js_parts) |part_id| { - const runtime_parts = c.graph.ast.items(.parts)[Index.runtime.get()].slice(); - const part: *Part = &runtime_parts[part_id]; - const symbol_refs = part.symbol_uses.keys(); - for (symbol_refs) |ref| { - if (ref.eql(c.cjs_runtime_ref)) continue; - } - } - - // Generate a dummy part that depends on the "__commonJS" symbol. - const dependencies: []js_ast.Dependency = if (c.options.output_format != .internal_bake_dev) brk: { - const dependencies = bun.handleOom(c.allocator().alloc(js_ast.Dependency, common_js_parts.len)); - for (common_js_parts, dependencies) |part, *cjs| { - cjs.* = .{ - .part_index = part, - .source_index = Index.runtime, - }; - } - break :brk dependencies; - } else &.{}; - var symbol_uses: Part.SymbolUseMap = .empty; - bun.handleOom(symbol_uses.put(c.allocator(), wrapper_ref, .{ .count_estimate = 1 })); - const part_index = c.graph.addPartToFile( - source_index, - .{ - .stmts = &.{}, - .symbol_uses = symbol_uses, - .declared_symbols = js_ast.DeclaredSymbol.List.fromSlice( - c.allocator(), - &[_]js_ast.DeclaredSymbol{ - .{ .ref = c.graph.ast.items(.exports_ref)[source_index], .is_top_level = true }, - .{ .ref = c.graph.ast.items(.module_ref)[source_index], .is_top_level = true }, - .{ .ref = c.graph.ast.items(.wrapper_ref)[source_index], .is_top_level = true }, - }, - ) catch unreachable, - .dependencies = Dependency.List.fromOwnedSlice(dependencies), - }, - ) catch unreachable; - bun.assert(part_index != js_ast.namespace_export_part_index); - wrapper_part_index.* = Index.part(part_index); - - // Bake uses a wrapping approach that does not use __commonJS - if (c.options.output_format != .internal_bake_dev) { - c.graph.generateSymbolImportAndUse( - source_index, - part_index, - c.cjs_runtime_ref, - 1, - Index.runtime, - ) catch unreachable; - } - }, - - .esm => { - // If this is a lazily-initialized ESM file, we're going to need to - // generate a wrapper for the ESM closure. That will end up looking - // something like this: - // - // var init_foo = __esm(() => { - // ... - // }); - // - // This depends on the "__esm" symbol and declares the "init_foo" symbol - // for similar reasons to the CommonJS closure above. - - // Count async dependencies to determine if we need __promiseAll - var async_import_count: usize = 0; - const import_records = c.graph.ast.items(.import_records)[source_index].slice(); - const meta_flags = c.graph.meta.items(.flags); - - for (import_records) |record| { - if (!record.source_index.isValid()) { - continue; - } - const other_flags = meta_flags[record.source_index.get()]; - if (other_flags.is_async_or_has_async_dependency) { - async_import_count += 1; - if (async_import_count >= 2) { - break; - } - } - } - - const needs_promise_all = async_import_count >= 2; - - const esm_parts = if (wrapper_ref.isValid() and c.options.output_format != .internal_bake_dev) - c.topLevelSymbolsToPartsForRuntime(c.esm_runtime_ref) - else - &.{}; - - const promise_all_parts = if (needs_promise_all and wrapper_ref.isValid() and c.options.output_format != .internal_bake_dev) - c.topLevelSymbolsToPartsForRuntime(c.promise_all_runtime_ref) - else - &.{}; - - // generate a dummy part that depends on the "__esm" and optionally "__promiseAll" symbols - const dependencies = c.allocator().alloc(js_ast.Dependency, esm_parts.len + promise_all_parts.len) catch unreachable; - var dep_index: usize = 0; - for (esm_parts) |part| { - dependencies[dep_index] = .{ - .part_index = part, - .source_index = Index.runtime, - }; - dep_index += 1; - } - for (promise_all_parts) |part| { - dependencies[dep_index] = .{ - .part_index = part, - .source_index = Index.runtime, - }; - dep_index += 1; - } - - var symbol_uses: Part.SymbolUseMap = .empty; - bun.handleOom(symbol_uses.put(c.allocator(), wrapper_ref, .{ .count_estimate = 1 })); - const part_index = c.graph.addPartToFile( - source_index, - .{ - .symbol_uses = symbol_uses, - .declared_symbols = js_ast.DeclaredSymbol.List.fromSlice(c.allocator(), &[_]js_ast.DeclaredSymbol{ - .{ .ref = wrapper_ref, .is_top_level = true }, - }) catch unreachable, - .dependencies = Dependency.List.fromOwnedSlice(dependencies), - }, - ) catch unreachable; - bun.assert(part_index != js_ast.namespace_export_part_index); - wrapper_part_index.* = Index.part(part_index); - if (wrapper_ref.isValid() and c.options.output_format != .internal_bake_dev) { - c.graph.generateSymbolImportAndUse( - source_index, - part_index, - c.esm_runtime_ref, - 1, - Index.runtime, - ) catch |err| bun.handleOom(err); - - // Only mark __promiseAll as used if we have multiple async dependencies - if (needs_promise_all) { - c.graph.generateSymbolImportAndUse( - source_index, - part_index, - c.promise_all_runtime_ref, - 1, - Index.runtime, - ) catch |err| bun.handleOom(err); - } - } - }, - else => {}, - } - } - - pub fn advanceImportTracker(c: *LinkerContext, tracker: *const ImportTracker) ImportTracker.Iterator { - const id = tracker.source_index.get(); - var named_imports: *JSAst.NamedImports = &c.graph.ast.items(.named_imports)[id]; - var import_records = c.graph.ast.items(.import_records)[id]; - const exports_kind: []const js_ast.ExportsKind = c.graph.ast.items(.exports_kind); - const ast_flags = c.graph.ast.items(.flags); - - const named_import: js_ast.NamedImport = named_imports.get(tracker.import_ref) orelse - // TODO: investigate if this is a bug - // It implies there are imports being added without being resolved - return .{ - .value = .{}, - .status = .external, - }; - - // Is this an external file? - const record: *const ImportRecord = import_records.at(named_import.import_record_index); - if (!record.source_index.isValid()) { - return .{ - .value = .{}, - .status = .external, - }; - } - - // Barrel optimization: deferred import records point to empty ASTs - if (record.flags.is_unused) { - return .{ - .value = .{}, - .status = .external, - }; - } - - // Is this a disabled file? - const other_source_index = record.source_index.get(); - const other_id = other_source_index; - - if (other_id > c.graph.ast.len or c.parse_graph.input_files.items(.source)[other_source_index].path.is_disabled) { - return .{ - .value = .{ - .source_index = record.source_index, - }, - .status = .disabled, - }; - } - - const flags = ast_flags[other_id]; - - // Is this a named import of a file without any exports? - if (!named_import.alias_is_star and - flags.has_lazy_export and - - // ESM exports - !flags.uses_export_keyword and !strings.eqlComptime(named_import.alias orelse "", "default") and - // CommonJS exports - !flags.uses_exports_ref and !flags.uses_module_ref) - { - // Just warn about it and replace the import with "undefined" - return .{ - .value = .{ - .source_index = Index.source(other_source_index), - .import_ref = Ref.None, - }, - .status = .cjs_without_exports, - }; - } - const other_kind = exports_kind[other_id]; - // Is this a CommonJS file? - if (other_kind == .cjs) { - return .{ - .value = .{ - .source_index = Index.source(other_source_index), - .import_ref = Ref.None, - }, - .status = .cjs, - }; - } - - // Match this import star with an export star from the imported file - if (named_import.alias_is_star) { - const matching_export = c.graph.meta.items(.resolved_export_star)[other_id]; - if (matching_export.data.import_ref.isValid()) { - // Check to see if this is a re-export of another import - return .{ - .value = matching_export.data, - .status = .found, - .import_data = matching_export.potentially_ambiguous_export_star_refs.slice(), - }; - } - } - - // Match this import up with an export from the imported file - if (c.graph.meta.items(.resolved_exports)[other_id].get(named_import.alias.?)) |matching_export| { - // Check to see if this is a re-export of another import - return .{ - .value = .{ - .source_index = matching_export.data.source_index, - .import_ref = matching_export.data.import_ref, - .name_loc = matching_export.data.name_loc, - }, - .status = .found, - .import_data = matching_export.potentially_ambiguous_export_star_refs.slice(), - }; - } - - // Is this a file with dynamic exports? - const is_commonjs_to_esm = flags.force_cjs_to_esm; - if (other_kind.isESMWithDynamicFallback() or is_commonjs_to_esm) { - return .{ - .value = .{ - .source_index = Index.source(other_source_index), - .import_ref = c.graph.ast.items(.exports_ref)[other_id], - }, - .status = if (is_commonjs_to_esm) - .dynamic_fallback_interop_default - else - .dynamic_fallback, - }; - } - - // Missing re-exports in TypeScript files are indistinguishable from types - const other_loader = c.parse_graph.input_files.items(.loader)[other_id]; - if (named_import.is_exported and other_loader.isTypeScript()) { - return .{ - .value = .{}, - .status = .probably_typescript_type, - }; - } - - return .{ - .value = .{ - .source_index = Index.source(other_source_index), - }, - .status = .no_match, - }; - } - - pub fn matchImportsWithExportsForFile( - c: *LinkerContext, - named_imports_ptr: *JSAst.NamedImports, - imports_to_bind: *RefImportData, - source_index: Index.Int, - ) void { - var named_imports = bun.handleOom(named_imports_ptr.clone(c.allocator())); - defer named_imports_ptr.* = named_imports; - - const Sorter = struct { - imports: *JSAst.NamedImports, - - pub fn lessThan(self: @This(), a_index: usize, b_index: usize) bool { - const a_ref = self.imports.keys()[a_index]; - const b_ref = self.imports.keys()[b_index]; - - return std.math.order(a_ref.innerIndex(), b_ref.innerIndex()) == .lt; - } - }; - const sorter = Sorter{ - .imports = &named_imports, - }; - named_imports.sort(sorter); - - for (named_imports.keys(), named_imports.values()) |ref, named_import| { - // Re-use memory for the cycle detector - c.cycle_detector.clearRetainingCapacity(); - - const import_ref = ref; - - var re_exports = std.array_list.Managed(js_ast.Dependency).init(c.allocator()); - const result = c.matchImportWithExport(.{ - .source_index = Index.source(source_index), - .import_ref = import_ref, - }, &re_exports); - - switch (result.kind) { - .normal => { - imports_to_bind.put( - c.allocator(), - import_ref, - .{ - .re_exports = bun.BabyList(js_ast.Dependency).fromOwnedSlice(re_exports.items), - .data = .{ - .source_index = Index.source(result.source_index), - .import_ref = result.ref, - }, - }, - ) catch unreachable; - }, - .namespace => { - c.graph.symbols.get(import_ref).?.namespace_alias = js_ast.G.NamespaceAlias{ - .namespace_ref = result.namespace_ref, - .alias = result.alias, - }; - }, - .normal_and_namespace => { - imports_to_bind.put( - c.allocator(), - import_ref, - .{ - .re_exports = bun.BabyList(js_ast.Dependency).fromOwnedSlice(re_exports.items), - .data = .{ - .source_index = Index.source(result.source_index), - .import_ref = result.ref, - }, - }, - ) catch unreachable; - - c.graph.symbols.get(import_ref).?.namespace_alias = js_ast.G.NamespaceAlias{ - .namespace_ref = result.namespace_ref, - .alias = result.alias, - }; - }, - .cycle => { - const source = &c.parse_graph.input_files.items(.source)[source_index]; - const r = lex.rangeOfIdentifier(source, named_import.alias_loc orelse Logger.Loc{}); - c.log.addRangeErrorFmt( - source, - r, - c.allocator(), - "Detected cycle while resolving import \"{s}\"", - .{ - named_import.alias.?, - }, - ) catch unreachable; - }, - .probably_typescript_type => { - c.graph.meta.items(.probably_typescript_type)[source_index].put( - c.allocator(), - import_ref, - {}, - ) catch unreachable; - }, - .ambiguous => { - const source = &c.parse_graph.input_files.items(.source)[source_index]; - - const r = lex.rangeOfIdentifier(source, named_import.alias_loc orelse Logger.Loc{}); - - // TODO: log locations of the ambiguous exports - - const symbol: *Symbol = c.graph.symbols.get(import_ref).?; - if (symbol.import_item_status == .generated) { - symbol.import_item_status = .missing; - c.log.addRangeWarningFmt( - source, - r, - c.allocator(), - "Import \"{s}\" will always be undefined because there are multiple matching exports", - .{ - named_import.alias.?, - }, - ) catch unreachable; - } else { - c.log.addRangeErrorFmt( - source, - r, - c.allocator(), - "Ambiguous import \"{s}\" has multiple matching exports", - .{ - named_import.alias.?, - }, - ) catch unreachable; - } - }, - .ignore => {}, - } - } - } - - pub fn breakOutputIntoPieces( - c: *LinkerContext, - alloc: std.mem.Allocator, - j: *StringJoiner, - count: u32, - ) !Chunk.IntermediateOutput { - const trace = bun.perf.trace("Bundler.breakOutputIntoPieces"); - defer trace.end(); - - const OutputPiece = Chunk.OutputPiece; - - if (!j.contains(c.unique_key_prefix)) - // There are like several cases that prohibit this from being checked more trivially, example: - // 1. dynamic imports - // 2. require() - // 3. require.resolve() - // 4. externals - return .{ .joiner = j.* }; - - var pieces = brk: { - errdefer j.deinit(); - break :brk try std.array_list.Managed(OutputPiece).initCapacity(alloc, count); - }; - errdefer pieces.deinit(); - const complete_output = try j.done(alloc); - var output = complete_output; - - const prefix = c.unique_key_prefix; - - outer: while (true) { - // Scan for the next piece boundary - const boundary = strings.indexOf(output, prefix) orelse - break; - - // Try to parse the piece boundary - const start = boundary + prefix.len; - if (start + 9 > output.len) { - // Not enough bytes to parse the piece index - break; - } - - const kind: OutputPiece.Query.Kind = switch (output[start]) { - 'A' => .asset, - 'C' => .chunk, - 'S' => .scb, - 'H' => .html_import, - else => { - if (bun.Environment.isDebug) - bun.Output.debugWarn("Invalid output piece boundary", .{}); - break; - }, - }; - - var index: usize = 0; - for (output[start..][1..9].*) |char| { - if (char < '0' or char > '9') { - if (bun.Environment.isDebug) - bun.Output.debugWarn("Invalid output piece boundary", .{}); - break :outer; - } - - index = (index * 10) + (@as(usize, char) - '0'); - } - - // Validate the boundary - switch (kind) { - .asset, .scb => if (index >= c.graph.files.len) { - if (bun.Environment.isDebug) - bun.Output.debugWarn("Invalid output piece boundary", .{}); - break; - }, - .chunk => if (index >= count) { - if (bun.Environment.isDebug) - bun.Output.debugWarn("Invalid output piece boundary", .{}); - break; - }, - .html_import => if (index >= c.parse_graph.html_imports.server_source_indices.len) { - if (bun.Environment.isDebug) - bun.Output.debugWarn("Invalid output piece boundary", .{}); - break; - }, - else => unreachable, - } - - try pieces.append(OutputPiece.init(output[0..boundary], .{ - .kind = kind, - .index = @intCast(index), - })); - output = output[boundary + prefix.len + 9 ..]; - } - - try pieces.append(OutputPiece.init(output, OutputPiece.Query.none)); - - return .{ - .pieces = bun.BabyList(Chunk.OutputPiece).fromOwnedSlice(pieces.items), - }; - } -}; - -pub const Ref = bun.ast.Ref; -pub const ThreadPoolLib = bun.ThreadPool; -pub const Fs = @import("../resolver/fs.zig"); - -pub const Index = bun.ast.Index; -const debugTreeShake = Output.scoped(.TreeShake, .hidden); - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const string = []const u8; - -const NodeFallbackModules = @import("../resolver/node_fallbacks.zig"); -const js_printer = @import("../js_printer/js_printer.zig"); -const lex = @import("../js_parser/lexer.zig"); -const linker = @import("./linker.zig"); -const runtime = @import("../js_parser/runtime.zig"); -const std = @import("std"); - -const Logger = @import("../logger/logger.zig"); -const Loc = Logger.Loc; - -const _resolver = @import("../resolver/resolver.zig"); -const Resolver = _resolver.Resolver; - -const options = @import("./options.zig"); -const Loader = options.Loader; - -const bun = @import("bun"); -const Environment = bun.Environment; -const FeatureFlags = bun.FeatureFlags; -const ImportRecord = bun.ImportRecord; -const MultiArrayList = bun.MultiArrayList; -const MutableString = bun.MutableString; -const OOM = bun.OOM; -const Output = bun.Output; -const SourceMap = bun.SourceMap; -const StringJoiner = bun.StringJoiner; -const bake = bun.bake; -const base64 = bun.base64; -const renamer = bun.renamer; -const strings = bun.strings; -const sync = bun.threading; -const AutoBitSet = bun.bit_set.AutoBitSet; -const BabyList = bun.collections.BabyList; - -const js_ast = bun.ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const Dependency = js_ast.Dependency; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const JSAst = js_ast.BundledAst; -const Part = js_ast.Part; -const S = js_ast.S; -const Stmt = js_ast.Stmt; -const Symbol = js_ast.Symbol; - -const bundler = bun.bundle_v2; -const AdditionalFile = bundler.AdditionalFile; -const BundleV2 = bundler.BundleV2; -const Chunk = bundler.Chunk; -const CompileResultForSourceMap = bundler.CompileResultForSourceMap; -const ContentHasher = bundler.ContentHasher; -const EntryPoint = bundler.EntryPoint; -const ExportData = bundler.ExportData; -const Graph = bundler.Graph; -const ImportTracker = bundler.ImportTracker; -const JSMeta = bundler.JSMeta; -const LinkerGraph = bundler.LinkerGraph; -const MangledProps = bundler.MangledProps; -const PartRange = bundler.PartRange; -const RefImportData = bundler.RefImportData; -const ServerComponentBoundary = bundler.ServerComponentBoundary; -const StableRef = bundler.StableRef; -const WrapKind = bundler.WrapKind; -const genericPathWithPrettyInitialized = bundler.genericPathWithPrettyInitialized; -const logPartDependencyTree = bundler.logPartDependencyTree; - -const jsc = bun.jsc; -const EventLoop = bun.jsc.AnyEventLoop; diff --git a/src/bundler/LinkerGraph.zig b/src/bundler/LinkerGraph.zig deleted file mode 100644 index a17efb5da37c..000000000000 --- a/src/bundler/LinkerGraph.zig +++ /dev/null @@ -1,563 +0,0 @@ -pub const LinkerGraph = @This(); - -const debug = Output.scoped(.LinkerGraph, .visible); - -files: File.List = .{}, -files_live: BitSet = undefined, -entry_points: EntryPoint.List = .{}, -symbols: js_ast.Symbol.Map = .{}, - -allocator: std.mem.Allocator, - -code_splitting: bool = false, - -// This is an alias from Graph -// it is not a clone! -ast: MultiArrayList(JSAst) = .{}, -meta: MultiArrayList(JSMeta) = .{}, - -/// We should avoid traversing all files in the bundle, because the linker -/// should be able to run a linking operation on a large bundle where only -/// a few files are needed (e.g. an incremental compilation scenario). This -/// holds all files that could possibly be reached through the entry points. -/// If you need to iterate over all files in the linking operation, iterate -/// over this array. This array is also sorted in a deterministic ordering -/// to help ensure deterministic builds (source indices are random). -reachable_files: []Index = &[_]Index{}, - -/// Index from `.parse_graph.input_files` to index in `.files` -stable_source_indices: []const u32 = &[_]u32{}, - -is_scb_bitset: BitSet = .{}, - -/// This is for cross-module inlining of detected inlinable constants -// const_values: js_ast.Ast.ConstValuesMap = .{}, -/// This is for cross-module inlining of TypeScript enum constants -ts_enums: js_ast.Ast.TsEnumsMap = .{}, - -pub fn init(allocator: std.mem.Allocator, file_count: usize) !LinkerGraph { - return LinkerGraph{ - .allocator = allocator, - .files_live = try BitSet.initEmpty(allocator, file_count), - }; -} - -pub fn runtimeFunction(this: *const LinkerGraph, name: string) Ref { - return this.ast.items(.named_exports)[Index.runtime.value].get(name).?.ref; -} - -pub fn generateNewSymbol(this: *LinkerGraph, source_index: u32, kind: Symbol.Kind, original_name: string) Ref { - const source_symbols = &this.symbols.symbols_for_source.slice()[source_index]; - - var ref = Ref.init( - @truncate(source_symbols.len), - @truncate(source_index), - false, - ); - ref.tag = .symbol; - - // TODO: will this crash on resize due to using threadlocal mimalloc heap? - source_symbols.append( - this.allocator, - .{ - .kind = kind, - .original_name = original_name, - }, - ) catch |err| bun.handleOom(err); - - this.ast.items(.module_scope)[source_index].generated.append(this.allocator, ref) catch |err| - bun.handleOom(err); - return ref; -} - -pub fn generateRuntimeSymbolImportAndUse( - graph: *LinkerGraph, - source_index: Index.Int, - entry_point_part_index: Index, - name: []const u8, - count: u32, -) bun.OOM!void { - if (count == 0) return; - debug("generateRuntimeSymbolImportAndUse({s}) for {d}", .{ name, source_index }); - - const ref = graph.runtimeFunction(name); - try graph.generateSymbolImportAndUse( - source_index, - entry_point_part_index.get(), - ref, - count, - Index.runtime, - ); -} - -pub fn addPartToFile( - graph: *LinkerGraph, - id: u32, - part: Part, -) bun.OOM!u32 { - var parts: *Part.List = &graph.ast.items(.parts)[id]; - const part_id = @as(u32, @truncate(parts.len)); - try parts.append(graph.allocator, part); - var top_level_symbol_to_parts_overlay: ?*TopLevelSymbolToParts = null; - - const Iterator = struct { - graph: *LinkerGraph, - id: u32, - top_level_symbol_to_parts_overlay: *?*TopLevelSymbolToParts, - part_id: u32, - - pub fn next(self: *@This(), ref: Ref) void { - var overlay = brk: { - if (self.top_level_symbol_to_parts_overlay.*) |out| { - break :brk out; - } - - const out = &self.graph.meta.items(.top_level_symbol_to_parts_overlay)[self.id]; - - self.top_level_symbol_to_parts_overlay.* = out; - break :brk out; - }; - - var entry = overlay.getOrPut(self.graph.allocator, ref) catch unreachable; - if (!entry.found_existing) { - if (self.graph.ast.items(.top_level_symbols_to_parts)[self.id].get(ref)) |original_parts| { - var list = std.array_list.Managed(u32).init(self.graph.allocator); - list.ensureTotalCapacityPrecise(original_parts.len + 1) catch unreachable; - list.appendSliceAssumeCapacity(original_parts.slice()); - list.appendAssumeCapacity(self.part_id); - - entry.value_ptr.* = .fromOwnedSlice(list.items); - } else { - entry.value_ptr.* = BabyList(u32).fromSlice(self.graph.allocator, &.{self.part_id}) catch |err| bun.handleOom(err); - } - } else { - bun.handleOom(entry.value_ptr.append(self.graph.allocator, self.part_id)); - } - } - }; - - var ctx = Iterator{ - .graph = graph, - .id = id, - .part_id = part_id, - .top_level_symbol_to_parts_overlay = &top_level_symbol_to_parts_overlay, - }; - - js_ast.DeclaredSymbol.forEachTopLevelSymbol(&parts.mut(part_id).declared_symbols, &ctx, Iterator.next); - - return part_id; -} - -pub fn generateSymbolImportAndUse( - g: *LinkerGraph, - source_index: u32, - part_index: u32, - ref: Ref, - use_count: u32, - source_index_to_import_from: Index, -) bun.OOM!void { - if (use_count == 0) return; - - var parts_list = g.ast.items(.parts)[source_index].slice(); - var part: *Part = &parts_list[part_index]; - - // Mark this symbol as used by this part - - var uses = &part.symbol_uses; - var uses_entry = try uses.getOrPut(g.allocator, ref); - - if (!uses_entry.found_existing) { - uses_entry.value_ptr.* = .{ .count_estimate = use_count }; - } else { - uses_entry.value_ptr.count_estimate += use_count; - } - - const exports_ref = g.ast.items(.exports_ref)[source_index]; - const module_ref = g.ast.items(.module_ref)[source_index]; - if (!exports_ref.isNull() and ref.eql(exports_ref)) { - g.ast.items(.flags)[source_index].uses_exports_ref = true; - } - - if (!module_ref.isNull() and ref.eql(module_ref)) { - g.ast.items(.flags)[source_index].uses_module_ref = true; - } - - // null ref shouldn't be there. - bun.assert(!ref.isEmpty()); - - // Track that this specific symbol was imported - if (source_index_to_import_from.get() != source_index) { - const imports_to_bind = &g.meta.items(.imports_to_bind)[source_index]; - try imports_to_bind.put(g.allocator, ref, .{ - .data = .{ - .source_index = source_index_to_import_from, - .import_ref = ref, - }, - }); - } - - // Pull in all parts that declare this symbol - var dependencies = &part.dependencies; - const part_ids = g.topLevelSymbolToParts(source_index_to_import_from.get(), ref); - const new_dependencies = try dependencies.writableSlice(g.allocator, part_ids.len); - for (part_ids, new_dependencies) |part_id, *dependency| { - dependency.* = .{ - .source_index = source_index_to_import_from, - .part_index = @as(u32, @truncate(part_id)), - }; - } -} - -pub fn topLevelSymbolToParts(g: *LinkerGraph, id: u32, ref: Ref) []u32 { - if (g.meta.items(.top_level_symbol_to_parts_overlay)[id].get(ref)) |overlay| { - return overlay.slice(); - } - - if (g.ast.items(.top_level_symbols_to_parts)[id].get(ref)) |list| { - return list.slice(); - } - - return &.{}; -} - -pub fn load( - this: *LinkerGraph, - entry_points: []const Index, - sources: []const Logger.Source, - server_component_boundaries: ServerComponentBoundary.List, - dynamic_import_entry_points: []const Index.Int, - entry_point_original_names: *const IndexStringMap, -) !void { - const scb = server_component_boundaries.slice(); - try this.files.setCapacity(this.allocator, sources.len); - this.files.zero(); - this.files_live = try BitSet.initEmpty( - this.allocator, - sources.len, - ); - this.files.len = sources.len; - var files = this.files.slice(); - - var entry_point_kinds = files.items(.entry_point_kind); - { - const kinds = std.mem.sliceAsBytes(entry_point_kinds); - @memset(kinds, 0); - } - - // Setup entry points - { - try this.entry_points.setCapacity(this.allocator, entry_points.len + server_component_boundaries.list.len + dynamic_import_entry_points.len); - this.entry_points.len = entry_points.len; - const source_indices = this.entry_points.items(.source_index); - - const path_strings: []bun.PathString = this.entry_points.items(.output_path); - { - const output_was_auto_generated = std.mem.sliceAsBytes(this.entry_points.items(.output_path_was_auto_generated)); - @memset(output_was_auto_generated, 0); - } - - for (entry_points, path_strings, source_indices) |i, *path_string, *source_index| { - const source = sources[i.get()]; - if (comptime Environment.allow_assert) { - bun.assert(source.index.get() == i.get()); - } - entry_point_kinds[source.index.get()] = EntryPoint.Kind.user_specified; - - // Check if this entry point has an original name (from virtual entry resolution) - if (entry_point_original_names.get(i.get())) |original_name| { - path_string.* = bun.PathString.init(original_name); - } else { - path_string.* = bun.PathString.init(source.path.text); - } - - source_index.* = source.index.get(); - } - - for (dynamic_import_entry_points) |id| { - bun.assert(this.code_splitting); // this should never be a thing without code splitting - - if (entry_point_kinds[id] != .none) { - // You could dynamic import a file that is already an entry point - continue; - } - - const source = &sources[id]; - entry_point_kinds[id] = EntryPoint.Kind.dynamic_import; - - this.entry_points.appendAssumeCapacity(.{ - .source_index = id, - .output_path = bun.PathString.init(source.path.text), - .output_path_was_auto_generated = true, - }); - } - - var import_records_list: []ImportRecord.List = this.ast.items(.import_records); - try this.meta.setCapacity(this.allocator, import_records_list.len); - this.meta.len = this.ast.len; - this.meta.zero(); - - if (scb.list.len > 0) { - this.is_scb_bitset = BitSet.initEmpty(this.allocator, this.files.len) catch unreachable; - - // Index all SCBs into the bitset. This is needed so chunking - // can track the chunks that SCBs belong to. - for (scb.list.items(.use_directive), scb.list.items(.source_index), scb.list.items(.reference_source_index)) |use, original_id, ref_id| { - switch (use) { - .none => {}, - .client => { - this.is_scb_bitset.set(original_id); - this.is_scb_bitset.set(ref_id); - }, - .server => { - bun.todoPanic(@src(), "um", .{}); - }, - } - } - - // For client components, the import record index currently points to the original source index, instead of the reference source index. - for (this.reachable_files) |source_id| { - for (import_records_list[source_id.get()].slice()) |*import_record| { - if (import_record.source_index.isValid() and this.is_scb_bitset.isSet(import_record.source_index.get())) { - // Only rewrite if this is an original SCB file, not a reference file - if (scb.getReferenceSourceIndex(import_record.source_index.get())) |ref_index| { - import_record.source_index = Index.init(ref_index); - bun.assert(import_record.source_index.isValid()); // did not generate - } - // If it's already a reference file, leave it as-is - } - } - } - } else { - this.is_scb_bitset = .{}; - } - } - - // Setup files - { - var stable_source_indices = try this.allocator.alloc(Index, sources.len + 1); - - // set it to max value so that if we access an invalid one, it crashes - @memset(std.mem.sliceAsBytes(stable_source_indices), 255); - - for (this.reachable_files, 0..) |source_index, i| { - stable_source_indices[source_index.get()] = Index.source(i); - } - - @memset( - files.items(.distance_from_entry_point), - (LinkerGraph.File{}).distance_from_entry_point, - ); - this.stable_source_indices = @as([]const u32, @ptrCast(stable_source_indices)); - } - - { - var input_symbols = js_ast.Symbol.Map.initList( - js_ast.Symbol.NestedList.fromBorrowedSliceDangerous(this.ast.items(.symbols)), - ); - var symbols = bun.handleOom(input_symbols.symbols_for_source.clone(this.allocator)); - for (symbols.slice(), input_symbols.symbols_for_source.slice()) |*dest, src| { - dest.* = bun.handleOom(src.clone(this.allocator)); - } - this.symbols = js_ast.Symbol.Map.initList(symbols); - } - - // TODO: const_values - // { - // var const_values = this.const_values; - // var count: usize = 0; - - // for (this.ast.items(.const_values)) |const_value| { - // count += const_value.count(); - // } - - // if (count > 0) { - // try const_values.ensureTotalCapacity(this.allocator, count); - // for (this.ast.items(.const_values)) |const_value| { - // for (const_value.keys(), const_value.values()) |key, value| { - // const_values.putAssumeCapacityNoClobber(key, value); - // } - // } - // } - - // this.const_values = const_values; - // } - - { - var count: usize = 0; - for (this.ast.items(.ts_enums)) |ts_enums| { - count += ts_enums.count(); - } - if (count > 0) { - try this.ts_enums.ensureTotalCapacity(this.allocator, count); - for (this.ast.items(.ts_enums)) |ts_enums| { - for (ts_enums.keys(), ts_enums.values()) |key, value| { - this.ts_enums.putAssumeCapacityNoClobber(key, value); - } - } - } - } - - const src_named_exports: []js_ast.Ast.NamedExports = this.ast.items(.named_exports); - const dest_resolved_exports: []ResolvedExports = this.meta.items(.resolved_exports); - for (src_named_exports, dest_resolved_exports, 0..) |src, *dest, source_index| { - var resolved = ResolvedExports{}; - resolved.ensureTotalCapacity(this.allocator, src.count()) catch unreachable; - for (src.keys(), src.values()) |key, value| { - resolved.putAssumeCapacityNoClobber(key, .{ .data = .{ - .import_ref = value.ref, - .name_loc = value.alias_loc, - .source_index = Index.source(source_index), - } }); - } - dest.* = resolved; - } -} - -/// Transfers ownership of the AST to the graph allocator. -/// This is valid only if all allocators are `MimallocArena`s. -pub fn takeAstOwnership(this: *LinkerGraph) void { - const ast = this.ast.slice(); - const heap: bun.allocators.MimallocArena.Borrowed = .downcast(this.allocator); - if (comptime !bun.collections.baby_list.safety_checks) return; - for (ast.items(.import_records)) |*import_records| { - import_records.transferOwnership(heap); - } - for (ast.items(.parts)) |*parts| { - parts.transferOwnership(heap); - for (parts.slice()) |*part| { - part.dependencies.transferOwnership(heap); - } - } - for (ast.items(.symbols)) |*symbols| { - symbols.transferOwnership(heap); - } -} - -pub const File = struct { - entry_bits: AutoBitSet = undefined, - - input_file: Index = Index.source(0), - - /// The minimum number of links in the module graph to get from an entry point - /// to this file - distance_from_entry_point: u32 = std.math.maxInt(u32), - - /// This file is an entry point if and only if this is not ".none". - /// Note that dynamically-imported files are allowed to also be specified by - /// the user as top-level entry points, so some dynamically-imported files - /// may be ".user_specified" instead of ".dynamic_import". - entry_point_kind: EntryPoint.Kind = .none, - - /// If "entry_point_kind" is not ".none", this is the index of the - /// corresponding entry point chunk. - /// - /// This is also initialized for files that are a SCB's generated - /// reference, pointing to its destination. This forms a lookup map from - /// a Source.Index to its output path inb reakOutputIntoPieces - entry_point_chunk_index: u32 = std.math.maxInt(u32), - - line_offset_table: bun.SourceMap.LineOffsetTable.List = .empty, - quoted_source_contents: Owned(?[]u8) = .initNull(), - - pub fn isEntryPoint(this: *const File) bool { - return this.entry_point_kind.isEntryPoint(); - } - - pub fn isUserSpecifiedEntryPoint(this: *const File) bool { - return this.entry_point_kind.isUserSpecifiedEntryPoint(); - } - - pub const List = MultiArrayList(File); -}; - -pub fn propagateAsyncDependencies(this: *LinkerGraph) !void { - const State = struct { - visited: bun.collections.AutoBitSet, - import_records: []const ImportRecord.List, - flags: []JSMeta.Flags, - - pub fn visitAll(self: *@This()) void { - for (0..self.import_records.len) |i| { - self.visit(i); - } - } - - fn visit(self: *@This(), index: usize) void { - if (self.visited.isSet(index)) return; - self.visited.set(index); - if (self.flags[index].is_async_or_has_async_dependency) return; - - for (self.import_records[index].sliceConst()) |*import_record| { - switch (import_record.kind) { - .stmt => {}, - - // Any use of `import()` that makes the parent async will necessarily use - // top-level await, so this will have already been detected by `validateTLA`, - // and `is_async_or_has_async_dependency` will already be true. - // - // We don't want to process these imports here because `import()` can appear in - // non-top-level contexts (like inside an async function) or in contexts that - // don't use `await`, which don't necessarily make the parent module async. - .dynamic => continue, - - // `require()` cannot import async modules. - .require, .require_resolve => continue, - - // Entry points; not imports from JS - .entry_point_run, .entry_point_build => continue, - // CSS imports - .at, .at_conditional, .url, .composes => continue, - // Other non-JS imports - .html_manifest, .internal => continue, - } - - const import_index: usize = import_record.source_index.get(); - if (import_index >= self.import_records.len) continue; - self.visit(import_index); - - if (self.flags[import_index].is_async_or_has_async_dependency) { - self.flags[index].is_async_or_has_async_dependency = true; - break; - } - } - } - }; - - var state: State = .{ - .visited = try .initEmpty(bun.default_allocator, this.ast.len), - .import_records = this.ast.items(.import_records), - .flags = this.meta.items(.flags), - }; - defer state.visited.deinit(bun.default_allocator); - state.visitAll(); -} - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const Environment = bun.Environment; -const ImportRecord = bun.ImportRecord; -const MultiArrayList = bun.MultiArrayList; -const Output = bun.Output; -const Owned = bun.ptr.Owned; - -const js_ast = bun.ast; -const Symbol = js_ast.Symbol; - -const AutoBitSet = bun.bit_set.AutoBitSet; -const BitSet = bun.bit_set.DynamicBitSetUnmanaged; - -const EntryPoint = bun.bundle_v2.EntryPoint; -const Index = bun.bundle_v2.Index; -const IndexStringMap = bun.bundle_v2.IndexStringMap; -const JSAst = bun.bundle_v2.JSAst; -const JSMeta = bun.bundle_v2.JSMeta; -const Logger = bun.bundle_v2.Logger; -const Part = bun.bundle_v2.Part; -const Ref = bun.bundle_v2.Ref; -const ResolvedExports = bun.bundle_v2.ResolvedExports; -const ServerComponentBoundary = bun.bundle_v2.ServerComponentBoundary; -const TopLevelSymbolToParts = bun.bundle_v2.TopLevelSymbolToParts; diff --git a/src/bundler/OutputFile.zig b/src/bundler/OutputFile.zig deleted file mode 100644 index 3d92eb1ed967..000000000000 --- a/src/bundler/OutputFile.zig +++ /dev/null @@ -1,336 +0,0 @@ -const OutputFile = @This(); - -// Instead of keeping files in-memory, we: -// 1. Write directly to disk -// 2. (Optional) move the file to the destination -// This saves us from allocating a buffer - -loader: Loader, -input_loader: Loader = .js, -src_path: Fs.Path, -value: Value, -size: usize = 0, -size_without_sourcemap: usize = 0, -hash: u64 = 0, -is_executable: bool = false, -source_map_index: u32 = std.math.maxInt(u32), -bytecode_index: u32 = std.math.maxInt(u32), -module_info_index: u32 = std.math.maxInt(u32), -output_kind: jsc.API.BuildArtifact.OutputKind, -/// Relative -dest_path: []const u8 = "", -side: ?bun.bake.Side, -/// This is only set for the JS bundle, and not files associated with an -/// entrypoint like sourcemaps and bytecode -entry_point_index: ?u32, -referenced_css_chunks: []const Index = &.{}, -source_index: Index.Optional = .none, -bake_extra: BakeExtra = .{}, - -pub const zero_value = OutputFile{ - .loader = .file, - .src_path = Fs.Path.init(""), - .value = .noop, - .output_kind = .chunk, - .side = null, - .entry_point_index = null, -}; - -pub const BakeExtra = struct { - is_route: bool = false, - fully_static: bool = false, - bake_is_runtime: bool = false, -}; - -pub const Index = bun.GenericIndex(u32, OutputFile); - -pub fn deinit(this: *OutputFile) void { - this.value.deinit(); - - bun.default_allocator.free(this.src_path.text); - bun.default_allocator.free(this.dest_path); - bun.default_allocator.free(this.referenced_css_chunks); -} - -// Depending on: -// - The target -// - The number of open file handles -// - Whether or not a file of the same name exists -// We may use a different system call -pub const FileOperation = struct { - pathname: string, - fd: FileDescriptorType = bun.invalid_fd, - dir: FileDescriptorType = bun.invalid_fd, - is_tmpdir: bool = false, - is_outdir: bool = false, - close_handle_on_complete: bool = false, - autowatch: bool = true, - - pub fn fromFile(fd: bun.FD, pathname: string) FileOperation { - return .{ - .fd = fd, - .pathname = pathname, - }; - } - - pub fn getPathname(file: *const FileOperation) string { - if (file.is_tmpdir) { - return resolve_path.joinAbs(Fs.FileSystem.RealFS.tmpdirPath(), .auto, file.pathname); - } else { - return file.pathname; - } - } -}; - -pub const Kind = enum { - move, - copy, - noop, - buffer, - pending, - saved, -}; - -// TODO: document how and why all variants of this union(enum) are used, -// specifically .move and .copy; the new bundler has to load files in memory -// in order to hash them, so i think it uses .buffer for those -pub const Value = union(Kind) { - move: FileOperation, - copy: FileOperation, - noop: u0, - buffer: struct { - allocator: std.mem.Allocator, - bytes: []const u8, - }, - pending: resolver.Result, - saved: SavedFile, - - pub fn deinit(this: *Value) void { - switch (this.*) { - .buffer => |buf| { - buf.allocator.free(buf.bytes); - }, - .saved => {}, - .move => {}, - .copy => {}, - .noop => {}, - .pending => {}, - } - } - - pub fn asSlice(v: Value) []const u8 { - return switch (v) { - .buffer => |buf| buf.bytes, - else => "", - }; - } - - pub fn toBunString(v: Value) bun.String { - return switch (v) { - .noop => bun.String.empty, - .buffer => |buf| { - // Use ExternalStringImpl to avoid cloning the string, at - // the cost of allocating space to remember the allocator. - const FreeContext = struct { - allocator: std.mem.Allocator, - - fn onFree(ctx: *@This(), buffer: *anyopaque, len: u32) callconv(.c) void { - ctx.allocator.free(@as([*]u8, @ptrCast(buffer))[0..len]); - bun.destroy(ctx); - } - }; - return bun.String.createExternal( - *FreeContext, - buf.bytes, - true, - bun.new(FreeContext, .{ .allocator = buf.allocator }), - FreeContext.onFree, - ); - }, - .pending => unreachable, - else => |tag| bun.todoPanic(@src(), "handle .{s}", .{@tagName(tag)}), - }; - } -}; - -pub const SavedFile = @import("../bundler_jsc/output_file_jsc.zig").SavedFile; - -pub fn initPending(loader: Loader, pending: resolver.Result) OutputFile { - return .{ - .loader = loader, - .src_path = pending.pathConst().?.*, - .size = 0, - .value = .{ .pending = pending }, - }; -} - -pub fn initFile(file: std.fs.File, pathname: string, size: usize) OutputFile { - return .{ - .loader = .file, - .src_path = Fs.Path.init(pathname), - .size = size, - .value = .{ .copy = FileOperation.fromFile(file.handle, pathname) }, - }; -} - -pub fn initFileWithDir(file: std.fs.File, pathname: string, size: usize, dir: std.fs.Dir) OutputFile { - var res = initFile(file, pathname, size); - res.value.copy.dir_handle = .fromStdDir(dir); - return res; -} - -pub const Options = struct { - loader: Loader, - input_loader: Loader, - hash: ?u64 = null, - source_map_index: ?u32 = null, - bytecode_index: ?u32 = null, - module_info_index: ?u32 = null, - output_path: string, - source_index: Index.Optional = .none, - size: ?usize = null, - input_path: []const u8 = "", - display_size: u32 = 0, - output_kind: jsc.API.BuildArtifact.OutputKind, - is_executable: bool, - data: union(enum) { - buffer: struct { - allocator: std.mem.Allocator, - data: []const u8, - }, - file: struct { - file: std.fs.File, - size: usize, - dir: std.fs.Dir, - }, - saved: usize, - }, - side: ?bun.bake.Side, - entry_point_index: ?u32, - referenced_css_chunks: []const Index = &.{}, - bake_extra: BakeExtra = .{}, -}; - -pub fn init(options: Options) OutputFile { - return .{ - .loader = options.loader, - .input_loader = options.input_loader, - .src_path = Fs.Path.init(options.input_path), - .dest_path = options.output_path, - .source_index = options.source_index, - .size = options.size orelse switch (options.data) { - .buffer => |buf| buf.data.len, - .file => |file| file.size, - .saved => 0, - }, - .size_without_sourcemap = options.display_size, - .hash = options.hash orelse 0, - .output_kind = options.output_kind, - .bytecode_index = options.bytecode_index orelse std.math.maxInt(u32), - .module_info_index = options.module_info_index orelse std.math.maxInt(u32), - .source_map_index = options.source_map_index orelse std.math.maxInt(u32), - .is_executable = options.is_executable, - .value = switch (options.data) { - .buffer => |buffer| Value{ .buffer = .{ .allocator = buffer.allocator, .bytes = buffer.data } }, - .file => |file| Value{ - .copy = brk: { - var op = FileOperation.fromFile(.fromStdFile(file.file), options.output_path); - op.dir = .fromStdDir(file.dir); - break :brk op; - }, - }, - .saved => Value{ .saved = .{} }, - }, - .side = options.side, - .entry_point_index = options.entry_point_index, - .referenced_css_chunks = options.referenced_css_chunks, - .bake_extra = options.bake_extra, - }; -} - -pub fn writeToDisk(f: OutputFile, root_dir: std.fs.Dir, root_dir_path: []const u8) !void { - switch (f.value) { - .noop => {}, - .saved => { - // already written to disk - }, - .buffer => |value| { - var rel_path = f.dest_path; - if (f.dest_path.len > root_dir_path.len) { - rel_path = resolve_path.relative(root_dir_path, f.dest_path); - if (std.fs.path.dirname(rel_path)) |parent| { - if (parent.len > root_dir_path.len) { - try root_dir.makePath(parent); - } - } - } - - var path_buf: bun.PathBuffer = undefined; - _ = try jsc.Node.fs.NodeFS.writeFileWithPathBuffer(&path_buf, .{ - .data = .{ .buffer = .{ - .buffer = .{ - .ptr = @constCast(value.bytes.ptr), - .len = value.bytes.len, - .byte_len = value.bytes.len, - }, - } }, - .encoding = .buffer, - .mode = if (f.is_executable) 0o755 else 0o644, - .dirfd = .fromStdDir(root_dir), - .file = .{ .path = .{ - .string = bun.PathString.init(rel_path), - } }, - }).unwrap(); - }, - .move => |value| { - try f.moveTo(root_dir_path, value.pathname, .fromStdDir(root_dir)); - }, - .copy => |value| { - try f.copyTo(root_dir_path, value.pathname, .fromStdDir(root_dir)); - }, - .pending => unreachable, - } -} - -pub fn moveTo(file: *const OutputFile, _: string, rel_path: []const u8, dir: FileDescriptorType) !void { - try bun.sys.moveFileZ(file.value.move.dir, bun.sliceTo(&(try std.posix.toPosixPath(file.value.move.getPathname())), 0), dir, bun.sliceTo(&(try std.posix.toPosixPath(rel_path)), 0)); -} - -pub fn copyTo(file: *const OutputFile, _: string, rel_path: []const u8, dir: FileDescriptorType) !void { - const fd_out = bun.FD.fromStdFile(try dir.stdDir().createFile(rel_path, .{})); - var do_close = false; - const fd_in = bun.FD.fromStdFile(try std.fs.cwd().openFile(file.src_path.text, .{ .mode = .read_only })); - - if (Environment.isWindows) { - do_close = Fs.FileSystem.instance.fs.needToCloseFiles(); - - // use paths instead of bun.getFdPathW() - @panic("TODO windows"); - } - - defer { - if (do_close) { - fd_out.close(); - fd_in.close(); - } - } - - try bun.copyFile(fd_in, fd_out).unwrap(); -} - -pub const toJS = @import("../bundler_jsc/output_file_jsc.zig").toJS; - -pub const toBlob = @import("../bundler_jsc/output_file_jsc.zig").toBlob; - -const string = []const u8; - -const resolve_path = @import("../paths/resolve_path.zig"); -const resolver = @import("../resolver/resolver.zig"); -const std = @import("std"); -const Loader = @import("./options.zig").Loader; - -const bun = @import("bun"); -const Environment = bun.Environment; -const FileDescriptorType = bun.FD; -const Fs = bun.fs; -const jsc = bun.jsc; diff --git a/src/bundler/ParseTask.zig b/src/bundler/ParseTask.zig deleted file mode 100644 index bcc793aad939..000000000000 --- a/src/bundler/ParseTask.zig +++ /dev/null @@ -1,1496 +0,0 @@ -pub const ContentsOrFd = union(enum) { - fd: struct { - dir: FD, - file: FD, - }, - contents: string, - - const Tag = @typeInfo(ContentsOrFd).@"union".tag_type.?; -}; - -pub const ParseTask = @This(); - -path: Fs.Path, -secondary_path_for_commonjs_interop: ?Fs.Path = null, -contents_or_fd: ContentsOrFd, -external_free_function: CacheEntry.ExternalFreeFunction = .none, -side_effects: _resolver.SideEffects, -loader: ?Loader = null, -jsx: options.JSX.Pragma, -source_index: Index = Index.invalid, -task: ThreadPoolLib.Task = .{ .callback = &taskCallback }, - -// Split this into a different task so that we don't accidentally run the -// tasks for io on the threads that are meant for parsing. -io_task: ThreadPoolLib.Task = .{ .callback = &ioTaskCallback }, - -// Used for splitting up the work between the io and parse steps. -stage: ParseTaskStage = .needs_source_code, - -tree_shaking: bool = false, -known_target: options.Target, -module_type: options.ModuleType = .unknown, -emit_decorator_metadata: bool = false, -experimental_decorators: bool = false, -ctx: *BundleV2, -package_version: string = "", -package_name: string = "", -is_entry_point: bool = false, - -const ParseTaskStage = union(enum) { - needs_source_code: void, - needs_parse: CacheEntry, -}; - -/// The information returned to the Bundler thread when a parse finishes. -pub const Result = struct { - task: EventLoop.Task, - ctx: *BundleV2, - value: Value, - watcher_data: WatcherData, - /// This is used for native onBeforeParsePlugins to store - /// a function pointer and context pointer to free the - /// returned source code by the plugin. - external: CacheEntry.ExternalFreeFunction = .none, - - pub const Value = union(enum) { - success: Success, - err: Error, - empty: struct { - source_index: Index, - }, - }; - - const WatcherData = struct { - fd: bun.FD, - dir_fd: bun.FD, - - /// When no files to watch, this encoding is used. - pub const none: WatcherData = .{ - .fd = bun.invalid_fd, - .dir_fd = bun.invalid_fd, - }; - }; - - pub const Success = struct { - ast: JSAst, - source: Logger.Source, - log: Logger.Log, - use_directive: UseDirective, - side_effects: _resolver.SideEffects, - - /// Used by "file" loader files. - unique_key_for_additional_file: []const u8 = "", - /// Used by "file" loader files. - content_hash_for_additional_file: u64 = 0, - - loader: Loader, - - /// The package name from package.json, used for barrel optimization. - package_name: string = "", - }; - - pub const Error = struct { - err: anyerror, - step: Step, - log: Logger.Log, - target: options.Target, - source_index: Index, - - pub const Step = enum { - pending, - read_file, - parse, - resolve, - }; - }; -}; - -const debug = Output.scoped(.ParseTask, .hidden); - -pub fn init(resolve_result: *const _resolver.Result, source_index: Index, ctx: *BundleV2) ParseTask { - return .{ - .ctx = ctx, - .path = resolve_result.path_pair.primary, - .contents_or_fd = .{ - .fd = .{ - .dir = resolve_result.dirname_fd, - .file = resolve_result.file_fd, - }, - }, - .side_effects = resolve_result.primary_side_effects_data, - .jsx = resolve_result.jsx, - .source_index = source_index, - .module_type = resolve_result.module_type, - .emit_decorator_metadata = resolve_result.flags.emit_decorator_metadata, - .experimental_decorators = resolve_result.flags.experimental_decorators, - .package_version = if (resolve_result.package_json) |package_json| package_json.version else "", - .package_name = if (resolve_result.package_json) |package_json| package_json.name else "", - .known_target = ctx.transpiler.options.target, - }; -} - -const RuntimeSource = struct { - parse_task: ParseTask, - source: Logger.Source, -}; - -fn getRuntimeSourceComptime(comptime target: options.Target) RuntimeSource { - // When the `require` identifier is visited, it is replaced with e_require_call_target - // and then that is either replaced with the module itself, or an import to the - // runtime here. - const runtime_require = switch (target) { - // Previously, Bun inlined `import.meta.require` at all usages. This broke - // code that called `fn.toString()` and parsed the code outside a module - // context. - .bun, .bun_macro => - \\export var __require = import.meta.require; - , - - .node => - \\import { createRequire } from "node:module"; - \\export var __require = /* @__PURE__ */ createRequire(import.meta.url); - \\ - , - - // Copied from esbuild's runtime.go: - // - // > This fallback "require" function exists so that "typeof require" can - // > naturally be "function" even in non-CommonJS environments since esbuild - // > emulates a CommonJS environment (issue #1202). However, people want this - // > shim to fall back to "globalThis.require" even if it's defined later - // > (including property accesses such as "require.resolve") so we need to - // > use a proxy (issue #1614). - // - // When bundling to node, esbuild picks this code path as well, but `globalThis.require` - // is not always defined there. The `createRequire` call approach is more reliable. - else => - \\export var __require = /* @__PURE__ */ (x => - \\ typeof require !== 'undefined' ? require : - \\ typeof Proxy !== 'undefined' ? new Proxy(x, { - \\ get: (a, b) => (typeof require !== 'undefined' ? require : a)[b] - \\ }) : x - \\)(function (x) { - \\ if (typeof require !== 'undefined') return require.apply(this, arguments) - \\ throw Error('Dynamic require of "' + x + '" is not supported') - \\}); - \\ - }; - const runtime_using_symbols = switch (target) { - // JavaScriptCore supports `using` / `await using` natively (see - // `lower_using = !target.isBun()` below), so these helpers are unused - // when bundling for Bun and will be tree-shaken. They are still defined - // here so the runtime module exports a consistent shape across targets. - // Bun's WebKit also has Symbol.asyncDispose, Symbol.dispose, and - // SuppressedError, so no polyfills are needed. - .bun => - \\export var __using = (stack, value, async) => { - \\ if (value != null) { - \\ if (typeof value !== 'object' && typeof value !== 'function') throw TypeError('Object expected to be assigned to "using" declaration') - \\ let dispose - \\ if (async) dispose = value[Symbol.asyncDispose] - \\ if (dispose === void 0) dispose = value[Symbol.dispose] - \\ if (typeof dispose !== 'function') throw TypeError('Object not disposable') - \\ stack.push([async, dispose, value]) - \\ } else if (async) { - \\ stack.push([async]) - \\ } - \\ return value - \\} - \\ - \\export var __callDispose = (stack, error, hasError) => { - \\ let fail = e => error = hasError ? new SuppressedError(e, error, 'An error was suppressed during disposal') : (hasError = true, e) - \\ , next = (it) => { - \\ while (it = stack.pop()) { - \\ try { - \\ var result = it[1] && it[1].call(it[2]) - \\ if (it[0]) return Promise.resolve(result).then(next, (e) => (fail(e), next())) - \\ } catch (e) { - \\ fail(e) - \\ } - \\ } - \\ if (hasError) throw error - \\ } - \\ return next() - \\} - \\ - , - // Other platforms may or may not have the symbol or errors - // The definitions of __dispose and __asyncDispose match what esbuild's __wellKnownSymbol() helper does - else => - \\var __dispose = Symbol.dispose || /* @__PURE__ */ Symbol.for('Symbol.dispose'); - \\var __asyncDispose = Symbol.asyncDispose || /* @__PURE__ */ Symbol.for('Symbol.asyncDispose'); - \\ - \\export var __using = (stack, value, async) => { - \\ if (value != null) { - \\ if (typeof value !== 'object' && typeof value !== 'function') throw TypeError('Object expected to be assigned to "using" declaration') - \\ var dispose - \\ if (async) dispose = value[__asyncDispose] - \\ if (dispose === void 0) dispose = value[__dispose] - \\ if (typeof dispose !== 'function') throw TypeError('Object not disposable') - \\ stack.push([async, dispose, value]) - \\ } else if (async) { - \\ stack.push([async]) - \\ } - \\ return value - \\} - \\ - \\export var __callDispose = (stack, error, hasError) => { - \\ var E = typeof SuppressedError === 'function' ? SuppressedError : - \\ function (e, s, m, _) { return _ = Error(m), _.name = 'SuppressedError', _.error = e, _.suppressed = s, _ }, - \\ fail = e => error = hasError ? new E(e, error, 'An error was suppressed during disposal') : (hasError = true, e), - \\ next = (it) => { - \\ while (it = stack.pop()) { - \\ try { - \\ var result = it[1] && it[1].call(it[2]) - \\ if (it[0]) return Promise.resolve(result).then(next, (e) => (fail(e), next())) - \\ } catch (e) { - \\ fail(e) - \\ } - \\ } - \\ if (hasError) throw error - \\ } - \\ return next() - \\} - \\ - }; - const runtime_code = @embedFile("../runtime.js") ++ runtime_require ++ runtime_using_symbols; - - const parse_task = ParseTask{ - .ctx = undefined, - .path = Fs.Path.initWithNamespace("runtime", "bun:runtime"), - .side_effects = .no_side_effects__pure_data, - .jsx = .{ - .parse = false, - }, - .contents_or_fd = .{ - .contents = runtime_code, - }, - .source_index = Index.runtime, - .loader = .js, - .known_target = target, - }; - const source = Logger.Source{ - .path = parse_task.path, - .contents = parse_task.contents_or_fd.contents, - .index = Index.runtime, - }; - return .{ .parse_task = parse_task, .source = source }; -} - -pub fn getRuntimeSource(target: options.Target) RuntimeSource { - return switch (target) { - inline else => |t| comptime getRuntimeSourceComptime(t), - }; -} - -fn getEmptyCSSAST( - log: *Logger.Log, - transpiler: *Transpiler, - opts: js_parser.Parser.Options, - allocator: std.mem.Allocator, - source: *const Logger.Source, -) !JSAst { - const root = Expr.init(E.Object, E.Object{}, Logger.Loc{ .start = 0 }); - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); - ast.css = bun.create(allocator, bun.css.BundlerStyleSheet, bun.css.BundlerStyleSheet.empty(allocator)); - return ast; -} - -fn getEmptyAST(log: *Logger.Log, transpiler: *Transpiler, opts: js_parser.Parser.Options, allocator: std.mem.Allocator, source: *const Logger.Source, comptime RootType: type) !JSAst { - const root = Expr.init(RootType, RootType{}, Logger.Loc.Empty); - return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); -} - -const FileLoaderHash = struct { - key: []const u8, - content_hash: u64, -}; - -fn getAST( - log: *Logger.Log, - transpiler: *Transpiler, - opts: js_parser.Parser.Options, - allocator: std.mem.Allocator, - resolver: *Resolver, - source: *const Logger.Source, - loader: Loader, - unique_key_prefix: u64, - unique_key_for_additional_file: *FileLoaderHash, - has_any_css_locals: *std.atomic.Value(u32), -) !JSAst { - switch (loader) { - .jsx, .tsx, .js, .ts => { - const trace = bun.perf.trace("Bundler.ParseJS"); - defer trace.end(); - return if (try resolver.caches.js.parse( - transpiler.allocator, - opts, - transpiler.options.define, - log, - source, - )) |res| - JSAst.init(res.ast) - else switch (opts.module_type == .esm) { - inline else => |as_undefined| try getEmptyAST( - log, - transpiler, - opts, - allocator, - source, - if (as_undefined) E.Undefined else E.Object, - ), - }; - }, - .json, .jsonc => |v| { - const trace = bun.perf.trace("Bundler.ParseJSON"); - defer trace.end(); - const root = (try resolver.caches.json.parseJSON(log, source, allocator, if (v == .jsonc) .jsonc else .json, true)) orelse Expr.init(E.Object, E.Object{}, Logger.Loc.Empty); - return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); - }, - .toml => { - const trace = bun.perf.trace("Bundler.ParseTOML"); - defer trace.end(); - var temp_log = bun.logger.Log.init(allocator); - defer { - bun.handleOom(temp_log.cloneToWithRecycled(log, true)); - temp_log.msgs.clearAndFree(); - } - const root = try TOML.parse(source, &temp_log, allocator, false); - return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, &temp_log, root, source, "")).?); - }, - .yaml => { - const trace = bun.perf.trace("Bundler.ParseYAML"); - defer trace.end(); - var temp_log = bun.logger.Log.init(allocator); - defer { - bun.handleOom(temp_log.cloneToWithRecycled(log, true)); - temp_log.msgs.clearAndFree(); - } - const root = try YAML.parse(source, &temp_log, allocator); - return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, &temp_log, root, source, "")).?); - }, - .json5 => { - const trace = bun.perf.trace("Bundler.ParseJSON5"); - defer trace.end(); - var temp_log = bun.logger.Log.init(allocator); - defer { - bun.handleOom(temp_log.cloneToWithRecycled(log, true)); - temp_log.msgs.clearAndFree(); - } - const root = try JSON5.parse(source, &temp_log, allocator); - return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, &temp_log, root, source, "")).?); - }, - .text => { - const root = Expr.init(E.String, E.String{ - .data = source.contents, - }, Logger.Loc{ .start = 0 }); - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); - ast.addUrlForCss(allocator, source, "text/plain", null, transpiler.options.compile_to_standalone_html); - return ast; - }, - .md => { - const html = bun.md.renderToHtml(source.contents, allocator) catch { - log.addError( - source, - Logger.Loc.Empty, - "Failed to render markdown to HTML", - ) catch |err| bun.handleOom(err); - return error.ParserError; - }; - const root = Expr.init(E.String, E.String{ - .data = html, - }, Logger.Loc{ .start = 0 }); - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); - ast.addUrlForCss(allocator, source, "text/html", null, transpiler.options.compile_to_standalone_html); - return ast; - }, - - .sqlite_embedded, .sqlite => { - if (!transpiler.options.target.isBun()) { - log.addError( - source, - Logger.Loc.Empty, - "To use the \"sqlite\" loader, set target to \"bun\"", - ) catch |err| bun.handleOom(err); - return error.ParserError; - } - - const path_to_use = brk: { - // Implements embedded sqlite - if (loader == .sqlite_embedded) { - const embedded_path = std.fmt.allocPrint(allocator, "{f}A{d:0>8}", .{ bun.fmt.hexIntLower(unique_key_prefix), source.index.get() }) catch unreachable; - unique_key_for_additional_file.* = .{ - .key = embedded_path, - .content_hash = ContentHasher.run(source.contents), - }; - break :brk embedded_path; - } - - break :brk source.path.text; - }; - - // This injects the following code: - // - // import.meta.require(unique_key).db - // - const import_path = Expr.init(E.String, E.String{ - .data = path_to_use, - }, Logger.Loc{ .start = 0 }); - - const import_meta = Expr.init(E.ImportMeta, E.ImportMeta{}, Logger.Loc{ .start = 0 }); - const require_property = Expr.init(E.Dot, E.Dot{ - .target = import_meta, - .name_loc = Logger.Loc.Empty, - .name = "require", - }, Logger.Loc{ .start = 0 }); - const require_args = allocator.alloc(Expr, 2) catch unreachable; - require_args[0] = import_path; - const object_properties = allocator.alloc(G.Property, 1) catch unreachable; - object_properties[0] = G.Property{ - .key = Expr.init(E.String, E.String{ - .data = "type", - }, Logger.Loc{ .start = 0 }), - .value = Expr.init(E.String, E.String{ - .data = "sqlite", - }, Logger.Loc{ .start = 0 }), - }; - require_args[1] = Expr.init(E.Object, E.Object{ - .properties = G.Property.List.fromOwnedSlice(object_properties), - .is_single_line = true, - }, Logger.Loc{ .start = 0 }); - const require_call = Expr.init(E.Call, E.Call{ - .target = require_property, - .args = BabyList(Expr).fromOwnedSlice(require_args), - }, Logger.Loc{ .start = 0 }); - - const root = Expr.init(E.Dot, E.Dot{ - .target = require_call, - .name_loc = Logger.Loc.Empty, - .name = "db", - }, Logger.Loc{ .start = 0 }); - - return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); - }, - .napi => { - // (dap-eval-cb "source.contents.ptr") - if (transpiler.options.target == .browser) { - log.addError( - source, - Logger.Loc.Empty, - "Loading .node files won't work in the browser. Make sure to set target to \"bun\" or \"node\"", - ) catch |err| bun.handleOom(err); - return error.ParserError; - } - - const unique_key = std.fmt.allocPrint(allocator, "{f}A{d:0>8}", .{ bun.fmt.hexIntLower(unique_key_prefix), source.index.get() }) catch unreachable; - // This injects the following code: - // - // require(unique_key) - // - const import_path = Expr.init(E.String, E.String{ - .data = unique_key, - }, Logger.Loc{ .start = 0 }); - - const require_args = allocator.alloc(Expr, 1) catch unreachable; - require_args[0] = import_path; - - const root = Expr.init(E.Call, E.Call{ - .target = .{ .data = .{ .e_require_call_target = {} }, .loc = .{ .start = 0 } }, - .args = BabyList(Expr).fromOwnedSlice(require_args), - }, Logger.Loc{ .start = 0 }); - - unique_key_for_additional_file.* = .{ - .key = unique_key, - .content_hash = ContentHasher.run(source.contents), - }; - return JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); - }, - .html => { - var scanner = HTMLScanner.init(allocator, log, source); - try scanner.scan(source.contents); - - // Reuse existing code for creating the AST - // because it handles the various Ref and other structs we - // need in order to print code later. - var ast = (try js_parser.newLazyExportAST( - allocator, - transpiler.options.define, - opts, - log, - Expr.init(E.Missing, E.Missing{}, Logger.Loc.Empty), - source, - "", - )).?; - ast.import_records = scanner.import_records; - - // We're banning import default of html loader files for now. - // - // TLDR: it kept including: - // - // var name_default = ...; - // - // in the bundle because of the exports AST, and - // gave up on figuring out how to fix it so that - // this feature could ship. - ast.has_lazy_export = false; - ast.parts.ptr[1] = .{ - .stmts = &.{}, - .is_live = true, - .import_record_indices = brk2: { - // Generate a single part that depends on all the import records. - // This is to ensure that we generate a JavaScript bundle containing all the user's code. - var import_record_indices = try Part.ImportRecordIndices.initCapacity(allocator, scanner.import_records.len); - import_record_indices.len = @truncate(scanner.import_records.len); - for (import_record_indices.slice(), 0..) |*import_record, index| { - import_record.* = @intCast(index); - } - break :brk2 import_record_indices; - }, - }; - - // Try to avoid generating unnecessary ESM <> CJS wrapper code. - if (opts.output_format == .esm or opts.output_format == .iife) { - ast.exports_kind = .esm; - } - - return JSAst.init(ast); - }, - .css => { - // make css ast - var import_records = BabyList(ImportRecord){}; - const source_code = source.contents; - var temp_log = bun.logger.Log.init(allocator); - defer { - bun.handleOom(temp_log.appendToMaybeRecycled(log, source)); - } - - const css_module_suffix = ".module.css"; - const enable_css_modules = source.path.pretty.len > css_module_suffix.len and - strings.eqlComptime(source.path.pretty[source.path.pretty.len - css_module_suffix.len ..], css_module_suffix); - const parser_options = if (enable_css_modules) init: { - var parseropts = bun.css.ParserOptions.default(allocator, &temp_log); - parseropts.filename = bun.path.basename(source.path.pretty); - parseropts.css_modules = bun.css.CssModuleConfig{}; - break :init parseropts; - } else bun.css.ParserOptions.default(allocator, &temp_log); - - var css_ast, var extra = switch (bun.css.BundlerStyleSheet.parseBundler( - allocator, - source_code, - parser_options, - &import_records, - source.index, - )) { - .result => |v| v, - .err => |e| { - try e.addToLogger(&temp_log, source, allocator); - return error.SyntaxError; - }, - }; - // Make sure the css modules local refs have a valid tag - if (comptime bun.Environment.isDebug) { - if (css_ast.local_scope.count() > 0) { - for (css_ast.local_scope.values()) |entry| { - const ref = entry.ref; - bun.assert(ref.innerIndex() < extra.symbols.len); - } - } - } - if (css_ast.minify(allocator, bun.css.MinifyOptions{ - .targets = bun.css.Targets.forBundlerTarget(transpiler.options.target), - .unused_symbols = .{}, - }, &extra).asErr()) |e| { - try e.addToLogger(&temp_log, source, allocator); - return error.MinifyError; - } - if (css_ast.local_scope.count() > 0) { - _ = has_any_css_locals.fetchAdd(1, .monotonic); - } - // If this is a css module, the final exports object wil be set in `generateCodeForLazyExport`. - const root = Expr.init(E.Object, E.Object{}, Logger.Loc{ .start = 0 }); - const css_ast_heap = bun.create(allocator, bun.css.BundlerStyleSheet, css_ast); - var ast = JSAst.init((try js_parser.newLazyExportASTImpl(allocator, transpiler.options.define, opts, &temp_log, root, source, "", extra.symbols)).?); - ast.css = css_ast_heap; - ast.import_records = import_records; - return ast; - }, - // TODO: - .dataurl, .base64, .bunsh => { - return try getEmptyAST(log, transpiler, opts, allocator, source, E.String); - }, - .file, .wasm => { - bun.assert(loader.shouldCopyForBundling()); - - // Put a unique key in the AST to implement the URL loader. At the end - // of the bundle, the key is replaced with the actual URL. - const content_hash = ContentHasher.run(source.contents); - - const unique_key: []const u8 = if (transpiler.options.dev_server != null) - // With DevServer, the actual URL is added now, since it can be - // known this far ahead of time, and it means the unique key code - // does not have to perform an additional pass over files. - // - // To avoid a mutex, the actual insertion of the asset to DevServer - // is done on the bundler thread. - try std.fmt.allocPrint( - allocator, - bun.bake.DevServer.asset_prefix ++ "/{s}{s}", - .{ - &std.fmt.bytesToHex(std.mem.asBytes(&content_hash), .lower), - std.fs.path.extension(source.path.text), - }, - ) - else - try std.fmt.allocPrint( - allocator, - "{f}A{d:0>8}", - .{ bun.fmt.hexIntLower(unique_key_prefix), source.index.get() }, - ); - const root = Expr.init(E.String, .{ .data = unique_key }, .{ .start = 0 }); - unique_key_for_additional_file.* = .{ - .key = unique_key, - .content_hash = content_hash, - }; - var ast = JSAst.init((try js_parser.newLazyExportAST(allocator, transpiler.options.define, opts, log, root, source, "")).?); - ast.addUrlForCss(allocator, source, null, unique_key, transpiler.options.compile_to_standalone_html); - return ast; - }, - } -} - -fn getCodeForParseTaskWithoutPlugins( - task: *ParseTask, - log: *Logger.Log, - transpiler: *Transpiler, - resolver: *Resolver, - allocator: std.mem.Allocator, - file_path: *Fs.Path, - loader: Loader, -) !CacheEntry { - return switch (task.contents_or_fd) { - .fd => |contents| brk: { - const trace = bun.perf.trace("Bundler.readFile"); - defer trace.end(); - - // Check FileMap for in-memory files first - if (task.ctx.file_map) |file_map| { - if (file_map.get(file_path.text)) |file_contents| { - break :brk .{ - .contents = file_contents, - .fd = bun.invalid_fd, - }; - } - } - - if (strings.eqlComptime(file_path.namespace, "node")) lookup_builtin: { - if (task.ctx.framework) |f| { - if (f.built_in_modules.get(file_path.text)) |file| { - switch (file) { - .code => |code| break :brk .{ .contents = code, .fd = bun.invalid_fd }, - .import => |path| { - file_path.* = Fs.Path.init(path); - break :lookup_builtin; - }, - } - } - } - - break :brk .{ - .contents = NodeFallbackModules.contentsFromPath(file_path.text) orelse "", - .fd = bun.invalid_fd, - }; - } - - break :brk resolver.caches.fs.readFileWithAllocator( - // TODO: this allocator may be wrong for native plugins - if (loader.shouldCopyForBundling()) - // The OutputFile will own the memory for the contents - bun.default_allocator - else - allocator, - transpiler.fs, - file_path.text, - task.contents_or_fd.fd.dir, - false, - contents.file.unwrapValid(), - ) catch |err| { - const source = &Logger.Source.initEmptyFile(log.msgs.allocator.dupe(u8, file_path.text) catch unreachable); - switch (err) { - error.ENOENT, error.FileNotFound => { - log.addErrorFmt( - source, - Logger.Loc.Empty, - allocator, - "File not found {f}", - .{bun.fmt.quote(file_path.text)}, - ) catch {}; - return error.FileNotFound; - }, - else => { - log.addErrorFmt( - source, - Logger.Loc.Empty, - allocator, - "{s} reading file: {f}", - .{ @errorName(err), bun.fmt.quote(file_path.text) }, - ) catch {}; - }, - } - return err; - }; - }, - .contents => |contents| .{ - .contents = contents, - .fd = bun.invalid_fd, - }, - }; -} - -fn getCodeForParseTask( - task: *ParseTask, - log: *Logger.Log, - transpiler: *Transpiler, - resolver: *Resolver, - allocator: std.mem.Allocator, - file_path: *Fs.Path, - loader: *Loader, - from_plugin: *bool, -) !CacheEntry { - const might_have_on_parse_plugins = brk: { - if (task.source_index.isRuntime()) break :brk false; - const plugin = task.ctx.plugins orelse break :brk false; - if (!plugin.hasOnBeforeParsePlugins()) break :brk false; - - if (strings.eqlComptime(file_path.namespace, "node")) { - break :brk false; - } - break :brk true; - }; - - if (!might_have_on_parse_plugins) { - return getCodeForParseTaskWithoutPlugins(task, log, transpiler, resolver, allocator, file_path, loader.*); - } - - var should_continue_running: i32 = 1; - - var ctx = OnBeforeParsePlugin{ - .task = task, - .log = log, - .transpiler = transpiler, - .resolver = resolver, - .allocator = allocator, - .file_path = file_path, - .loader = loader, - .deferred_error = null, - .should_continue_running = &should_continue_running, - }; - - return try ctx.run(task.ctx.plugins.?, from_plugin); -} - -const OnBeforeParsePlugin = struct { - task: *ParseTask, - log: *Logger.Log, - transpiler: *Transpiler, - resolver: *Resolver, - allocator: std.mem.Allocator, - file_path: *Fs.Path, - loader: *Loader, - deferred_error: ?anyerror = null, - should_continue_running: *i32, - - result: ?*OnBeforeParseResult = null, - - const headers = bun.c; - - comptime { - bun.assert(@sizeOf(OnBeforeParseArguments) == @sizeOf(headers.OnBeforeParseArguments)); - bun.assert(@alignOf(OnBeforeParseArguments) == @alignOf(headers.OnBeforeParseArguments)); - - bun.assert(@sizeOf(BunLogOptions) == @sizeOf(headers.BunLogOptions)); - bun.assert(@alignOf(BunLogOptions) == @alignOf(headers.BunLogOptions)); - - bun.assert(@sizeOf(OnBeforeParseResult) == @sizeOf(headers.OnBeforeParseResult)); - bun.assert(@alignOf(OnBeforeParseResult) == @alignOf(headers.OnBeforeParseResult)); - - bun.assert(@sizeOf(BunLogOptions) == @sizeOf(headers.BunLogOptions)); - bun.assert(@alignOf(BunLogOptions) == @alignOf(headers.BunLogOptions)); - } - - const OnBeforeParseArguments = extern struct { - struct_size: usize = @sizeOf(OnBeforeParseArguments), - context: *OnBeforeParsePlugin, - path_ptr: ?[*]const u8 = "", - path_len: usize = 0, - namespace_ptr: ?[*]const u8 = "file", - namespace_len: usize = "file".len, - default_loader: Loader = .file, - external: ?*anyopaque = null, - }; - - const BunLogOptions = extern struct { - struct_size: usize = @sizeOf(BunLogOptions), - message_ptr: ?[*]const u8 = null, - message_len: usize = 0, - path_ptr: ?[*]const u8 = null, - path_len: usize = 0, - source_line_text_ptr: ?[*]const u8 = null, - source_line_text_len: usize = 0, - level: Logger.Log.Level = .err, - line: i32 = 0, - column: i32 = 0, - line_end: i32 = 0, - column_end: i32 = 0, - - pub fn sourceLineText(this: *const BunLogOptions) string { - if (this.source_line_text_ptr) |ptr| { - if (this.source_line_text_len > 0) { - return ptr[0..this.source_line_text_len]; - } - } - return ""; - } - - pub fn path(this: *const BunLogOptions) string { - if (this.path_ptr) |ptr| { - if (this.path_len > 0) { - return ptr[0..this.path_len]; - } - } - return ""; - } - - pub fn message(this: *const BunLogOptions) string { - if (this.message_ptr) |ptr| { - if (this.message_len > 0) { - return ptr[0..this.message_len]; - } - } - return ""; - } - - pub fn append(this: *const BunLogOptions, log: *Logger.Log, namespace: string) void { - const allocator = log.msgs.allocator; - const source_line_text = this.sourceLineText(); - const location = Logger.Location.init( - this.path(), - namespace, - @max(this.line, -1), - @max(this.column, -1), - @max(this.column_end - this.column, 0), - if (source_line_text.len > 0) bun.handleOom(allocator.dupe(u8, source_line_text)) else null, - ); - var msg = Logger.Msg{ .data = .{ .location = location, .text = bun.handleOom(allocator.dupe(u8, this.message())) } }; - switch (this.level) { - .err => msg.kind = .err, - .warn => msg.kind = .warn, - .verbose => msg.kind = .verbose, - .debug => msg.kind = .debug, - else => {}, - } - if (msg.kind == .err) { - log.errors += 1; - } else if (msg.kind == .warn) { - log.warnings += 1; - } - bun.handleOom(log.addMsg(msg)); - } - - pub fn logFn( - args_: ?*OnBeforeParseArguments, - log_options_: ?*BunLogOptions, - ) callconv(.c) void { - const args = args_ orelse return; - const log_options = log_options_ orelse return; - log_options.append(args.context.log, args.context.file_path.namespace); - } - }; - - const OnBeforeParseResultWrapper = extern struct { - original_source: ?[*]const u8 = null, - original_source_len: usize = 0, - original_source_fd: bun.FD = bun.invalid_fd, - loader: Loader, - check: if (bun.Environment.isDebug) u32 else u0 = if (bun.Environment.isDebug) 42069 else 0, // Value to ensure OnBeforeParseResult is wrapped in this struct - result: OnBeforeParseResult, - }; - - const OnBeforeParseResult = extern struct { - struct_size: usize = @sizeOf(OnBeforeParseResult), - source_ptr: ?[*]const u8 = null, - source_len: usize = 0, - loader: Loader, - - fetch_source_code_fn: *const fn (*OnBeforeParseArguments, *OnBeforeParseResult) callconv(.c) i32 = &fetchSourceCode, - - user_context: ?*anyopaque = null, - free_user_context: ?*const fn (?*anyopaque) callconv(.c) void = null, - - log: *const fn ( - args_: ?*OnBeforeParseArguments, - log_options_: ?*BunLogOptions, - ) callconv(.c) void = &BunLogOptions.logFn, - - pub fn getWrapper(result: *OnBeforeParseResult) *OnBeforeParseResultWrapper { - const wrapper: *OnBeforeParseResultWrapper = @fieldParentPtr("result", result); - bun.debugAssert(wrapper.check == 42069); - return wrapper; - } - }; - - pub fn fetchSourceCode(args: *OnBeforeParseArguments, result: *OnBeforeParseResult) callconv(.c) i32 { - debug("fetchSourceCode", .{}); - const this = args.context; - if (this.log.errors > 0 or this.deferred_error != null or this.should_continue_running.* != 1) { - return 1; - } - - if (result.source_ptr != null) { - return 0; - } - - const entry = getCodeForParseTaskWithoutPlugins( - this.task, - this.log, - this.transpiler, - this.resolver, - this.allocator, - this.file_path, - - result.loader, - ) catch |err| { - this.deferred_error = err; - this.should_continue_running.* = 0; - return 1; - }; - result.source_ptr = entry.contents.ptr; - result.source_len = entry.contents.len; - result.free_user_context = null; - result.user_context = null; - const wrapper: *OnBeforeParseResultWrapper = result.getWrapper(); - wrapper.original_source = entry.contents.ptr; - wrapper.original_source_len = entry.contents.len; - wrapper.original_source_fd = entry.fd; - return 0; - } - - pub export fn OnBeforeParseResult__reset(this: *OnBeforeParseResult) void { - const wrapper = this.getWrapper(); - this.loader = wrapper.loader; - if (wrapper.original_source) |src_ptr| { - const src = src_ptr[0..wrapper.original_source_len]; - this.source_ptr = src.ptr; - this.source_len = src.len; - } else { - this.source_ptr = null; - this.source_len = 0; - } - } - - pub export fn OnBeforeParsePlugin__isDone(this: *OnBeforeParsePlugin) i32 { - if (this.should_continue_running.* != 1) { - return 1; - } - - const result = this.result orelse return 1; - // The first plugin to set the source wins. - // But, we must check that they actually modified it - // since fetching the source stores it inside `result.source_ptr` - if (result.source_ptr != null) { - const wrapper: *OnBeforeParseResultWrapper = result.getWrapper(); - return @intFromBool(result.source_ptr.? != wrapper.original_source.?); - } - - return 0; - } - - pub fn run(this: *OnBeforeParsePlugin, plugin: *jsc.API.JSBundler.Plugin, from_plugin: *bool) !CacheEntry { - var args = OnBeforeParseArguments{ - .context = this, - .path_ptr = this.file_path.text.ptr, - .path_len = this.file_path.text.len, - .default_loader = this.loader.*, - }; - if (this.file_path.namespace.len > 0) { - args.namespace_ptr = this.file_path.namespace.ptr; - args.namespace_len = this.file_path.namespace.len; - } - var wrapper = OnBeforeParseResultWrapper{ - .loader = this.loader.*, - .result = OnBeforeParseResult{ - .loader = this.loader.*, - }, - }; - - this.result = &wrapper.result; - const count = plugin.callOnBeforeParsePlugins( - this, - if (bun.strings.eqlComptime(this.file_path.namespace, "file")) - &bun.String.empty - else - &bun.String.init(this.file_path.namespace), - - &bun.String.init(this.file_path.text), - &args, - &wrapper.result, - this.should_continue_running, - ); - if (comptime Environment.enable_logs) - debug("callOnBeforeParsePlugins({s}:{s}) = {d}", .{ this.file_path.namespace, this.file_path.text, count }); - if (count > 0) { - if (this.deferred_error) |err| { - if (wrapper.result.free_user_context) |free_user_context| { - free_user_context(wrapper.result.user_context); - } - - return err; - } - - // If the plugin sets the `free_user_context` function pointer, it _must_ set the `user_context` pointer. - // Otherwise this is just invalid behavior. - if (wrapper.result.user_context == null and wrapper.result.free_user_context != null) { - var msg = Logger.Msg{ .data = .{ .location = null, .text = bun.default_allocator.dupe( - u8, - "Native plugin set the `free_plugin_source_code_context` field without setting the `plugin_source_code_context` field.", - ) catch |err| bun.handleOom(err) } }; - msg.kind = .err; - args.context.log.errors += 1; - bun.handleOom(args.context.log.addMsg(msg)); - return error.InvalidNativePlugin; - } - - if (this.log.errors > 0) { - if (wrapper.result.free_user_context) |free_user_context| { - free_user_context(wrapper.result.user_context); - } - - return error.SyntaxError; - } - - if (wrapper.result.source_ptr) |ptr| { - if (wrapper.result.free_user_context != null) { - this.task.external_free_function = .{ - .ctx = wrapper.result.user_context, - .function = wrapper.result.free_user_context, - }; - } - from_plugin.* = true; - this.loader.* = wrapper.result.loader; - return .{ - .contents = ptr[0..wrapper.result.source_len], - .external_free_function = .{ - .ctx = wrapper.result.user_context, - .function = wrapper.result.free_user_context, - }, - .fd = wrapper.original_source_fd, - }; - } - } - - return try getCodeForParseTaskWithoutPlugins(this.task, this.log, this.transpiler, this.resolver, this.allocator, this.file_path, this.loader.*); - } -}; - -fn getSourceCode( - task: *ParseTask, - this: *ThreadPool.Worker, - log: *Logger.Log, -) anyerror!CacheEntry { - const allocator = this.allocator; - - var data = this.data; - const transpiler = &data.transpiler; - errdefer transpiler.resetStore(); - const resolver: *Resolver = &transpiler.resolver; - var file_path = task.path; - var loader = task.loader orelse file_path.loader(&transpiler.options.loaders) orelse options.Loader.file; - - var contents_came_from_plugin: bool = false; - return try getCodeForParseTask(task, log, transpiler, resolver, allocator, &file_path, &loader, &contents_came_from_plugin); -} - -fn runWithSourceCode( - task: *ParseTask, - this: *ThreadPool.Worker, - step: *ParseTask.Result.Error.Step, - log: *Logger.Log, - entry: *CacheEntry, -) anyerror!Result.Success { - const allocator = this.allocator; - - var transpiler = this.transpilerForTarget(task.known_target); - errdefer transpiler.resetStore(); - const resolver: *Resolver = &transpiler.resolver; - const file_path = &task.path; - const loader = task.loader orelse file_path.loader(&transpiler.options.loaders) orelse options.Loader.file; - - // WARNING: Do not change the variant of `task.contents_or_fd` from - // `.fd` to `.contents` (or back) after this point! - // - // When `task.contents_or_fd == .fd`, `entry.contents` is an owned string. - // When `task.contents_or_fd == .contents`, `entry.contents` is NOT owned! Freeing it here will cause a double free! - // - // Changing from `.contents` to `.fd` will cause a double free. - // This was the case in the situation where the ParseTask receives its `.contents` from an onLoad plugin, which caused it to be - // allocated by `bun.default_allocator` and then freed in `BundleV2.deinit` (and also by `entry.deinit(allocator)` below). - const debug_original_variant_check: if (bun.Environment.isDebug) ContentsOrFd.Tag else void = - if (bun.Environment.isDebug) @as(ContentsOrFd.Tag, task.contents_or_fd); - errdefer { - if (comptime bun.Environment.isDebug) { - if (@as(ContentsOrFd.Tag, task.contents_or_fd) != debug_original_variant_check) { - std.debug.panic("BUG: `task.contents_or_fd` changed in a way that will cause a double free or memory to leak!\n\n Original = {s}\n New = {s}\n", .{ - @tagName(debug_original_variant_check), - @tagName(task.contents_or_fd), - }); - } - } - if (task.contents_or_fd == .fd) entry.deinit(allocator); - } - - const will_close_file_descriptor = task.contents_or_fd == .fd and - entry.fd.isValid() and - entry.fd.stdioTag() == null and - this.ctx.bun_watcher == null; - if (will_close_file_descriptor) { - _ = entry.closeFD(); - task.contents_or_fd = .{ .fd = .{ - .file = bun.invalid_fd, - .dir = bun.invalid_fd, - } }; - } else if (task.contents_or_fd == .fd) { - task.contents_or_fd = .{ .fd = .{ - .file = entry.fd, - .dir = bun.invalid_fd, - } }; - } - step.* = .parse; - - const is_empty = strings.isAllWhitespace(entry.contents); - - const use_directive: UseDirective = if (!is_empty and transpiler.options.server_components) - if (UseDirective.parse(entry.contents)) |use| - use - else - .none - else - .none; - - if (use_directive == .client and - task.known_target != .bake_server_components_ssr and - this.ctx.framework != null and - this.ctx.framework.?.server_components.?.separate_ssr_graph or - // set the target to the client when bundling client-side files - ((transpiler.options.server_components or transpiler.options.dev_server != null) and - task.known_target == .browser)) - { - // separate_ssr_graph makes boundaries switch to client because the server file uses that generated file as input. - // this is not done when there is one server graph because it is easier for plugins to deal with. - transpiler = this.transpilerForTarget(.browser); - } - - const source = &Logger.Source{ - .path = file_path.*, - .index = task.source_index, - .contents = entry.contents, - .contents_is_recycled = false, - }; - - const target = (if (task.source_index.get() == 1) targetFromHashbang(entry.contents) else null) orelse - if (task.known_target == .bake_server_components_ssr and transpiler.options.framework.?.server_components.?.separate_ssr_graph) - .bake_server_components_ssr - else - transpiler.options.target; - - const output_format = transpiler.options.output_format; - - var opts = js_parser.Parser.Options.init(task.jsx, loader); - opts.bundle = true; - opts.warn_about_unbundled_modules = false; - opts.allow_unresolved = &transpiler.options.allow_unresolved; - opts.macro_context = &transpiler.macro_context.?; - opts.package_version = task.package_version; - - opts.features.allow_runtime = !source.index.isRuntime(); - opts.features.unwrap_commonjs_to_esm = output_format == .esm and FeatureFlags.unwrap_commonjs_to_esm; - opts.features.top_level_await = output_format == .esm or output_format == .internal_bake_dev; - opts.features.auto_import_jsx = task.jsx.parse and transpiler.options.auto_import_jsx; - opts.features.trim_unused_imports = loader.isTypeScript() or (transpiler.options.trim_unused_imports orelse false); - opts.features.inlining = transpiler.options.minify_syntax; - opts.output_format = output_format; - opts.features.minify_syntax = transpiler.options.minify_syntax; - opts.features.minify_identifiers = transpiler.options.minify_identifiers; - opts.features.minify_keep_names = transpiler.options.keep_names; - opts.features.minify_whitespace = transpiler.options.minify_whitespace; - opts.features.emit_decorator_metadata = task.emit_decorator_metadata; - // emitDecoratorMetadata implies legacy/experimental decorators, as it only - // makes sense with TypeScript's legacy decorator system (reflect-metadata). - // TC39 standard decorators have their own metadata mechanism. - opts.features.standard_decorators = !loader.isTypeScript() or !(task.experimental_decorators or task.emit_decorator_metadata); - opts.features.unwrap_commonjs_packages = transpiler.options.unwrap_commonjs_packages; - opts.features.bundler_feature_flags = transpiler.options.bundler_feature_flags; - // JavaScriptCore implements `using` / `await using` natively, so when - // targeting Bun there is no need to lower them. - opts.features.lower_using = !target.isBun(); - opts.features.hot_module_reloading = output_format == .internal_bake_dev and !source.index.isRuntime(); - opts.features.auto_polyfill_require = output_format == .esm and !opts.features.hot_module_reloading; - opts.features.react_fast_refresh = transpiler.options.react_fast_refresh and - loader.isJSX() and - !source.path.isNodeModule(); - - opts.features.server_components = if (transpiler.options.server_components) switch (target) { - .browser => .client_side, - else => switch (use_directive) { - .none => .wrap_anon_server_functions, - .client => if (transpiler.options.framework.?.server_components.?.separate_ssr_graph) - .client_side - else - .wrap_exports_for_client_reference, - .server => .wrap_exports_for_server_reference, - }, - } else .none; - - opts.framework = transpiler.options.framework; - - opts.ignore_dce_annotations = transpiler.options.ignore_dce_annotations and !source.index.isRuntime(); - - // For files that are not user-specified entrypoints, set `import.meta.main` to `false`. - // Entrypoints will have `import.meta.main` set as "unknown", unless we use `--compile`, - // in which we inline `true`. - if (transpiler.options.inline_entrypoint_import_meta_main or !task.is_entry_point) { - opts.import_meta_main_value = task.is_entry_point and transpiler.options.dev_server == null; - } else if (target == .node) { - opts.lower_import_meta_main_for_node_js = true; - } - - opts.tree_shaking = if (source.index.isRuntime()) true else transpiler.options.tree_shaking; - opts.code_splitting = transpiler.options.code_splitting; - opts.module_type = task.module_type; - - task.jsx.parse = loader.isJSX(); - - var unique_key_for_additional_file: FileLoaderHash = .{ - .key = "", - .content_hash = 0, - }; - var ast: JSAst = if (!is_empty or loader.handlesEmptyFile()) - try getAST(log, transpiler, opts, allocator, resolver, source, loader, task.ctx.unique_key, &unique_key_for_additional_file, &task.ctx.linker.has_any_css_locals) - else switch (opts.module_type == .esm) { - inline else => |as_undefined| if (loader.isCSS()) try getEmptyCSSAST( - log, - transpiler, - opts, - allocator, - source, - ) else try getEmptyAST( - log, - transpiler, - opts, - allocator, - source, - if (as_undefined) E.Undefined else E.Object, - ), - }; - - ast.target = target; - if (ast.parts.len <= 1 and ast.css == null and (task.loader == null or task.loader.? != .html)) { - task.side_effects = .no_side_effects__empty_ast; - } - - // bun.debugAssert(ast.parts.len > 0); // when parts.len == 0, it is assumed to be pending/failed. empty ast has at least 1 part. - - step.* = .resolve; - - return .{ - .ast = ast, - .source = source.*, - .log = log.*, - .use_directive = use_directive, - .unique_key_for_additional_file = unique_key_for_additional_file.key, - .side_effects = task.side_effects, - .loader = loader, - .package_name = task.package_name, - - // Hash the files in here so that we do it in parallel. - .content_hash_for_additional_file = if (loader.shouldCopyForBundling()) - unique_key_for_additional_file.content_hash - else - 0, - }; -} - -fn ioTaskCallback(task: *ThreadPoolLib.Task) void { - runFromThreadPool(@fieldParentPtr("io_task", task)); -} - -fn taskCallback(task: *ThreadPoolLib.Task) void { - runFromThreadPool(@fieldParentPtr("task", task)); -} - -pub fn runFromThreadPool(this: *ParseTask) void { - var worker = ThreadPool.Worker.get(this.ctx); - defer worker.unget(); - debug("ParseTask(0x{x}, {s}) callback", .{ @intFromPtr(this), this.path.text }); - - var step: ParseTask.Result.Error.Step = .pending; - var log = Logger.Log.init(worker.allocator); - bun.assert(this.source_index.isValid()); // forgot to set source_index - - const value: ParseTask.Result.Value = value: { - if (this.stage == .needs_source_code) { - this.stage = .{ - .needs_parse = getSourceCode(this, worker, &log) catch |err| { - break :value .{ .err = .{ - .err = err, - .step = step, - .log = log, - .source_index = this.source_index, - .target = this.known_target, - } }; - }, - }; - - if (log.hasErrors()) { - break :value .{ .err = .{ - .err = error.SyntaxError, - .step = step, - .log = log, - .source_index = this.source_index, - .target = this.known_target, - } }; - } - - if (ThreadPool.usesIOPool()) { - this.ctx.graph.pool.scheduleInsideThreadPool(this); - return; - } - } - - if (runWithSourceCode(this, worker, &step, &log, &this.stage.needs_parse)) |ast| { - // When using HMR, always flag asts with errors as parse failures. - // Not done outside of the dev server out of fear of breaking existing code. - if (this.ctx.transpiler.options.dev_server != null and ast.log.hasErrors()) { - break :value .{ - .err = .{ - .err = error.SyntaxError, - .step = .parse, - .log = ast.log, - .source_index = this.source_index, - .target = this.known_target, - }, - }; - } - - break :value .{ .success = ast }; - } else |err| { - if (err == error.EmptyAST) { - log.deinit(); - break :value .{ .empty = .{ - .source_index = this.source_index, - } }; - } - - break :value .{ .err = .{ - .err = err, - .step = step, - .log = log, - .source_index = this.source_index, - .target = this.known_target, - } }; - } - }; - - const result = bun.handleOom(bun.default_allocator.create(Result)); - - result.* = .{ - .ctx = this.ctx, - .task = .{}, - .value = value, - .external = this.external_free_function, - .watcher_data = switch (this.contents_or_fd) { - .fd => |fd| .{ .fd = fd.file, .dir_fd = fd.dir }, - .contents => .none, - }, - }; - - switch (worker.ctx.loop().*) { - .js => |jsc_event_loop| { - jsc_event_loop.enqueueTaskConcurrent(jsc.ConcurrentTask.fromCallback(result, onComplete)); - }, - .mini => |*mini| { - mini.enqueueTaskConcurrentWithExtraCtx( - Result, - BundleV2, - result, - BundleV2.onParseTaskComplete, - .task, - ); - }, - } -} - -pub fn onComplete(result: *Result) void { - BundleV2.onParseTaskComplete(result, result.ctx); -} - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; - -const string = []const u8; - -const Fs = @import("../resolver/fs.zig"); -const HTMLScanner = @import("./HTMLScanner.zig"); -const NodeFallbackModules = @import("../resolver/node_fallbacks.zig"); -const linker = @import("./linker.zig"); -const runtime = @import("../js_parser/runtime.zig"); -const std = @import("std"); -const URL = @import("../url/url.zig").URL; -const CacheEntry = @import("./cache.zig").Fs.Entry; - -const Logger = @import("../logger/logger.zig"); -const Loc = Logger.Loc; - -const _resolver = @import("../resolver/resolver.zig"); -const Resolver = _resolver.Resolver; - -const options = @import("./options.zig"); -const Loader = options.Loader; - -const bun = @import("bun"); -const Environment = bun.Environment; -const FD = bun.FD; -const FeatureFlags = bun.FeatureFlags; -const ImportRecord = bun.ImportRecord; -const Output = bun.Output; -const ThreadPoolLib = bun.ThreadPool; -const Transpiler = bun.Transpiler; -const bake = bun.bake; -const base64 = bun.base64; -const default_allocator = bun.default_allocator; -const js_parser = bun.js_parser; -const strings = bun.strings; -const BabyList = bun.collections.BabyList; -const JSON5 = bun.interchange.json5.JSON5Parser; -const TOML = bun.interchange.toml.TOML; -const YAML = bun.interchange.yaml.YAML; - -const js_ast = bun.ast; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const JSAst = js_ast.BundledAst; -const Part = js_ast.Part; -const Symbol = js_ast.Symbol; - -const bundler = bun.bundle_v2; -const BundleV2 = bundler.BundleV2; -const ContentHasher = bundler.ContentHasher; -const UseDirective = bundler.UseDirective; -const targetFromHashbang = bundler.targetFromHashbang; - -const jsc = bun.jsc; -const EventLoop = bun.jsc.AnyEventLoop; diff --git a/src/bundler/PathToSourceIndexMap.zig b/src/bundler/PathToSourceIndexMap.zig deleted file mode 100644 index 3273c5eea15d..000000000000 --- a/src/bundler/PathToSourceIndexMap.zig +++ /dev/null @@ -1,46 +0,0 @@ -const PathToSourceIndexMap = @This(); - -/// The lifetime of the keys are not owned by this map. -/// -/// We assume it's arena allocated. -map: Map = .{}, - -const Map = bun.StringHashMapUnmanaged(Index.Int); - -pub fn getPath(this: *const PathToSourceIndexMap, path: *const Fs.Path) ?Index.Int { - return this.get(path.text); -} - -pub fn get(this: *const PathToSourceIndexMap, text: []const u8) ?Index.Int { - return this.map.get(text); -} - -pub fn putPath(this: *PathToSourceIndexMap, allocator: std.mem.Allocator, path: *const Fs.Path, value: Index.Int) bun.OOM!void { - try this.map.put(allocator, path.text, value); -} - -pub fn put(this: *PathToSourceIndexMap, allocator: std.mem.Allocator, text: []const u8, value: Index.Int) bun.OOM!void { - try this.map.put(allocator, text, value); -} - -pub fn getOrPutPath(this: *PathToSourceIndexMap, allocator: std.mem.Allocator, path: *const Fs.Path) bun.OOM!Map.GetOrPutResult { - return this.getOrPut(allocator, path.text); -} - -pub fn getOrPut(this: *PathToSourceIndexMap, allocator: std.mem.Allocator, text: []const u8) bun.OOM!Map.GetOrPutResult { - return try this.map.getOrPut(allocator, text); -} - -pub fn remove(this: *PathToSourceIndexMap, text: []const u8) bool { - return this.map.remove(text); -} - -pub fn removePath(this: *PathToSourceIndexMap, path: *const Fs.Path) bool { - return this.remove(path.text); -} - -const std = @import("std"); - -const bun = @import("bun"); -const Fs = bun.fs; -const Index = bun.ast.Index; diff --git a/src/bundler/ServerComponentParseTask.zig b/src/bundler/ServerComponentParseTask.zig deleted file mode 100644 index cc8689dc15da..000000000000 --- a/src/bundler/ServerComponentParseTask.zig +++ /dev/null @@ -1,247 +0,0 @@ -/// Files for Server Components are generated using `AstBuilder`, instead of -/// running through the js_parser. It emits a ParseTask.Result and joins -/// with the same logic that it runs though. -pub const ServerComponentParseTask = @This(); - -task: ThreadPoolLib.Task = .{ .callback = &taskCallbackWrap }, -data: Data, -ctx: *BundleV2, -source: Logger.Source, - -pub const Data = union(enum) { - /// Generate server-side code for a "use client" module. Given the - /// client ast, a "reference proxy" is created with identical exports. - client_reference_proxy: ReferenceProxy, - - client_entry_wrapper: ClientEntryWrapper, - - pub const ReferenceProxy = struct { - other_source: Logger.Source, - named_exports: JSAst.NamedExports, - }; - - pub const ClientEntryWrapper = struct { - path: []const u8, - }; -}; - -fn taskCallbackWrap(thread_pool_task: *ThreadPoolLib.Task) void { - const task: *ServerComponentParseTask = @fieldParentPtr("task", thread_pool_task); - var worker = ThreadPool.Worker.get(task.ctx); - defer worker.unget(); - var log = Logger.Log.init(worker.allocator); - - const result = bun.handleOom(bun.default_allocator.create(ParseTask.Result)); - result.* = .{ - .ctx = task.ctx, - .task = undefined, - - .value = if (taskCallback( - task, - &log, - worker.allocator, - )) |success| - .{ .success = success } - else |err| switch (err) { - error.OutOfMemory => bun.outOfMemory(), - }, - - .watcher_data = .none, - }; - - switch (worker.ctx.loop().*) { - .js => |jsc_event_loop| { - jsc_event_loop.enqueueTaskConcurrent(jsc.ConcurrentTask.fromCallback(result, ParseTask.onComplete)); - }, - .mini => |*mini| { - mini.enqueueTaskConcurrentWithExtraCtx( - ParseTask.Result, - BundleV2, - result, - BundleV2.onParseTaskComplete, - .task, - ); - }, - } -} - -fn taskCallback( - task: *ServerComponentParseTask, - log: *Logger.Log, - allocator: std.mem.Allocator, -) bun.OOM!ParseTask.Result.Success { - var ab = try AstBuilder.init(allocator, &task.source, task.ctx.transpiler.options.hot_module_reloading); - - switch (task.data) { - .client_reference_proxy => |data| try task.generateClientReferenceProxy(data, &ab), - .client_entry_wrapper => |data| try task.generateClientEntryWrapper(data, &ab), - } - - var bundled_ast = try ab.toBundledAst(switch (task.data) { - // Server-side - .client_reference_proxy => task.ctx.transpiler.options.target, - // Client-side, - .client_entry_wrapper => .browser, - }); - - // `wrapper_ref` is used to hold the HMR api ref (see comment in - // `src/ast/Ast.zig`) - bundled_ast.wrapper_ref = ab.hmr_api_ref; - - return .{ - .ast = bundled_ast, - .source = task.source, - .loader = .js, - .log = log.*, - .use_directive = .none, - .side_effects = .no_side_effects__pure_data, - }; -} - -fn generateClientEntryWrapper(_: *ServerComponentParseTask, data: Data.ClientEntryWrapper, b: *AstBuilder) !void { - const record = try b.addImportRecord(data.path, .stmt); - const namespace_ref = try b.newSymbol(.other, "main"); - try b.appendStmt(S.Import{ - .namespace_ref = namespace_ref, - .import_record_index = record, - .items = &.{}, - .is_single_line = true, - }); - b.import_records.items[record].flags.was_originally_bare_import = true; -} - -fn generateClientReferenceProxy(task: *ServerComponentParseTask, data: Data.ReferenceProxy, b: *AstBuilder) !void { - const server_components = task.ctx.framework.?.server_components orelse - unreachable; // config must be non-null to enter this function - - const client_named_exports = data.named_exports; - - const register_client_reference = (try b.addImportStmt( - server_components.server_runtime_import, - &.{server_components.server_register_client_reference}, - ))[0]; - - const module_path = b.newExpr(E.String{ - // In development, the path loaded is the source file: Easy! - // - // In production, the path here must be the final chunk path, but - // that information is not yet available since chunks are not - // computed. The unique_key replacement system is used here. - .data = if (task.ctx.transpiler.options.dev_server != null) - data.other_source.path.pretty - else - try std.fmt.allocPrint(b.allocator, "{f}S{d:0>8}", .{ - bun.fmt.hexIntLower(task.ctx.unique_key), - data.other_source.index.get(), - }), - }); - - for (client_named_exports.keys()) |key| { - const is_default = bun.strings.eqlComptime(key, "default"); - - // This error message is taken from - // https://github.com/facebook/react/blob/c5b9375767e2c4102d7e5559d383523736f1c902/packages/react-server-dom-webpack/src/ReactFlightWebpackNodeLoader.js#L323-L354 - const err_msg_string = try if (is_default) - std.fmt.allocPrint( - b.allocator, - "Attempted to call the default export of {[module_path]s} from " ++ - "the server, but it's on the client. It's not possible to invoke a " ++ - "client function from the server, it can only be rendered as a " ++ - "Component or passed to props of a Client Component.", - .{ .module_path = data.other_source.path.pretty }, - ) - else - std.fmt.allocPrint( - b.allocator, - "Attempted to call {[key]s}() from the server but {[key]s} " ++ - "is on the client. It's not possible to invoke a client function from " ++ - "the server, it can only be rendered as a Component or passed to " ++ - "props of a Client Component.", - .{ .key = key }, - ); - - // throw new Error(...) - const err_msg = b.newExpr(E.New{ - .target = b.newExpr(E.Identifier{ - .ref = try b.newExternalSymbol("Error"), - }), - .args = try BabyList(Expr).fromSlice(b.allocator, &.{ - b.newExpr(E.String{ .data = err_msg_string }), - }), - .close_parens_loc = Logger.Loc.Empty, - }); - - // registerClientReference( - // () => { throw new Error(...) }, - // "src/filepath.tsx", - // "Comp" - // ); - const value = b.newExpr(E.Call{ - .target = register_client_reference, - .args = try js_ast.ExprNodeList.fromSlice(b.allocator, &.{ - b.newExpr(E.Arrow{ .body = .{ - .stmts = try b.allocator.dupe(Stmt, &.{ - b.newStmt(S.Throw{ .value = err_msg }), - }), - .loc = Logger.Loc.Empty, - } }), - module_path, - b.newExpr(E.String{ .data = key }), - }), - }); - - if (is_default) { - const ref = try b.newSymbol(.other, "default"); - // export default registerClientReference(...); - try b.appendStmt(S.ExportDefault{ .value = .{ .expr = value }, .default_name = .{ .ref = ref } }); - } else { - // export const Component = registerClientReference(...); - const export_ref = try b.newSymbol(.other, key); - try b.appendStmt(S.Local{ - .decls = try G.Decl.List.fromSlice(b.allocator, &.{.{ - .binding = Binding.alloc(b.allocator, B.Identifier{ .ref = export_ref }, Logger.Loc.Empty), - .value = value, - }}), - .is_export = true, - .kind = .k_const, - }); - } - } -} - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const options = @import("./options.zig"); -const std = @import("std"); - -const Logger = @import("../logger/logger.zig"); -const Loc = Logger.Loc; - -const bun = @import("bun"); -const OOM = bun.OOM; -const ThreadPoolLib = bun.ThreadPool; -const default_allocator = bun.default_allocator; -const js_parser = bun.js_parser; -const jsc = bun.jsc; -const strings = bun.strings; -const BabyList = bun.collections.BabyList; - -const js_ast = bun.ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const JSAst = js_ast.BundledAst; -const S = js_ast.S; -const Stmt = js_ast.Stmt; - -const bundler = bun.bundle_v2; -const AstBuilder = bundler.AstBuilder; -const BundleV2 = bundler.BundleV2; diff --git a/src/bundler/ThreadPool.zig b/src/bundler/ThreadPool.zig deleted file mode 100644 index 35ff6fb9d001..000000000000 --- a/src/bundler/ThreadPool.zig +++ /dev/null @@ -1,364 +0,0 @@ -pub const ThreadPool = struct { - /// macOS holds an IORWLock on every file open. - /// This causes massive contention after about 4 threads as of macOS 15.2 - /// On Windows, this seemed to be a small performance improvement. - /// On Linux, this was a performance regression. - /// In some benchmarks on macOS, this yielded up to a 60% performance improvement in microbenchmarks that load ~10,000 files. - io_pool: *ThreadPoolLib, - worker_pool: *ThreadPoolLib, - worker_pool_is_owned: bool = false, - workers_assignments: std.AutoArrayHashMap(std.Thread.Id, *Worker) = std.AutoArrayHashMap(std.Thread.Id, *Worker).init(bun.default_allocator), - workers_assignments_lock: bun.Mutex = .{}, - v2: *BundleV2, - - const debug = Output.scoped(.ThreadPool, .visible); - - const IOThreadPool = struct { - var thread_pool: ThreadPoolLib = undefined; - // Protects initialization and deinitialization of the IO thread pool. - var mutex = bun.threading.Mutex{}; - // 0 means not initialized. 1 means initialized but not used. - // N > 1 means N-1 `ThreadPool`s are using the IO thread pool. - var ref_count = std.atomic.Value(usize).init(0); - - pub fn acquire() *ThreadPoolLib { - var count = ref_count.load(.acquire); - while (true) { - if (count == 0) break; - // .monotonic is okay because we already loaded this value with .acquire, - // and we don't need the store to be .release because the only store that - // matters is the one that goes from 0 to 1, and that one is .release. - count = ref_count.cmpxchgWeak( - count, - count + 1, - .monotonic, - .monotonic, - ) orelse return &thread_pool; - } - - mutex.lock(); - defer mutex.unlock(); - - // .monotonic because the store we care about (the one that stores 1 to - // indicate the thread pool is initialized) is guarded by the mutex. - if (ref_count.load(.monotonic) != 0) return &thread_pool; - thread_pool = .init(.{ - .max_threads = @max(@min(bun.getThreadCount(), 4), 2), - // Use a much smaller stack size for the IO thread pool - .stack_size = 512 * 1024, - }); - // 2 means initialized and referenced by one `ThreadPool`. - ref_count.store(2, .release); - return &thread_pool; - } - - pub fn release() void { - const old = ref_count.fetchSub(1, .release); - bun.assertf(old > 1, "IOThreadPool: too many calls to release()", .{}); - } - - pub fn shutdown() bool { - // .acquire instead of .acq_rel is okay because we only need to ensure that other - // threads are done using the IO pool if we read 1 from the ref count. - // - // .monotonic is okay because this function is only guaranteed to succeed when we - // can ensure that no `ThreadPool`s exist. - if (ref_count.cmpxchgStrong(1, 0, .acquire, .monotonic) != null) { - // At least one `ThreadPool` still exists. - return false; - } - - mutex.lock(); - defer mutex.unlock(); - - // .monotonic is okay because the only store that could happen at this point - // is guarded by the mutex. - if (ref_count.load(.monotonic) != 0) return false; - thread_pool.deinit(); - thread_pool = undefined; - } - }; - - pub fn init(v2: *BundleV2, worker_pool: ?*ThreadPoolLib) !ThreadPool { - const pool = worker_pool orelse blk: { - const cpu_count = bun.getThreadCount(); - const pool = try v2.allocator().create(ThreadPoolLib); - pool.* = .init(.{ .max_threads = cpu_count }); - debug("{d} workers", .{cpu_count}); - break :blk pool; - }; - var this = initWithPool(v2, pool); - this.worker_pool_is_owned = false; - return this; - } - - pub fn initWithPool(v2: *BundleV2, worker_pool: *ThreadPoolLib) ThreadPool { - return .{ - .worker_pool = worker_pool, - .io_pool = if (usesIOPool()) IOThreadPool.acquire() else undefined, - .v2 = v2, - }; - } - - pub fn deinit(this: *ThreadPool) void { - if (this.worker_pool_is_owned) { - this.worker_pool.deinit(); - this.v2.allocator().destroy(this.worker_pool); - } - if (usesIOPool()) { - IOThreadPool.release(); - } - } - - pub fn start(this: *ThreadPool) void { - this.worker_pool.warm(8); - if (usesIOPool()) { - this.io_pool.warm(1); - } - } - - pub fn usesIOPool() bool { - if (bun.feature_flag.BUN_FEATURE_FLAG_FORCE_IO_POOL.get()) { - // For testing. - return true; - } - - if (bun.feature_flag.BUN_FEATURE_FLAG_DISABLE_IO_POOL.get()) { - // For testing. - return false; - } - - if (Environment.isMac or Environment.isWindows) { - // 4 was the sweet spot on macOS. Didn't check the sweet spot on Windows. - return bun.getThreadCount() > 3; - } - - return false; - } - - /// Shut down the IO pool, if and only if no `ThreadPool`s exist right now. - /// If a `ThreadPool` exists, this function is a no-op and returns false. - /// Blocks until the IO pool is shut down. - pub fn shutdownIOPool() bool { - return if (usesIOPool()) IOThreadPool.shutdown() else true; - } - - pub fn scheduleWithOptions(this: *ThreadPool, parse_task: *ParseTask, is_inside_thread_pool: bool) void { - if (parse_task.contents_or_fd == .contents and parse_task.stage == .needs_source_code) { - parse_task.stage = .{ - .needs_parse = .{ - .contents = parse_task.contents_or_fd.contents, - .fd = bun.invalid_fd, - }, - }; - } - - const scheduleFn = if (is_inside_thread_pool) &ThreadPoolLib.scheduleInsideThreadPool else &ThreadPoolLib.schedule; - - if (usesIOPool()) { - switch (parse_task.stage) { - .needs_parse => { - scheduleFn(this.worker_pool, .from(&parse_task.task)); - }, - .needs_source_code => { - scheduleFn(this.io_pool, .from(&parse_task.io_task)); - }, - } - } else { - scheduleFn(this.worker_pool, .from(&parse_task.task)); - } - } - - pub fn schedule(this: *ThreadPool, parse_task: *ParseTask) void { - this.scheduleWithOptions(parse_task, false); - } - - pub fn scheduleInsideThreadPool(this: *ThreadPool, parse_task: *ParseTask) void { - this.scheduleWithOptions(parse_task, true); - } - - pub fn getWorker(this: *ThreadPool, id: std.Thread.Id) *Worker { - var worker: *Worker = undefined; - { - this.workers_assignments_lock.lock(); - defer this.workers_assignments_lock.unlock(); - const entry = this.workers_assignments.getOrPut(id) catch unreachable; - if (entry.found_existing) { - return entry.value_ptr.*; - } - - worker = bun.default_allocator.create(Worker) catch unreachable; - entry.value_ptr.* = worker; - } - - worker.* = .{ - .ctx = this.v2, - .heap = undefined, - .allocator = undefined, - .thread = ThreadPoolLib.Thread.current, - }; - worker.init(this.v2); - - return worker; - } - - pub const Worker = struct { - heap: ThreadLocalArena, - - /// Thread-local memory allocator - /// All allocations are freed in `deinit` at the very end of bundling. - allocator: std.mem.Allocator, - - ctx: *BundleV2, - - data: WorkerData = undefined, - quit: bool = false, - - ast_memory_allocator: js_ast.ASTMemoryAllocator = undefined, - has_created: bool = false, - thread: ?*ThreadPoolLib.Thread = null, - - deinit_task: ThreadPoolLib.Task = .{ .callback = deinitCallback }, - - temporary_arena: bun.ArenaAllocator = undefined, - stmt_list: LinkerContext.StmtList = undefined, - - pub fn deinitCallback(task: *ThreadPoolLib.Task) void { - debug("Worker.deinit()", .{}); - var this: *Worker = @alignCast(@fieldParentPtr("deinit_task", task)); - this.deinit(); - } - - pub fn deinitSoon(this: *Worker) void { - if (this.thread) |thread| { - thread.pushIdleTask(&this.deinit_task); - } - } - - pub fn deinit(this: *Worker) void { - if (this.has_created) { - this.heap.deinit(); - } - - bun.default_allocator.destroy(this); - } - - pub fn get(ctx: *BundleV2) *Worker { - var worker = ctx.graph.pool.getWorker(std.Thread.getCurrentId()); - if (!worker.has_created) { - worker.create(ctx); - } - - worker.ast_memory_allocator.push(); - - if (comptime FeatureFlags.help_catch_memory_issues) { - worker.heap.helpCatchMemoryIssues(); - } - - return worker; - } - - pub fn unget(this: *Worker) void { - if (comptime FeatureFlags.help_catch_memory_issues) { - this.heap.helpCatchMemoryIssues(); - } - - this.ast_memory_allocator.pop(); - } - - pub const WorkerData = struct { - log: *Logger.Log, - estimated_input_lines_of_code: usize = 0, - transpiler: Transpiler, - other_transpiler: ?Transpiler = null, - }; - - pub fn init(worker: *Worker, v2: *BundleV2) void { - worker.ctx = v2; - } - - fn create(this: *Worker, ctx: *BundleV2) void { - const trace = bun.perf.trace("Bundler.Worker.create"); - defer trace.end(); - - this.has_created = true; - Output.Source.configureThread(); - this.heap = ThreadLocalArena.init(); - this.allocator = this.heap.allocator(); - - const allocator = this.allocator; - - this.ast_memory_allocator = .{ .allocator = this.allocator }; - this.ast_memory_allocator.reset(); - - this.data = WorkerData{ - .log = bun.handleOom(allocator.create(Logger.Log)), - .transpiler = undefined, - }; - this.data.log.* = Logger.Log.init(allocator); - this.ctx = ctx; - this.temporary_arena = bun.ArenaAllocator.init(this.allocator); - this.stmt_list = LinkerContext.StmtList.init(this.allocator); - this.initializeTranspiler(&this.data.transpiler, ctx.transpiler, allocator); - - debug("Worker.create()", .{}); - } - - fn initializeTranspiler(this: *Worker, transpiler: *Transpiler, from: *Transpiler, allocator: std.mem.Allocator) void { - transpiler.* = from.*; - transpiler.setLog(this.data.log); - transpiler.setAllocator(allocator); - transpiler.linker.resolver = &transpiler.resolver; - transpiler.macro_context = js_ast.Macro.MacroContext.init(transpiler); - const CacheSet = @import("./cache.zig"); - transpiler.resolver.caches = CacheSet.Set.init(allocator); - } - - pub fn transpilerForTarget(this: *Worker, target: bun.options.Target) *Transpiler { - if (target == .browser and this.data.transpiler.options.target != target) { - const other_transpiler = if (this.data.other_transpiler) |*other| - other - else blk: { - this.data.other_transpiler = undefined; - const other = &this.data.other_transpiler.?; - this.initializeTranspiler(other, this.ctx.client_transpiler.?, this.allocator); - break :blk other; - }; - bun.debugAssert(other_transpiler.options.target == target); - return other_transpiler; - } - - return &this.data.transpiler; - } - - pub fn run(this: *Worker, ctx: *BundleV2) void { - if (!this.has_created) { - this.create(ctx); - } - } - }; -}; - -pub const Ref = bun.ast.Ref; - -pub const Index = bun.ast.Index; - -const Logger = @import("../logger/logger.zig"); -const linker = @import("./linker.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const FeatureFlags = bun.FeatureFlags; -const Output = bun.Output; -const ThreadPoolLib = bun.ThreadPool; -const Transpiler = bun.Transpiler; -const default_allocator = bun.default_allocator; -const js_ast = bun.ast; - -const allocators = bun.allocators; -const ThreadLocalArena = bun.allocators.MimallocArena; - -const BundleV2 = bun.bundle_v2.BundleV2; -const LinkerContext = bun.bundle_v2.LinkerContext; -const ParseTask = bun.bundle_v2.ParseTask; diff --git a/src/bundler/analyze_transpiled_module.zig b/src/bundler/analyze_transpiled_module.zig deleted file mode 100644 index 3cd6ed6e0b61..000000000000 --- a/src/bundler/analyze_transpiled_module.zig +++ /dev/null @@ -1,397 +0,0 @@ -pub const RecordKind = enum(u8) { - /// var_name - declared_variable, - /// let_name - lexical_variable, - /// module_name, import_name, local_name - import_info_single, - /// module_name, import_name, local_name - import_info_single_type_script, - /// module_name, import_name = '*', local_name - import_info_namespace, - /// export_name, import_name, module_name - export_info_indirect, - /// export_name, local_name, padding (for local => indirect conversion) - export_info_local, - /// export_name, module_name - export_info_namespace, - /// module_name - export_info_star, - _, - - pub fn len(record: RecordKind) !usize { - return switch (record) { - .declared_variable, .lexical_variable => 1, - .import_info_single => 3, - .import_info_single_type_script => 3, - .import_info_namespace => 3, - .export_info_indirect => 3, - .export_info_local => 3, - .export_info_namespace => 2, - .export_info_star => 1, - else => return error.InvalidRecordKind, - }; - } -}; - -pub const Flags = packed struct(u8) { - contains_import_meta: bool = false, - is_typescript: bool = false, - has_tla: bool = false, - _padding: u5 = 0, -}; - -pub const ModuleInfoDeserialized = struct { - strings_buf: []const u8, - strings_lens: []align(1) const u32, - requested_modules_keys: []align(1) const StringID, - requested_modules_values: []align(1) const ModuleInfo.FetchParameters, - buffer: []align(1) const StringID, - record_kinds: []align(1) const RecordKind, - flags: Flags, - owner: union(enum) { - module_info, - allocated_slice: struct { - slice: []const u8, - allocator: std.mem.Allocator, - }, - }, - pub fn deinit(self: *ModuleInfoDeserialized) void { - switch (self.owner) { - .module_info => { - const mi: *ModuleInfo = @fieldParentPtr("_deserialized", self); - mi.destroy(); - }, - .allocated_slice => |as| { - as.allocator.free(as.slice); - as.allocator.destroy(self); - }, - } - } - - inline fn eat(rem: *[]const u8, len: usize) ![]const u8 { - if (rem.*.len < len) return error.BadModuleInfo; - const res = rem.*[0..len]; - rem.* = rem.*[len..]; - return res; - } - inline fn eatC(rem: *[]const u8, comptime len: usize) !*const [len]u8 { - if (rem.*.len < len) return error.BadModuleInfo; - const res = rem.*[0..len]; - rem.* = rem.*[len..]; - return res; - } - pub fn create(source: []const u8, gpa: std.mem.Allocator) !*ModuleInfoDeserialized { - const duped = try gpa.dupe(u8, source); - errdefer gpa.free(duped); - var rem: []const u8 = duped; - const res = try gpa.create(ModuleInfoDeserialized); - errdefer gpa.destroy(res); - - const record_kinds_len = std.mem.readInt(u32, try eatC(&rem, 4), .little); - const record_kinds = std.mem.bytesAsSlice(RecordKind, try eat(&rem, record_kinds_len * @sizeOf(RecordKind))); - _ = try eat(&rem, (4 - (record_kinds_len % 4)) % 4); // alignment padding - - const buffer_len = std.mem.readInt(u32, try eatC(&rem, 4), .little); - const buffer = std.mem.bytesAsSlice(StringID, try eat(&rem, buffer_len * @sizeOf(StringID))); - - const requested_modules_len = std.mem.readInt(u32, try eatC(&rem, 4), .little); - const requested_modules_keys = std.mem.bytesAsSlice(StringID, try eat(&rem, requested_modules_len * @sizeOf(StringID))); - const requested_modules_values = std.mem.bytesAsSlice(ModuleInfo.FetchParameters, try eat(&rem, requested_modules_len * @sizeOf(ModuleInfo.FetchParameters))); - - const flags: Flags = @bitCast((try eatC(&rem, 1))[0]); - _ = try eat(&rem, 3); // alignment padding - - const strings_len = std.mem.readInt(u32, try eatC(&rem, 4), .little); - const strings_lens = std.mem.bytesAsSlice(u32, try eat(&rem, strings_len * @sizeOf(u32))); - const strings_buf = rem; - - res.* = .{ - .strings_buf = strings_buf, - .strings_lens = strings_lens, - .requested_modules_keys = requested_modules_keys, - .requested_modules_values = requested_modules_values, - .buffer = buffer, - .record_kinds = record_kinds, - .flags = flags, - .owner = .{ .allocated_slice = .{ - .slice = duped, - .allocator = gpa, - } }, - }; - return res; - } - - /// Wrapper around `create` for use when loading from a cache (transpiler cache or standalone module graph). - /// Returns `null` instead of panicking on corrupt/truncated data. - pub fn createFromCachedRecord(source: []const u8, gpa: std.mem.Allocator) ?*ModuleInfoDeserialized { - return create(source, gpa) catch |e| switch (e) { - error.OutOfMemory => bun.outOfMemory(), - error.BadModuleInfo => null, - }; - } - - pub fn serialize(self: *const ModuleInfoDeserialized, writer: anytype) !void { - try writer.writeInt(u32, @truncate(self.record_kinds.len), .little); - try writer.writeAll(std.mem.sliceAsBytes(self.record_kinds)); - try writer.writeByteNTimes(0, (4 - (self.record_kinds.len % 4)) % 4); // alignment padding - - try writer.writeInt(u32, @truncate(self.buffer.len), .little); - try writer.writeAll(std.mem.sliceAsBytes(self.buffer)); - - try writer.writeInt(u32, @truncate(self.requested_modules_keys.len), .little); - try writer.writeAll(std.mem.sliceAsBytes(self.requested_modules_keys)); - try writer.writeAll(std.mem.sliceAsBytes(self.requested_modules_values)); - - try writer.writeByte(@bitCast(self.flags)); - try writer.writeByteNTimes(0, 3); // alignment padding - - try writer.writeInt(u32, @truncate(self.strings_lens.len), .little); - try writer.writeAll(std.mem.sliceAsBytes(self.strings_lens)); - try writer.writeAll(self.strings_buf); - } -}; - -const StringMapKey = enum(u32) { - _, -}; -pub const StringContext = struct { - strings_buf: []const u8, - strings_lens: []const u32, - - pub fn hash(_: @This(), s: []const u8) u32 { - return @as(u32, @truncate(std.hash.Wyhash.hash(0, s))); - } - pub fn eql(self: @This(), fetch_key: []const u8, item_key: StringMapKey, item_i: usize) bool { - return bun.strings.eqlLong(fetch_key, self.strings_buf[@intFromEnum(item_key)..][0..self.strings_lens[item_i]], true); - } -}; - -pub const ModuleInfo = struct { - /// all strings in wtf-8. index in hashmap = StringID - gpa: std.mem.Allocator, - strings_map: std.ArrayHashMapUnmanaged(StringMapKey, void, void, true), - strings_buf: std.ArrayListUnmanaged(u8), - strings_lens: std.ArrayListUnmanaged(u32), - requested_modules: std.AutoArrayHashMap(StringID, FetchParameters), - buffer: std.ArrayListUnmanaged(StringID), - record_kinds: std.ArrayListUnmanaged(RecordKind), - flags: Flags, - exported_names: std.AutoArrayHashMapUnmanaged(StringID, void), - finalized: bool = false, - - /// only initialized after .finalize() is called - _deserialized: ModuleInfoDeserialized, - - pub fn asDeserialized(self: *ModuleInfo) *ModuleInfoDeserialized { - bun.assert(self.finalized); - return &self._deserialized; - } - - pub const FetchParameters = enum(u32) { - none = std.math.maxInt(u32), - javascript = std.math.maxInt(u32) - 1, - webassembly = std.math.maxInt(u32) - 2, - json = std.math.maxInt(u32) - 3, - _, // host_defined: cast to StringID - pub fn hostDefined(value: StringID) FetchParameters { - return @enumFromInt(@intFromEnum(value)); - } - }; - - pub const VarKind = enum { declared, lexical }; - pub fn addVar(self: *ModuleInfo, name: StringID, kind: VarKind) !void { - switch (kind) { - .declared => try self.addDeclaredVariable(name), - .lexical => try self.addLexicalVariable(name), - } - } - - fn _addRecord(self: *ModuleInfo, kind: RecordKind, data: []const StringID) !void { - bun.assert(!self.finalized); - bun.assert(data.len == kind.len() catch unreachable); - try self.record_kinds.append(self.gpa, kind); - try self.buffer.appendSlice(self.gpa, data); - } - pub fn addDeclaredVariable(self: *ModuleInfo, id: StringID) !void { - try self._addRecord(.declared_variable, &.{id}); - } - pub fn addLexicalVariable(self: *ModuleInfo, id: StringID) !void { - try self._addRecord(.lexical_variable, &.{id}); - } - pub fn addImportInfoSingle(self: *ModuleInfo, module_name: StringID, import_name: StringID, local_name: StringID, only_used_as_type: bool) !void { - try self._addRecord(if (only_used_as_type) .import_info_single_type_script else .import_info_single, &.{ module_name, import_name, local_name }); - } - pub fn addImportInfoNamespace(self: *ModuleInfo, module_name: StringID, local_name: StringID) !void { - try self._addRecord(.import_info_namespace, &.{ module_name, .star_namespace, local_name }); - } - pub fn addExportInfoIndirect(self: *ModuleInfo, export_name: StringID, import_name: StringID, module_name: StringID) !void { - if (try self._hasOrAddExportedName(export_name)) return; // a syntax error will be emitted later in this case - try self._addRecord(.export_info_indirect, &.{ export_name, import_name, module_name }); - } - pub fn addExportInfoLocal(self: *ModuleInfo, export_name: StringID, local_name: StringID) !void { - if (try self._hasOrAddExportedName(export_name)) return; // a syntax error will be emitted later in this case - try self._addRecord(.export_info_local, &.{ export_name, local_name, @enumFromInt(std.math.maxInt(u32)) }); - } - pub fn addExportInfoNamespace(self: *ModuleInfo, export_name: StringID, module_name: StringID) !void { - if (try self._hasOrAddExportedName(export_name)) return; // a syntax error will be emitted later in this case - try self._addRecord(.export_info_namespace, &.{ export_name, module_name }); - } - pub fn addExportInfoStar(self: *ModuleInfo, module_name: StringID) !void { - try self._addRecord(.export_info_star, &.{module_name}); - } - - pub fn _hasOrAddExportedName(self: *ModuleInfo, name: StringID) !bool { - if (try self.exported_names.fetchPut(self.gpa, name, {}) != null) return true; - return false; - } - - pub fn create(gpa: std.mem.Allocator, is_typescript: bool) !*ModuleInfo { - const res = try gpa.create(ModuleInfo); - res.* = ModuleInfo.init(gpa, is_typescript); - return res; - } - fn init(allocator: std.mem.Allocator, is_typescript: bool) ModuleInfo { - return .{ - .gpa = allocator, - .strings_map = .{}, - .strings_buf = .{}, - .strings_lens = .{}, - .exported_names = .{}, - .requested_modules = std.AutoArrayHashMap(StringID, FetchParameters).init(allocator), - .buffer = .empty, - .record_kinds = .empty, - .flags = .{ .contains_import_meta = false, .is_typescript = is_typescript }, - ._deserialized = undefined, - }; - } - fn deinit(self: *ModuleInfo) void { - self.strings_map.deinit(self.gpa); - self.strings_buf.deinit(self.gpa); - self.strings_lens.deinit(self.gpa); - self.exported_names.deinit(self.gpa); - self.requested_modules.deinit(); - self.buffer.deinit(self.gpa); - self.record_kinds.deinit(self.gpa); - } - pub fn destroy(self: *ModuleInfo) void { - const alloc = self.gpa; - self.deinit(); - alloc.destroy(self); - } - pub fn str(self: *ModuleInfo, value: []const u8) !StringID { - try self.strings_buf.ensureUnusedCapacity(self.gpa, value.len); - try self.strings_lens.ensureUnusedCapacity(self.gpa, 1); - const gpres = try self.strings_map.getOrPutAdapted(self.gpa, value, StringContext{ - .strings_buf = self.strings_buf.items, - .strings_lens = self.strings_lens.items, - }); - if (gpres.found_existing) return @enumFromInt(@as(u32, @intCast(gpres.index))); - - gpres.key_ptr.* = @enumFromInt(@as(u32, @truncate(self.strings_buf.items.len))); - gpres.value_ptr.* = {}; - self.strings_buf.appendSliceAssumeCapacity(value); - self.strings_lens.appendAssumeCapacity(@as(u32, @truncate(value.len))); - return @enumFromInt(@as(u32, @intCast(gpres.index))); - } - pub fn requestModule(self: *ModuleInfo, import_record_path: StringID, fetch_parameters: FetchParameters) !void { - // jsc only records the attributes of the first import with the given import_record_path. so only put if not exists. - const gpres = try self.requested_modules.getOrPut(import_record_path); - if (!gpres.found_existing) gpres.value_ptr.* = fetch_parameters; - } - - /// Replace all occurrences of old_id with new_id in records and requested_modules. - /// Used to fix up cross-chunk import specifiers after final paths are computed. - pub fn replaceStringID(self: *ModuleInfo, old_id: StringID, new_id: StringID) void { - bun.assert(!self.finalized); - // Replace in record buffer - for (self.buffer.items) |*item| { - if (item.* == old_id) item.* = new_id; - } - // Replace in requested_modules keys (preserving insertion order) - if (self.requested_modules.getIndex(old_id)) |idx| { - self.requested_modules.keys()[idx] = new_id; - self.requested_modules.reIndex() catch {}; - } - } - - /// find any exports marked as 'local' that are actually 'indirect' and fix them - pub fn finalize(self: *ModuleInfo) !void { - bun.assert(!self.finalized); - var local_name_to_module_name = std.AutoArrayHashMap(StringID, struct { module_name: StringID, import_name: StringID, record_kinds_idx: usize, is_namespace: bool }).init(bun.default_allocator); - defer local_name_to_module_name.deinit(); - { - var i: usize = 0; - for (self.record_kinds.items, 0..) |k, idx| { - if (k == .import_info_single or k == .import_info_single_type_script) { - try local_name_to_module_name.put(self.buffer.items[i + 2], .{ .module_name = self.buffer.items[i], .import_name = self.buffer.items[i + 1], .record_kinds_idx = idx, .is_namespace = false }); - } else if (k == .import_info_namespace) { - try local_name_to_module_name.put(self.buffer.items[i + 2], .{ .module_name = self.buffer.items[i], .import_name = .star_namespace, .record_kinds_idx = idx, .is_namespace = true }); - } - i += k.len() catch unreachable; - } - } - - { - var i: usize = 0; - for (self.record_kinds.items) |*k| { - if (k.* == .export_info_local) { - if (local_name_to_module_name.get(self.buffer.items[i + 1])) |ip| { - // `import * as z from M; export { z }` is a Namespace export per - // spec; encode it as indirect with import_name = .star_namespace - // so the record stays the same length and toJSModuleRecord - // dispatches to addNamespaceExport. - k.* = .export_info_indirect; - self.buffer.items[i + 1] = ip.import_name; - self.buffer.items[i + 2] = ip.module_name; - // In TypeScript, the re-exported import may target a type-only - // export that was elided. Convert the import to SingleTypeScript - // so JSC tolerates it being NotFound during linking. - if (!ip.is_namespace and self.flags.is_typescript) { - self.record_kinds.items[ip.record_kinds_idx] = .import_info_single_type_script; - } - } - } - i += k.len() catch unreachable; - } - } - - self._deserialized = .{ - .strings_buf = self.strings_buf.items, - .strings_lens = self.strings_lens.items, - .requested_modules_keys = self.requested_modules.keys(), - .requested_modules_values = self.requested_modules.values(), - .buffer = self.buffer.items, - .record_kinds = self.record_kinds.items, - .flags = self.flags, - .owner = .module_info, - }; - - self.finalized = true; - } -}; -pub const StringID = enum(u32) { - star_default = std.math.maxInt(u32), - star_namespace = std.math.maxInt(u32) - 1, - _, -}; - -// zig__renderDiff, zig__ModuleInfoDeserialized__toJSModuleRecord, and the -// JSModuleRecord/IdentifierArray opaques: see src/bundler_jsc/analyze_jsc.zig -comptime { - _ = @import("../bundler_jsc/analyze_jsc.zig"); -} - -export fn zig__ModuleInfo__destroy(info: *ModuleInfo) void { - info.destroy(); -} -export fn zig__ModuleInfoDeserialized__deinit(info: *ModuleInfoDeserialized) void { - info.deinit(); -} - -export fn zig_log(msg: [*:0]const u8) void { - bun.Output.errorWriter().print("{s}\n", .{std.mem.span(msg)}) catch {}; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/bundler/barrel_imports.zig b/src/bundler/barrel_imports.zig deleted file mode 100644 index 80233a079281..000000000000 --- a/src/bundler/barrel_imports.zig +++ /dev/null @@ -1,562 +0,0 @@ -//! Barrel optimization: detect pure re-export barrel files and defer loading -//! of unused submodules. Uses a persistent `requested_exports` map to track -//! which exports have been requested from each barrel, providing cross-call -//! deduplication and cycle detection (inspired by Rolldown's pattern). -//! -//! Import requests are recorded eagerly as each file is processed — before -//! barrels are known. When a barrel later loads, applyBarrelOptimization reads -//! `requested_exports` to see what's already been requested. No graph scan needed. - -const log = Output.scoped(.barrel, .hidden); - -pub const RequestedExports = union(enum) { - all, - partial: bun.StringArrayHashMapUnmanaged(void), -}; - -const BarrelExportResolution = struct { - import_record_index: u32, - /// The original alias in the source module (e.g. "d" for `export { d as c }`) - original_alias: ?[]const u8, - /// True when the underlying import is `import * as ns` — propagation - /// through this export must treat the target as needing all exports. - alias_is_star: bool, -}; - -/// Look up an export name → import_record_index by chasing -/// named_exports[alias].ref through named_imports. -/// Also returns the original alias from the source module for BFS propagation. -fn resolveBarrelExport(alias: []const u8, named_exports: JSAst.NamedExports, named_imports: JSAst.NamedImports) ?BarrelExportResolution { - const export_entry = named_exports.get(alias) orelse return null; - const import_entry = named_imports.get(export_entry.ref) orelse return null; - return .{ .import_record_index = import_entry.import_record_index, .original_alias = import_entry.alias, .alias_is_star = import_entry.alias_is_star }; -} - -/// Analyze a parsed file to determine if it's a barrel and mark unneeded -/// import records as is_unused so they won't be resolved. Runs BEFORE resolution. -/// -/// A file qualifies as a barrel if: -/// 1. It has `sideEffects: false` or is in `optimize_imports`, AND -/// 2. All named exports are re-exports (no local definitions), AND -/// 3. It is not an export star target of another barrel. -/// -/// Export * records are never deferred (always resolved) to avoid circular races. -pub fn applyBarrelOptimization(this: *BundleV2, parse_result: *ParseTask.Result) void { - bun.handleOom(applyBarrelOptimizationImpl(this, parse_result)); -} - -fn applyBarrelOptimizationImpl(this: *BundleV2, parse_result: *ParseTask.Result) !void { - const result = &parse_result.value.success; - const ast = &result.ast; - const source_index = result.source.index.get(); - - const is_explicit = if (this.transpiler.options.optimize_imports) |oi| oi.map.contains(result.package_name) else false; - const is_side_effects_false = result.side_effects == .no_side_effects__package_json; - if (!is_explicit and !is_side_effects_false) return; - if (ast.import_records.len == 0) return; - if (ast.named_exports.count() == 0 and ast.export_star_import_records.len == 0) return; - - const named_exports = ast.named_exports; - const named_imports = ast.named_imports; - - // Verify pure barrel: all named exports must be re-exports - var export_iter = named_exports.iterator(); - while (export_iter.next()) |entry| { - if (named_imports.get(entry.value_ptr.ref) == null) return; - } - - // If this barrel is a star target of another barrel, can't safely defer - if (this.graph.input_files.items(.flags)[source_index].is_export_star_target) return; - - // Check requested_exports to see which exports were already requested by - // files parsed before this barrel. scheduleBarrelDeferredImports records - // requests eagerly as each file is processed, so we don't need to scan - // the graph. - if (this.requested_exports.get(source_index)) |existing| { - switch (existing) { - .all => return, // import * already seen — load everything - .partial => {}, - } - } - - // Build the set of needed import_record_indices from already-requested - // export names. Export * records are always needed. - var needed_records_stack = std.heap.stackFallback(8192, this.allocator()); - const needed_records_alloc = needed_records_stack.get(); - var needed_records = std.AutoArrayHashMapUnmanaged(u32, void){}; - defer needed_records.deinit(needed_records_alloc); - - for (ast.export_star_import_records) |record_idx| { - try needed_records.put(needed_records_alloc, record_idx, {}); - } - - if (this.requested_exports.get(source_index)) |existing| { - switch (existing) { - .all => unreachable, // handled above - .partial => |partial| { - var partial_iter = partial.iterator(); - while (partial_iter.next()) |p_entry| { - if (resolveBarrelExport(p_entry.key_ptr.*, named_exports, named_imports)) |resolution| { - try needed_records.put(needed_records_alloc, resolution.import_record_index, {}); - } - } - }, - } - } - - // Dev server: also include exports persisted from previous builds. This - // handles the case where file A imports Alpha from the barrel (previous - // build) and file B adds Beta (current build). Without this, Alpha would - // be re-deferred because only B's requests are in requested_exports. - if (this.transpiler.options.dev_server) |dev| { - if (dev.barrel_needed_exports.get(result.source.path.text)) |persisted| { - var persisted_iter = persisted.keyIterator(); - while (persisted_iter.next()) |alias_ptr| { - if (resolveBarrelExport(alias_ptr.*, named_exports, named_imports)) |resolution| { - try needed_records.put(needed_records_alloc, resolution.import_record_index, {}); - } - } - } - } - - // When HMR is active, ConvertESMExportsForHmr deduplicates import records - // by path — two `export { ... } from './utils.js'` blocks get merged into - // one record. The surviving record might be the one barrel optimization - // would mark as unused (its exports not needed), while the other record - // (whose exports ARE needed) gets marked unused by HMR dedup. To prevent - // both records from ending up unused, promote needed_records to cover ALL - // import records that share a path with any needed record. - if (this.transpiler.options.dev_server != null) { - // Collect paths of needed records. - var needed_paths_stack = std.heap.stackFallback(4096, this.allocator()); - const needed_paths_alloc = needed_paths_stack.get(); - var needed_paths = bun.StringArrayHashMapUnmanaged(void){}; - defer needed_paths.deinit(needed_paths_alloc); - - for (needed_records.keys()) |rec_idx| { - if (rec_idx < ast.import_records.len) { - try needed_paths.put(needed_paths_alloc, ast.import_records.slice()[rec_idx].path.text, {}); - } - } - - // Add all records sharing a needed path to the needed set. - export_iter = named_exports.iterator(); - while (export_iter.next()) |entry| { - if (named_imports.get(entry.value_ptr.ref)) |imp| { - if (imp.import_record_index < ast.import_records.len) { - if (needed_paths.contains(ast.import_records.slice()[imp.import_record_index].path.text)) { - try needed_records.put(needed_records_alloc, imp.import_record_index, {}); - } - } - } - } - } - - // Mark unneeded named re-export records as is_unused. - var has_deferrals = false; - export_iter = named_exports.iterator(); - while (export_iter.next()) |entry| { - if (named_imports.get(entry.value_ptr.ref)) |imp| { - if (!needed_records.contains(imp.import_record_index)) { - if (imp.import_record_index < ast.import_records.len) { - ast.import_records.slice()[imp.import_record_index].flags.is_unused = true; - has_deferrals = true; - } - } - } - } - - if (has_deferrals) { - log("barrel detected: {s} (source={d}, {d} deferred, {d} needed)", .{ - if (result.package_name.len > 0) result.package_name else result.source.path.text, - source_index, - named_exports.count() -| needed_records.count(), - needed_records.count(), - }); - - // Merge with existing entry (keep already-requested names) or create new - const gop = try this.requested_exports.getOrPut(this.allocator(), source_index); - if (!gop.found_existing) { - gop.value_ptr.* = .{ .partial = .{} }; - } - - // Register with DevServer so isFileCached returns null for this barrel, - // ensuring it gets re-parsed on every incremental build. This is needed - // because the set of needed exports can change when importing files change. - if (this.transpiler.options.dev_server) |dev| { - const alloc = dev.allocator(); - const barrel_gop = try dev.barrel_files_with_deferrals.getOrPut(alloc, result.source.path.text); - if (!barrel_gop.found_existing) { - barrel_gop.key_ptr.* = try alloc.dupe(u8, result.source.path.text); - } - } - } -} - -/// Clear is_unused on a deferred barrel record. Returns true if the record was un-deferred. -fn unDeferRecord(import_records: *ImportRecord.List, record_idx: u32) bool { - if (record_idx >= import_records.len) return false; - const rec = &import_records.slice()[record_idx]; - if (rec.flags.is_internal or !rec.flags.is_unused) return false; - rec.flags.is_unused = false; - return true; -} - -/// BFS work queue item: un-defer an export from a barrel. -const BarrelWorkItem = struct { barrel_source_index: u32, alias: []const u8, is_star: bool }; - -/// Resolve, process, and patch import records for a single barrel. -/// Used to inline-resolve deferred records whose source_index is still invalid. -fn resolveBarrelRecords(this: *BundleV2, barrel_idx: u32, barrels_to_resolve: *std.AutoArrayHashMapUnmanaged(u32, void)) i32 { - const graph_ast = this.graph.ast.slice(); - const barrel_ir = &graph_ast.items(.import_records)[barrel_idx]; - const target = graph_ast.items(.target)[barrel_idx]; - var resolve_result = this.resolveImportRecords(.{ - .import_records = barrel_ir, - .source = &this.graph.input_files.items(.source)[barrel_idx], - .loader = this.graph.input_files.items(.loader)[barrel_idx], - .target = target, - }); - defer resolve_result.resolve_queue.deinit(); - const scheduled = this.processResolveQueue(resolve_result.resolve_queue, target, barrel_idx); - // Re-derive pointer after processResolveQueue may have reallocated graph.ast - const barrel_ir_updated = &this.graph.ast.slice().items(.import_records)[barrel_idx]; - this.patchImportRecordSourceIndices(barrel_ir_updated, .{ - .source_index = Index.init(barrel_idx), - .source_path = this.graph.input_files.items(.source)[barrel_idx].path.text, - .loader = this.graph.input_files.items(.loader)[barrel_idx], - .target = target, - .force_save = true, - }); - _ = barrels_to_resolve.swapRemove(barrel_idx); - return scheduled; -} - -/// After a new file's import records are patched with source_indices, -/// record what this file requests from each target in requested_exports -/// (eagerly, before barrels are known), then BFS through barrel chains -/// to un-defer needed records. Un-deferred records are re-resolved through -/// resolveImportRecords (same path as initial resolution). -/// Returns the number of newly scheduled parse tasks. -pub fn scheduleBarrelDeferredImports(this: *BundleV2, result: *ParseTask.Result.Success) !i32 { - const file_import_records = result.ast.import_records; - - // Phase 1: Seed — eagerly record what this file requests from each target. - // This runs for every file, even before any barrels are known. When a barrel - // is later parsed, applyBarrelOptimization reads these pre-recorded requests - // to decide which exports to keep. O(file's imports) per file. - - // Build a set of import_record_indices that have named_imports entries, - // so we can detect bare imports (those with no specific export bindings). - var named_ir_indices_stack = std.heap.stackFallback(4096, this.allocator()); - const named_ir_indices_alloc = named_ir_indices_stack.get(); - var named_ir_indices = std.AutoArrayHashMapUnmanaged(u32, void){}; - defer named_ir_indices.deinit(named_ir_indices_alloc); - - // In dev server mode, patchImportRecordSourceIndices skips saving source_indices - // on import records (the dev server uses path-based identifiers instead). But - // barrel optimization requires source_indices to seed requested_exports and to - // BFS un-defer records. Resolve paths → source_indices here as a fallback. - const path_to_source_index_map = if (this.transpiler.options.dev_server != null) - this.pathToSourceIndexMap(result.ast.target) - else - null; - - // In HMR, ConvertESMExportsForHmr deduplicates import records by path: - // two `import { X } from 'mod'` statements become one, and the second - // record is marked is_unused=true. resolveImportRecords then skips those - // records, so their path.text stays as the raw specifier while the - // surviving record's path.text becomes the resolved absolute path. - // named_imports entries created for the dedup'd record still point at - // its index, so the direct path lookup below fails for those entries. - // Build a fallback: raw specifier → surviving record's resolved path - // text, using non-unused records in this file. See #28886. - var dedup_fallback = bun.StringArrayHashMapUnmanaged([]const u8){}; - defer dedup_fallback.deinit(this.allocator()); - if (this.transpiler.options.dev_server != null) { - for (file_import_records.slice()) |ir_probe| { - if (ir_probe.flags.is_unused or ir_probe.flags.is_internal) continue; - if (ir_probe.original_path.len == 0) continue; - if (bun.strings.eql(ir_probe.original_path, ir_probe.path.text)) continue; - try dedup_fallback.put(this.allocator(), ir_probe.original_path, ir_probe.path.text); - } - } - - var ni_iter = result.ast.named_imports.iterator(); - while (ni_iter.next()) |ni_entry| { - const ni = ni_entry.value_ptr; - if (ni.import_record_index >= file_import_records.len) continue; - try named_ir_indices.put(named_ir_indices_alloc, ni.import_record_index, {}); - const ir = file_import_records.slice()[ni.import_record_index]; - // In dev server mode, source_index may not be patched — resolve via - // path map as a read-only fallback. Do NOT write back to the import - // record — the dev server intentionally leaves source_indices unset - // and other code (IncrementalGraph, printer) depends on that. - // For dedup'd HMR records (is_unused), fall back to a sibling's - // resolved path text since the record itself still has the raw - // specifier in path.text. - const resolved_path_text = if (ir.flags.is_unused) - (dedup_fallback.get(ir.path.text) orelse ir.path.text) - else - ir.path.text; - const target = if (ir.source_index.isValid()) - ir.source_index.get() - else if (path_to_source_index_map) |map| - map.get(resolved_path_text) orelse continue - else - continue; - - const gop = try this.requested_exports.getOrPut(this.allocator(), target); - if (ni.alias_is_star) { - gop.value_ptr.* = .all; - } else if (ni.alias) |alias| { - if (gop.found_existing) { - switch (gop.value_ptr.*) { - .all => {}, - .partial => |*p| try p.put(this.allocator(), alias, {}), - } - } else { - gop.value_ptr.* = .{ .partial = .{} }; - try gop.value_ptr.partial.put(this.allocator(), alias, {}); - } - // Persist the export request on DevServer so it survives across builds. - if (this.transpiler.options.dev_server) |dev| { - persistBarrelExport(dev, resolved_path_text, alias); - } - } else if (!gop.found_existing) { - gop.value_ptr.* = .{ .partial = .{} }; - } - } - - // Handle import records without named bindings (not in named_imports). - // - `import "x"` (bare statement): tree-shakeable with sideEffects: false — skip. - // - `require("x")`: synchronous, needs full module — always mark as .all. - // - `import("x")`: returns the full module namespace at runtime — consumer - // can destructure or access any export. Must mark as .all. We cannot - // safely assume which exports will be used. - for (file_import_records.slice(), 0..) |ir, idx| { - const target = if (ir.source_index.isValid()) - ir.source_index.get() - else if (path_to_source_index_map) |map| - map.getPath(&ir.path) orelse continue - else - continue; - if (ir.flags.is_internal) continue; - if (named_ir_indices.contains(@intCast(idx))) continue; - if (ir.flags.was_originally_bare_import) continue; - if (ir.kind == .require) { - const gop = try this.requested_exports.getOrPut(this.allocator(), target); - gop.value_ptr.* = .all; - } else if (ir.kind == .dynamic) { - // import() returns the full module namespace — must preserve all exports. - const gop = try this.requested_exports.getOrPut(this.allocator(), target); - gop.value_ptr.* = .all; - } - } - - // Phase 2: BFS — un-defer barrel records that are now needed. - // Build work queue from this file's named_imports, then propagate - // through chains of barrels. Only runs real work when barrels exist - // (targets with deferred records). - var queue_stack = std.heap.stackFallback(8192, this.allocator()); - const queue_alloc = queue_stack.get(); - var queue = std.ArrayListUnmanaged(BarrelWorkItem){}; - defer queue.deinit(queue_alloc); - - ni_iter = result.ast.named_imports.iterator(); - while (ni_iter.next()) |ni_entry| { - const ni = ni_entry.value_ptr; - if (ni.import_record_index >= file_import_records.len) continue; - const ir = file_import_records.slice()[ni.import_record_index]; - const resolved_path_text = if (ir.flags.is_unused) - (dedup_fallback.get(ir.path.text) orelse ir.path.text) - else - ir.path.text; - const ir_target = if (ir.source_index.isValid()) - ir.source_index.get() - else if (path_to_source_index_map) |map| - map.get(resolved_path_text) orelse continue - else - continue; - - if (ni.alias_is_star) { - try queue.append(queue_alloc, .{ .barrel_source_index = ir_target, .alias = "", .is_star = true }); - } else if (ni.alias) |alias| { - try queue.append(queue_alloc, .{ .barrel_source_index = ir_target, .alias = alias, .is_star = false }); - } - } - - // Add bare require/dynamic-import targets to BFS as star imports — both - // always need the full namespace. - for (file_import_records.slice(), 0..) |ir, idx| { - const target = if (ir.source_index.isValid()) - ir.source_index.get() - else if (path_to_source_index_map) |map| - map.getPath(&ir.path) orelse continue - else - continue; - if (ir.flags.is_internal) continue; - if (named_ir_indices.contains(@intCast(idx))) continue; - if (ir.flags.was_originally_bare_import) continue; - const should_add = ir.kind == .require or ir.kind == .dynamic; - if (should_add) { - try queue.append(queue_alloc, .{ .barrel_source_index = target, .alias = "", .is_star = true }); - } - } - - // Also seed the BFS with exports previously requested from THIS file - // that couldn't propagate because this file wasn't parsed yet. - // This handles the case where file A requests export "d" from file B, - // but B hadn't been parsed when A's BFS ran, so B's export * records - // were empty and the propagation stopped. - const this_source_index = result.source.index.get(); - if (this.requested_exports.get(this_source_index)) |existing| { - switch (existing) { - .all => try queue.append(queue_alloc, .{ .barrel_source_index = this_source_index, .alias = "", .is_star = true }), - .partial => |partial| { - var partial_iter = partial.iterator(); - while (partial_iter.next()) |p_entry| { - try queue.append(queue_alloc, .{ .barrel_source_index = this_source_index, .alias = p_entry.key_ptr.*, .is_star = false }); - } - }, - } - } - - if (queue.items.len == 0) return 0; - - // Items [0, initial_queue_len) are from this file's imports and were - // already recorded in requested_exports during seeding (phase 1). - // Skip dedup for them so un-deferral proceeds correctly. - // Items added during BFS propagation (>= initial_queue_len) use normal - // dedup via requested_exports to prevent cycles. - const initial_queue_len = queue.items.len; - - var barrels_to_resolve = std.AutoArrayHashMapUnmanaged(u32, void){}; - var barrels_to_resolve_stack = std.heap.stackFallback(1024, this.allocator()); - const barrels_to_resolve_alloc = barrels_to_resolve_stack.get(); - defer barrels_to_resolve.deinit(barrels_to_resolve_alloc); - - var newly_scheduled: i32 = 0; - var qi: usize = 0; - while (qi < queue.items.len) : (qi += 1) { - const item = queue.items[qi]; - const barrel_idx = item.barrel_source_index; - - // For BFS-propagated items (not from initial queue), use - // requested_exports for dedup and cycle detection. - if (qi >= initial_queue_len) { - const gop = try this.requested_exports.getOrPut(this.allocator(), barrel_idx); - if (item.is_star) { - gop.value_ptr.* = .all; - } else if (gop.found_existing) { - switch (gop.value_ptr.*) { - .all => continue, - .partial => |*p| { - const alias_gop = try p.getOrPut(this.allocator(), item.alias); - if (alias_gop.found_existing) continue; - }, - } - } else { - gop.value_ptr.* = .{ .partial = .{} }; - try gop.value_ptr.partial.put(this.allocator(), item.alias, {}); - } - } - - if (barrel_idx >= this.graph.ast.len) continue; - - // Use a helper to get barrel_ir freshly each time, since - // resolveBarrelRecords can reallocate graph.ast and invalidate pointers. - var barrel_ir = &this.graph.ast.slice().items(.import_records)[barrel_idx]; - - if (item.is_star) { - for (barrel_ir.slice(), 0..) |rec, idx| { - if (rec.flags.is_unused and !rec.flags.is_internal) { - if (unDeferRecord(barrel_ir, @intCast(idx))) { - try barrels_to_resolve.put(barrels_to_resolve_alloc, barrel_idx, {}); - } - } - } - continue; - } - - const alias = item.alias; - const graph_ast_snapshot = this.graph.ast.slice(); - const resolution = resolveBarrelExport(alias, graph_ast_snapshot.items(.named_exports)[barrel_idx], graph_ast_snapshot.items(.named_imports)[barrel_idx]) orelse { - // Name not in named re-exports — might come from export *. - for (graph_ast_snapshot.items(.export_star_import_records)[barrel_idx]) |star_idx| { - if (star_idx >= barrel_ir.len) continue; - if (unDeferRecord(barrel_ir, star_idx)) { - try barrels_to_resolve.put(barrels_to_resolve_alloc, barrel_idx, {}); - } - var star_rec = barrel_ir.slice()[star_idx]; - if (!star_rec.source_index.isValid()) { - // Deferred record was never resolved — resolve inline now. - newly_scheduled += resolveBarrelRecords(this, barrel_idx, &barrels_to_resolve); - // Re-derive pointer after resolution may have mutated slices. - barrel_ir = &this.graph.ast.slice().items(.import_records)[barrel_idx]; - star_rec = barrel_ir.slice()[star_idx]; - } - if (star_rec.source_index.isValid()) { - try queue.append(queue_alloc, .{ .barrel_source_index = star_rec.source_index.get(), .alias = alias, .is_star = false }); - } - } - continue; - }; - - if (unDeferRecord(barrel_ir, resolution.import_record_index)) { - try barrels_to_resolve.put(barrels_to_resolve_alloc, barrel_idx, {}); - } - - const propagate_alias = resolution.original_alias orelse alias; - if (resolution.import_record_index < barrel_ir.len) { - var rec = barrel_ir.slice()[resolution.import_record_index]; - if (!rec.source_index.isValid()) { - // Deferred record was never resolved — resolve inline now. - newly_scheduled += resolveBarrelRecords(this, barrel_idx, &barrels_to_resolve); - barrel_ir = &this.graph.ast.slice().items(.import_records)[barrel_idx]; - rec = barrel_ir.slice()[resolution.import_record_index]; - } - if (rec.source_index.isValid()) { - // When the barrel re-exports a namespace import (`import * as X; export { X }`), - // propagate as a star import so the target barrel loads all exports. - try queue.append(queue_alloc, .{ .barrel_source_index = rec.source_index.get(), .alias = propagate_alias, .is_star = resolution.alias_is_star }); - } - } - } - - // Re-resolve any remaining un-deferred records through the normal resolution path. - while (barrels_to_resolve.count() > 0) { - const barrel_source_index = barrels_to_resolve.keys()[0]; - newly_scheduled += resolveBarrelRecords(this, barrel_source_index, &barrels_to_resolve); - } - - return newly_scheduled; -} - -/// Persist an export name for a barrel file on the DevServer. Called during -/// seeding so that exports requested in previous builds are not lost when the -/// barrel is re-parsed in an incremental build where the requesting file is -/// not stale. -fn persistBarrelExport(dev: *bun.bake.DevServer, barrel_path: []const u8, alias: []const u8) void { - const alloc = dev.allocator(); - const outer_gop = dev.barrel_needed_exports.getOrPut(alloc, barrel_path) catch return; - if (!outer_gop.found_existing) { - outer_gop.key_ptr.* = alloc.dupe(u8, barrel_path) catch return; - outer_gop.value_ptr.* = .{}; - } - const inner_gop = outer_gop.value_ptr.getOrPut(alloc, alias) catch return; - if (!inner_gop.found_existing) { - inner_gop.key_ptr.* = alloc.dupe(u8, alias) catch return; - } -} - -const std = @import("std"); -const BundleV2 = @import("./bundle_v2.zig").BundleV2; -const ParseTask = @import("./ParseTask.zig").ParseTask; - -const bun = @import("bun"); -const ImportRecord = bun.ImportRecord; -const Output = bun.Output; - -const Index = bun.ast.Index; -const JSAst = bun.ast.BundledAst; diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig deleted file mode 100644 index d12d0998a285..000000000000 --- a/src/bundler/bundle_v2.zig +++ /dev/null @@ -1,4509 +0,0 @@ -// This is Bun's JavaScript/TypeScript bundler -// -// A lot of the implementation is based on the Go implementation of esbuild. Thank you Evan Wallace. -// -// # Memory management -// -// Zig is not a managed language, so we have to be careful about memory management. -// Manually freeing memory is error-prone and tedious, but garbage collection -// is slow and reference counting incurs a performance penalty. -// -// Bun's bundler relies on mimalloc's threadlocal heaps as arena allocators. -// -// When a new thread is spawned for a bundling job, it is given a threadlocal -// heap and all allocations are done on that heap. When the job is done, the -// threadlocal heap is destroyed and all memory is freed. -// -// There are a few careful gotchas to keep in mind: -// -// - A threadlocal heap cannot allocate memory on a different thread than the one that -// created it. You will get a segfault if you try to do that. -// -// - Since the heaps are destroyed at the end of bundling, any globally shared -// references to data must NOT be allocated on a threadlocal heap. -// -// For example, package.json and tsconfig.json read from the filesystem must be -// use the global allocator (bun.default_allocator) because bun's directory -// entry cache and module resolution cache are globally shared across all -// threads. -// -// Additionally, `LinkerContext`'s allocator is also threadlocal. -// -// - Globally allocated data must be in a cache & reused, or we will create an infinite -// memory leak over time. To do that, we have a DirnameStore, FilenameStore, and the other -// data structures related to `BSSMap`. This still leaks memory, but not very -// much since it only allocates the first time around. -// -// -// In development, it is strongly recommended to use either a debug build of -// mimalloc or Valgrind to help catch memory issues -// To use a debug build of mimalloc: -// -// make mimalloc-debug -// - -pub const logPartDependencyTree = Output.scoped(.part_dep_tree, .visible); - -pub const MangledProps = std.AutoArrayHashMapUnmanaged(Ref, []const u8); -pub const PathToSourceIndexMap = @import("./PathToSourceIndexMap.zig"); - -pub const Watcher = bun.jsc.hot_reloader.NewHotReloader(BundleV2, EventLoop, true); - -/// This assigns a concise, predictable, and unique `.pretty` attribute to a Path. -/// DevServer relies on pretty paths for identifying modules, so they must be unique. -pub fn genericPathWithPrettyInitialized(path: Fs.Path, target: options.Target, top_level_dir: string, allocator: std.mem.Allocator) !Fs.Path { - const buf = bun.path_buffer_pool.get(); - defer bun.path_buffer_pool.put(buf); - - const is_node = bun.strings.eqlComptime(path.namespace, "node"); - if (is_node and - (bun.strings.hasPrefixComptime(path.text, NodeFallbackModules.import_path) or - !std.fs.path.isAbsolute(path.text))) - { - return path; - } - - // "file" namespace should use the relative file path for its display name. - // the "node" namespace is also put through this code path so that the - // "node:" prefix is not emitted. - if (path.isFile() or is_node) { - const buf2 = if (target == .bake_server_components_ssr) bun.path_buffer_pool.get() else buf; - defer if (target == .bake_server_components_ssr) bun.path_buffer_pool.put(buf2); - const rel = bun.path.relativePlatformBuf(buf2, top_level_dir, path.text, .loose, false); - var path_clone = path; - // stack-allocated temporary is not leaked because dupeAlloc on the path will - // move .pretty into the heap. that function also fixes some slash issues. - if (target == .bake_server_components_ssr) { - // the SSR graph needs different pretty names or else HMR mode will - // confuse the two modules. - path_clone.pretty = std.fmt.bufPrint(buf, "ssr:{s}", .{rel}) catch buf[0..]; - } else { - path_clone.pretty = rel; - } - return path_clone.dupeAllocFixPretty(allocator); - } else { - // in non-file namespaces, standard filesystem rules do not apply. - var path_clone = path; - path_clone.pretty = std.fmt.bufPrint(buf, "{s}{f}:{s}", .{ - if (target == .bake_server_components_ssr) "ssr:" else "", - // make sure that a namespace including a colon wont collide with anything - std.fmt.Alt([]const u8, fmtEscapedNamespace){ .data = path.namespace }, - path.text, - }) catch buf[0..]; - return path_clone.dupeAllocFixPretty(allocator); - } -} - -fn fmtEscapedNamespace(slice: []const u8, w: *std.Io.Writer) !void { - var rest = slice; - while (bun.strings.indexOfChar(rest, ':')) |i| { - try w.writeAll(rest[0..i]); - try w.writeAll("::"); - rest = rest[i + 1 ..]; - } - try w.writeAll(rest); -} - -pub const BundleV2 = struct { - transpiler: *Transpiler, - /// When Server Component is enabled, this is used for the client bundles - /// and `transpiler` is used for the server bundles. - client_transpiler: ?*Transpiler, - /// See bake.Framework.ServerComponents.separate_ssr_graph - ssr_transpiler: *Transpiler, - /// When Bun Bake is used, the resolved framework is passed here - framework: ?bake.Framework, - graph: Graph, - linker: LinkerContext, - bun_watcher: ?*bun.Watcher, - plugins: ?*jsc.API.JSBundler.Plugin, - completion: ?*JSBundleCompletionTask, - /// In-memory files that can be used as entrypoints or imported. - /// This is a pointer to the FileMap in the completion config. - file_map: ?*const jsc.API.JSBundler.FileMap, - source_code_length: usize, - - /// There is a race condition where an onResolve plugin may schedule a task on the bundle thread before it's parsing task completes - resolve_tasks_waiting_for_import_source_index: std.AutoArrayHashMapUnmanaged(Index.Int, BabyList(struct { to_source_index: Index, import_record_index: u32 })) = .{}, - - /// Allocations not tracked by a threadlocal heap - free_list: std.array_list.Managed([]const u8) = std.array_list.Managed([]const u8).init(bun.default_allocator), - - /// See the comment in `Chunk.OutputPiece` - unique_key: u64 = 0, - dynamic_import_entry_points: std.AutoArrayHashMap(Index.Int, void) = undefined, - has_on_parse_plugins: bool = false, - - finalizers: std.ArrayListUnmanaged(CacheEntry.ExternalFreeFunction) = .{}, - - drain_defer_task: DeferredBatchTask = .{}, - - /// Set true by DevServer. Currently every usage of the transpiler (Bun.build - /// and `bun build` cli) runs at the top of an event loop. When this is - /// true, a callback is executed after all work is complete. - /// - /// You can find which callbacks are run by looking at the - /// `finishFromBakeDevServer(...)` function here - asynchronous: bool = false, - thread_lock: bun.safety.ThreadLock, - - // if false we can skip TLA validation and propagation - has_any_top_level_await_modules: bool = false, - - /// Barrel optimization: tracks which exports have been requested from each - /// module encountered during barrel BFS. Keys are source_indices. Values - /// track requested export names for deduplication and cycle detection. - /// Persists across calls to scheduleBarrelDeferredImports so cross-file - /// deduplication is free. - requested_exports: std.AutoArrayHashMapUnmanaged(u32, barrel_imports.RequestedExports) = .{}, - - const barrel_imports = @import("./barrel_imports.zig"); - - const BakeOptions = struct { - framework: bake.Framework, - client_transpiler: *Transpiler, - ssr_transpiler: *Transpiler, - plugins: ?*jsc.API.JSBundler.Plugin, - }; - - const debug = Output.scoped(.Bundle, .visible); - - pub inline fn loop(this: *BundleV2) *EventLoop { - return &this.linker.loop; - } - - /// Returns the jsc.EventLoop where plugin callbacks can be queued up on - pub fn jsLoopForPlugins(this: *BundleV2) *jsc.EventLoop { - bun.assert(this.plugins != null); - if (this.completion) |completion| - // From Bun.build - return completion.jsc_event_loop - else switch (this.loop().*) { - // From bake where the loop running the bundle is also the loop - // running the plugins. - .js => |jsc_event_loop| return jsc_event_loop, - // The CLI currently has no jsc event loop; for now, no plugin support - .mini => @panic("No JavaScript event loop for transpiler plugins to run on"), - } - } - - fn ensureClientTranspiler(this: *BundleV2) void { - if (this.client_transpiler == null) { - _ = this.initializeClientTranspiler() catch |e| { - std.debug.panic("Failed to initialize client transpiler: {s}", .{@errorName(e)}); - }; - } - } - - fn initializeClientTranspiler(this: *BundleV2) !*Transpiler { - @branchHint(.cold); - const alloc = this.allocator(); - - const this_transpiler = this.transpiler; - const client_transpiler = try alloc.create(Transpiler); - client_transpiler.* = this_transpiler.*; - client_transpiler.options = this_transpiler.options; - - client_transpiler.options.target = .browser; - client_transpiler.options.main_fields = options.Target.DefaultMainFields.get(options.Target.browser); - client_transpiler.options.conditions = try options.ESMConditions.init( - alloc, - options.Target.browser.defaultConditions(), - false, - &.{}, - ); - - // We need to make sure it has [hash] in the names so we don't get conflicts. - if (this_transpiler.options.compile) { - client_transpiler.options.asset_naming = bun.options.PathTemplate.asset.data; - client_transpiler.options.chunk_naming = bun.options.PathTemplate.chunk.data; - client_transpiler.options.entry_naming = "./[name]-[hash].[ext]"; - - // Use "/" so that asset URLs in HTML are absolute (e.g. "/chunk-abc.js" - // instead of "./chunk-abc.js"). Relative paths break when the HTML is - // served from a nested route like "/foo/". - client_transpiler.options.public_path = "/"; - } - - client_transpiler.setLog(this_transpiler.log); - client_transpiler.setAllocator(alloc); - client_transpiler.linker.resolver = &client_transpiler.resolver; - client_transpiler.macro_context = js_ast.Macro.MacroContext.init(client_transpiler); - const CacheSet = @import("./cache.zig"); - client_transpiler.resolver.caches = CacheSet.Set.init(alloc); - - try client_transpiler.configureDefines(); - client_transpiler.resolver.opts = client_transpiler.options; - client_transpiler.resolver.env_loader = client_transpiler.env; - this.client_transpiler = client_transpiler; - return client_transpiler; - } - - /// Most of the time, accessing .transpiler directly is OK. This is only - /// needed when it is important to distinct between client and server - /// - /// Note that .log, .allocator, and other things are shared - /// between the three transpiler configurations - pub inline fn transpilerForTarget(noalias this: *BundleV2, target: options.Target) *Transpiler { - if (!this.transpiler.options.server_components and this.linker.dev_server == null) { - if (target == .browser and this.transpiler.options.target.isServerSide()) { - return this.client_transpiler orelse this.initializeClientTranspiler() catch |e| { - std.debug.panic("Failed to initialize client transpiler: {s}", .{@errorName(e)}); - }; - } - - return this.transpiler; - } - - return switch (target) { - else => this.transpiler, - .browser => this.client_transpiler.?, - .bake_server_components_ssr => this.ssr_transpiler, - }; - } - - /// By calling this function, it implies that the returned log *will* be - /// written to. For DevServer, this allocates a per-file log for the sources - /// it is called on. Function must be called on the bundle thread. - pub fn logForResolutionFailures(this: *BundleV2, abs_path: []const u8, bake_graph: bake.Graph) *bun.logger.Log { - if (this.transpiler.options.dev_server) |dev| { - return bun.handleOom(dev.getLogForResolutionFailures(abs_path, bake_graph)); - } - return this.transpiler.log; - } - - pub inline fn pathToSourceIndexMap(this: *BundleV2, target: options.Target) *PathToSourceIndexMap { - return this.graph.pathToSourceIndexMap(target); - } - - const ReachableFileVisitor = struct { - reachable: std.array_list.Managed(Index), - visited: bun.bit_set.DynamicBitSet, - all_import_records: []ImportRecord.List, - all_loaders: []const Loader, - all_urls_for_css: []const []const u8, - redirects: []u32, - redirect_map: PathToSourceIndexMap, - dynamic_import_entry_points: *std.AutoArrayHashMap(Index.Int, void), - /// Files which are Server Component Boundaries - scb_bitset: ?bun.bit_set.DynamicBitSetUnmanaged, - scb_list: ServerComponentBoundary.List.Slice, - - /// Files which are imported by JS and inlined in CSS - additional_files_imported_by_js_and_inlined_in_css: *bun.bit_set.DynamicBitSetUnmanaged, - /// Files which are imported by CSS and inlined in CSS - additional_files_imported_by_css_and_inlined: *bun.bit_set.DynamicBitSetUnmanaged, - - const MAX_REDIRECTS: usize = 64; - - // Find all files reachable from all entry points. This order should be - // deterministic given that the entry point order is deterministic, since the - // returned order is the postorder of the graph traversal and import record - // order within a given file is deterministic. - pub fn visit(v: *@This(), source_index: Index, was_dynamic_import: bool, comptime check_dynamic_imports: bool) void { - if (source_index.isInvalid()) return; - - if (v.visited.isSet(source_index.get())) { - if (comptime check_dynamic_imports) { - if (was_dynamic_import) { - v.dynamic_import_entry_points.put(source_index.get(), {}) catch unreachable; - } - } - return; - } - v.visited.set(source_index.get()); - - if (v.scb_bitset) |scb_bitset| { - if (scb_bitset.isSet(source_index.get())) { - const scb_index = v.scb_list.getIndex(source_index.get()) orelse unreachable; - v.visit(Index.init(v.scb_list.list.items(.reference_source_index)[scb_index]), false, check_dynamic_imports); - v.visit(Index.init(v.scb_list.list.items(.ssr_source_index)[scb_index]), false, check_dynamic_imports); - } - } - - const is_js = v.all_loaders[source_index.get()].isJavaScriptLike(); - const is_css = v.all_loaders[source_index.get()].isCSS(); - - const import_record_list_id = source_index; - // when there are no import records, v index will be invalid - if (import_record_list_id.get() < v.all_import_records.len) { - const import_records = v.all_import_records[import_record_list_id.get()].slice(); - for (import_records) |*import_record| { - var other_source = import_record.source_index; - if (other_source.isValid()) { - var redirect_count: usize = 0; - while (getRedirectId(v.redirects[other_source.get()])) |redirect_id| : (redirect_count += 1) { - var other_import_records = v.all_import_records[other_source.get()].slice(); - const other_import_record = &other_import_records[redirect_id]; - import_record.source_index = other_import_record.source_index; - import_record.path = other_import_record.path; - other_source = other_import_record.source_index; - if (redirect_count == MAX_REDIRECTS) { - import_record.path.is_disabled = true; - import_record.source_index = Index.invalid; - break; - } - - // Handle redirects to a builtin or external module - // https://github.com/oven-sh/bun/issues/3764 - if (!other_source.isValid()) { - break; - } - } - - // Mark if the file is imported by JS and its URL is inlined for CSS - const is_inlined = import_record.source_index.isValid() and v.all_urls_for_css[import_record.source_index.get()].len > 0; - if (is_js and is_inlined) { - v.additional_files_imported_by_js_and_inlined_in_css.set(import_record.source_index.get()); - } else if (is_css and is_inlined) { - v.additional_files_imported_by_css_and_inlined.set(import_record.source_index.get()); - } - - v.visit(import_record.source_index, check_dynamic_imports and import_record.kind == .dynamic, check_dynamic_imports); - } - } - - // Redirects replace the source file with another file - if (getRedirectId(v.redirects[source_index.get()])) |redirect_id| { - const redirect_source_index = v.all_import_records[source_index.get()].slice()[redirect_id].source_index.get(); - v.visit(Index.source(redirect_source_index), was_dynamic_import, check_dynamic_imports); - return; - } - } - - // Each file must come after its dependencies - v.reachable.append(source_index) catch unreachable; - if (comptime check_dynamic_imports) { - if (was_dynamic_import) { - v.dynamic_import_entry_points.put(source_index.get(), {}) catch unreachable; - } - } - } - }; - - pub fn findReachableFiles(this: *BundleV2) ![]Index { - const trace = bun.perf.trace("Bundler.findReachableFiles"); - defer trace.end(); - - // Create a quick index for server-component boundaries. - // We need to mark the generated files as reachable, or else many files will appear missing. - var sfa = std.heap.stackFallback(4096, this.allocator()); - const stack_alloc = sfa.get(); - var scb_bitset = if (this.graph.server_component_boundaries.list.len > 0) - try this.graph.server_component_boundaries.slice().bitSet(stack_alloc, this.graph.input_files.len) - else - null; - defer if (scb_bitset) |*b| b.deinit(stack_alloc); - - var additional_files_imported_by_js_and_inlined_in_css = try bun.bit_set.DynamicBitSetUnmanaged.initEmpty(stack_alloc, this.graph.input_files.len); - var additional_files_imported_by_css_and_inlined = try bun.bit_set.DynamicBitSetUnmanaged.initEmpty(stack_alloc, this.graph.input_files.len); - defer { - additional_files_imported_by_js_and_inlined_in_css.deinit(stack_alloc); - additional_files_imported_by_css_and_inlined.deinit(stack_alloc); - } - - this.dynamic_import_entry_points = std.AutoArrayHashMap(Index.Int, void).init(this.allocator()); - - const all_urls_for_css = this.graph.ast.items(.url_for_css); - - var visitor = ReachableFileVisitor{ - .reachable = try std.array_list.Managed(Index).initCapacity(this.allocator(), this.graph.entry_points.items.len + 1), - .visited = try bun.bit_set.DynamicBitSet.initEmpty(this.allocator(), this.graph.input_files.len), - .redirects = this.graph.ast.items(.redirect_import_record_index), - .all_import_records = this.graph.ast.items(.import_records), - .all_loaders = this.graph.input_files.items(.loader), - .all_urls_for_css = all_urls_for_css, - .redirect_map = this.pathToSourceIndexMap(this.transpiler.options.target).*, - .dynamic_import_entry_points = &this.dynamic_import_entry_points, - .scb_bitset = scb_bitset, - .scb_list = if (scb_bitset != null) - this.graph.server_component_boundaries.slice() - else - undefined, // will never be read since the above bitset is `null` - .additional_files_imported_by_js_and_inlined_in_css = &additional_files_imported_by_js_and_inlined_in_css, - .additional_files_imported_by_css_and_inlined = &additional_files_imported_by_css_and_inlined, - }; - defer visitor.visited.deinit(); - - // If we don't include the runtime, __toESM or __toCommonJS will not get - // imported and weird things will happen - visitor.visit(Index.runtime, false, false); - - switch (this.transpiler.options.code_splitting) { - inline else => |check_dynamic_imports| { - for (this.graph.entry_points.items) |entry_point| { - visitor.visit(entry_point, false, comptime check_dynamic_imports); - } - }, - } - - const DebugLog = bun.Output.Scoped(.ReachableFiles, .visible); - if (DebugLog.isVisible()) { - DebugLog.log("Reachable count: {d} / {d}", .{ visitor.reachable.items.len, this.graph.input_files.len }); - const sources: []Logger.Source = this.graph.input_files.items(.source); - const targets: []options.Target = this.graph.ast.items(.target); - for (visitor.reachable.items) |idx| { - const source = sources[idx.get()]; - DebugLog.log("reachable file: #{d} {f} ({s}) target=.{s}", .{ - source.index.get(), - bun.fmt.quote(source.path.pretty), - source.path.text, - @tagName(targets[idx.get()]), - }); - } - } - - const additional_files = this.graph.input_files.items(.additional_files); - const unique_keys = this.graph.input_files.items(.unique_key_for_additional_file); - const content_hashes = this.graph.input_files.items(.content_hash_for_additional_file); - for (all_urls_for_css, 0..) |url_for_css, index| { - if (url_for_css.len > 0) { - // We like to inline additional files in CSS if they fit a size threshold - // If we do inline a file in CSS, and it is not imported by JS, then we don't need to copy the additional file into the output directory - if (additional_files_imported_by_css_and_inlined.isSet(index) and !additional_files_imported_by_js_and_inlined_in_css.isSet(index)) { - additional_files[index].clearRetainingCapacity(); - unique_keys[index] = ""; - content_hashes[index] = 0; - } - } - } - - return visitor.reachable.toOwnedSlice(); - } - - fn isDone(this: *BundleV2) bool { - this.thread_lock.assertLocked(); - - if (this.graph.pending_items == 0) { - if (this.graph.drainDeferredTasks(this)) { - return false; - } - - return true; - } - - return false; - } - - pub fn waitForParse(this: *BundleV2) void { - this.loop().tick(this, &isDone); - - debug("Parsed {d} files, producing {d} ASTs", .{ this.graph.input_files.len, this.graph.ast.len }); - } - - pub fn scanForSecondaryPaths(this: *BundleV2) void { - if (!this.graph.has_any_secondary_paths) { - - // Assert the boolean is accurate. - if (comptime Environment.ci_assert) { - for (this.graph.input_files.items(.secondary_path)) |secondary_path| { - if (secondary_path.len > 0) { - @panic("secondary_path is not empty"); - } - } - } - - // No dual package hazard. Do nothing. - return; - } - - // Now that all files have been scanned, look for packages that are imported - // both with "import" and "require". Rewrite any imports that reference the - // "module" package.json field to the "main" package.json field instead. - // - // This attempts to automatically avoid the "dual package hazard" where a - // package has both a CommonJS module version and an ECMAScript module - // version and exports a non-object in CommonJS (often a function). If we - // pick the "module" field and the package is imported with "require" then - // code expecting a function will crash. - const ast_import_records: []const ImportRecord.List = this.graph.ast.items(.import_records); - const targets: []const options.Target = this.graph.ast.items(.target); - const max_valid_source_index: Index = .init(this.graph.input_files.len); - const secondary_paths: []const []const u8 = this.graph.input_files.items(.secondary_path); - - for (ast_import_records, targets) |*ast_import_record_list, target| { - const import_records: []ImportRecord = ast_import_record_list.slice(); - const path_to_source_index_map = this.pathToSourceIndexMap(target); - for (import_records) |*import_record| { - const source_index = import_record.source_index.get(); - if (source_index >= max_valid_source_index.get()) { - continue; - } - const secondary_path = secondary_paths[source_index]; - if (secondary_path.len > 0) { - const secondary_source_index = path_to_source_index_map.get(secondary_path) orelse continue; - import_record.source_index = Index.init(secondary_source_index); - // Keep path in sync for determinism, diagnostics, and dev tooling. - import_record.path = this.graph.input_files.items(.source)[secondary_source_index].path; - } - } - } - } - - /// This runs on the Bundle Thread. - pub fn runResolver( - this: *BundleV2, - import_record: bun.jsc.API.JSBundler.Resolve.MiniImportRecord, - target: options.Target, - ) void { - const transpiler = this.transpilerForTarget(target); - const source_dir = Fs.PathName.init(import_record.source_file).dirWithTrailingSlash(); - - // Check the FileMap first for in-memory files - if (this.file_map) |file_map| { - if (file_map.resolve(import_record.source_file, import_record.specifier)) |_file_map_result| { - var file_map_result = _file_map_result; - var path_primary = file_map_result.path_pair.primary; - const entry = bun.handleOom(this.pathToSourceIndexMap(target).getOrPut(this.allocator(), path_primary.text)); - if (!entry.found_existing) { - const loader: Loader = brk: { - const record: *ImportRecord = &this.graph.ast.items(.import_records)[import_record.importer_source_index].slice()[import_record.import_record_index]; - if (record.loader) |out_loader| { - break :brk out_loader; - } - break :brk Fs.Path.init(path_primary.text).loader(&transpiler.options.loaders) orelse options.Loader.file; - }; - // For virtual files, use the path text as-is (no relative path computation needed). - path_primary.pretty = bun.handleOom(this.allocator().dupe(u8, path_primary.text)); - const idx = this.enqueueParseTask( - &file_map_result, - &.{ - .path = path_primary, - .contents = "", - }, - loader, - import_record.original_target, - ) catch |err| bun.handleOom(err); - entry.value_ptr.* = idx; - const record: *ImportRecord = &this.graph.ast.items(.import_records)[import_record.importer_source_index].slice()[import_record.import_record_index]; - record.source_index = Index.init(idx); - } else { - const record: *ImportRecord = &this.graph.ast.items(.import_records)[import_record.importer_source_index].slice()[import_record.import_record_index]; - record.source_index = Index.init(entry.value_ptr.*); - } - return; - } - } - - var had_busted_dir_cache: bool = false; - var resolve_result: _resolver.Result = while (true) break transpiler.resolver.resolve( - source_dir, - import_record.specifier, - import_record.kind, - ) catch |err| { - // Only perform directory busting when hot-reloading is enabled - if (err == error.ModuleNotFound) { - if (this.transpiler.options.dev_server) |dev| { - if (!had_busted_dir_cache) { - // Only re-query if we previously had something cached. - if (transpiler.resolver.bustDirCacheFromSpecifier(import_record.source_file, import_record.specifier)) { - had_busted_dir_cache = true; - continue; - } - } - - // Tell Bake's Dev Server to wait for the file to be imported. - dev.directory_watchers.trackResolutionFailure( - import_record.source_file, - import_record.specifier, - target.bakeGraph(), - this.graph.input_files.items(.loader)[import_record.importer_source_index], - ) catch |e| bun.handleOom(e); - - // Turn this into an invalid AST, so that incremental mode skips it when printing. - this.graph.ast.items(.parts)[import_record.importer_source_index].len = 0; - } - } - - var handles_import_errors = false; - var source: ?*const Logger.Source = null; - const log = this.logForResolutionFailures(import_record.source_file, target.bakeGraph()); - - var record: *ImportRecord = &this.graph.ast.items(.import_records)[import_record.importer_source_index].slice()[import_record.import_record_index]; - source = &this.graph.input_files.items(.source)[import_record.importer_source_index]; - handles_import_errors = record.flags.handles_import_errors; - - // Disable failing packages from being printed. - // This may cause broken code to write. - // However, doing this means we tell them all the resolve errors - // Rather than just the first one. - record.path.is_disabled = true; - - switch (err) { - error.ModuleNotFound => { - const addError = Logger.Log.addResolveErrorWithTextDupe; - - const path_to_use = import_record.specifier; - - if (!handles_import_errors and !this.transpiler.options.ignore_module_resolution_errors) { - if (isPackagePath(import_record.specifier)) { - if (target == .browser and options.ExternalModules.isNodeBuiltin(path_to_use)) { - addError( - log, - source, - import_record.range, - this.allocator(), - "Browser build cannot {s} Node.js module: \"{s}\". To use Node.js builtins, set target to 'node' or 'bun'", - .{ import_record.kind.errorLabel(), path_to_use }, - import_record.kind, - ) catch unreachable; - } else { - addError( - log, - source, - import_record.range, - this.allocator(), - "Could not resolve: \"{s}\". Maybe you need to \"bun install\"?", - .{path_to_use}, - import_record.kind, - ) catch unreachable; - } - } else { - addError( - log, - source, - import_record.range, - this.allocator(), - "Could not resolve: \"{s}\"", - .{ - path_to_use, - }, - import_record.kind, - ) catch unreachable; - } - } - }, - // assume other errors are already in the log - else => {}, - } - return; - }; - - var out_source_index: ?Index = null; - - var path: *Fs.Path = resolve_result.path() orelse { - var record: *ImportRecord = &this.graph.ast.items(.import_records)[import_record.importer_source_index].slice()[import_record.import_record_index]; - - // Disable failing packages from being printed. - // This may cause broken code to write. - // However, doing this means we tell them all the resolve errors - // Rather than just the first one. - record.path.is_disabled = true; - return; - }; - - if (resolve_result.flags.is_external) { - return; - } - - if (path.pretty.ptr == path.text.ptr) { - // TODO: outbase - const rel = bun.path.relativePlatform(transpiler.fs.top_level_dir, path.text, .loose, false); - path.pretty = bun.handleOom(this.allocator().dupe(u8, rel)); - } - path.assertPrettyIsValid(); - - path.assertFilePathIsAbsolute(); - const entry = bun.handleOom(this.pathToSourceIndexMap(target).getOrPut(this.allocator(), path.text)); - if (!entry.found_existing) { - path.* = bun.handleOom(this.pathWithPrettyInitialized(path.*, target)); - entry.key_ptr.* = path.text; - const loader: Loader = brk: { - const record: *ImportRecord = &this.graph.ast.items(.import_records)[import_record.importer_source_index].slice()[import_record.import_record_index]; - if (record.loader) |out_loader| { - break :brk out_loader; - } - break :brk path.loader(&transpiler.options.loaders) orelse options.Loader.file; - // HTML is only allowed at the entry point. - }; - const idx = this.enqueueParseTask( - &resolve_result, - &.{ - .path = path.*, - .contents = "", - }, - loader, - import_record.original_target, - ) catch |err| bun.handleOom(err); - entry.value_ptr.* = idx; - out_source_index = Index.init(idx); - - if (resolve_result.path_pair.secondary) |*secondary| { - if (!secondary.is_disabled and - secondary != path and - !strings.eqlLong(secondary.text, path.text, true)) - { - const secondary_path_to_copy = secondary.dupeAlloc(this.allocator()) catch |err| bun.handleOom(err); - this.graph.input_files.items(.secondary_path)[idx] = secondary_path_to_copy.text; - // Ensure the determinism pass runs. - this.graph.has_any_secondary_paths = true; - } - } - - // For non-javascript files, make all of these files share indices. - // For example, it is silly to bundle index.css depended on by client+server twice. - // It makes sense to separate these for JS because the target affects DCE - if (this.transpiler.options.server_components and !loader.isJavaScriptLike()) { - const a, const b = switch (target) { - else => .{ this.pathToSourceIndexMap(.browser), this.pathToSourceIndexMap(.bake_server_components_ssr) }, - .browser => .{ this.pathToSourceIndexMap(this.transpiler.options.target), this.pathToSourceIndexMap(.bake_server_components_ssr) }, - .bake_server_components_ssr => .{ this.pathToSourceIndexMap(this.transpiler.options.target), this.pathToSourceIndexMap(.browser) }, - }; - bun.handleOom(a.put(this.allocator(), entry.key_ptr.*, entry.value_ptr.*)); - if (this.framework.?.server_components.?.separate_ssr_graph) - bun.handleOom(b.put(this.allocator(), entry.key_ptr.*, entry.value_ptr.*)); - } - } else { - out_source_index = Index.init(entry.value_ptr.*); - } - - if (out_source_index) |source_index| { - const record: *ImportRecord = &this.graph.ast.items(.import_records)[import_record.importer_source_index].slice()[import_record.import_record_index]; - record.source_index = source_index; - } - } - - pub fn enqueueFileFromDevServerIncrementalGraphInvalidation( - this: *BundleV2, - path_slice: []const u8, - target: options.Target, - ) !void { - // TODO: plugins with non-file namespaces - const entry = try this.pathToSourceIndexMap(target).getOrPut(this.allocator(), path_slice); - if (entry.found_existing) { - return; - } - const t = this.transpilerForTarget(target); - const result = t.resolveEntryPoint(path_slice) catch - return; - var path = result.path_pair.primary; - this.incrementScanCounter(); - const source_index = Index.source(this.graph.input_files.len); - const loader = brk: { - const default = path.loader(&this.transpiler.options.loaders) orelse .file; - break :brk default; - }; - - path = bun.handleOom(this.pathWithPrettyInitialized(path, target)); - path.assertPrettyIsValid(); - entry.key_ptr.* = path.text; - entry.value_ptr.* = source_index.get(); - bun.handleOom(this.graph.ast.append(this.allocator(), JSAst.empty)); - - try this.graph.input_files.append(this.allocator(), .{ - .source = .{ - .path = path, - .contents = "", - .index = source_index, - }, - .loader = loader, - .side_effects = result.primary_side_effects_data, - }); - var task = try this.allocator().create(ParseTask); - task.* = ParseTask.init(&result, source_index, this); - task.loader = loader; - task.task.node.next = null; - task.tree_shaking = this.linker.options.tree_shaking; - task.known_target = target; - task.jsx.development = switch (t.options.force_node_env) { - .development => true, - .production => false, - .unspecified => t.options.jsx.development, - }; - - // Handle onLoad plugins as entry points - if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling()) { - var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = task.source_index.get() })); - this.graph.input_files.items(.side_effects)[source_index.get()] = .no_side_effects__pure_data; - this.graph.estimated_file_loader_count += 1; - } - - this.graph.pool.schedule(task); - } - } - - pub fn enqueueEntryItem( - this: *BundleV2, - resolve: _resolver.Result, - is_entry_point: bool, - target: options.Target, - ) !?Index.Int { - var result = resolve; - var path = result.path() orelse return null; - - path.assertFilePathIsAbsolute(); - const entry = try this.pathToSourceIndexMap(target).getOrPut(this.allocator(), path.text); - if (entry.found_existing) { - return null; - } - this.incrementScanCounter(); - const source_index = Index.source(this.graph.input_files.len); - - const loader = brk: { - const loader = path.loader(&this.transpiler.options.loaders) orelse .file; - break :brk loader; - }; - - path.* = bun.handleOom(this.pathWithPrettyInitialized(path.*, target)); - path.assertPrettyIsValid(); - entry.key_ptr.* = path.text; - entry.value_ptr.* = source_index.get(); - bun.handleOom(this.graph.ast.append(this.allocator(), JSAst.empty)); - - try this.graph.input_files.append(this.allocator(), .{ - .source = .{ - .path = path.*, - .contents = "", - .index = source_index, - }, - .loader = loader, - .side_effects = resolve.primary_side_effects_data, - }); - var task = try this.allocator().create(ParseTask); - task.* = ParseTask.init(&result, source_index, this); - task.loader = loader; - task.task.node.next = null; - task.tree_shaking = this.linker.options.tree_shaking; - task.is_entry_point = is_entry_point; - task.known_target = target; - { - const bundler = this.transpilerForTarget(target); - task.jsx.development = switch (bundler.options.force_node_env) { - .development => true, - .production => false, - .unspecified => bundler.options.jsx.development, - }; - } - - // Handle onLoad plugins as entry points - if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling()) { - var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = task.source_index.get() })); - this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; - this.graph.estimated_file_loader_count += 1; - } - - this.graph.pool.schedule(task); - } - - try this.graph.entry_points.append(this.allocator(), source_index); - - return source_index.get(); - } - - /// `heap` is not freed when `deinit`ing the BundleV2 - pub fn init( - transpiler: *Transpiler, - bake_options: ?BakeOptions, - alloc: std.mem.Allocator, - event_loop: EventLoop, - cli_watch_flag: bool, - thread_pool: ?*ThreadPoolLib, - heap: ThreadLocalArena, - ) !*BundleV2 { - transpiler.env.loadTracy(); - - const this = try alloc.create(BundleV2); - transpiler.options.mark_builtins_as_external = transpiler.options.target.isBun() or transpiler.options.target == .node; - transpiler.resolver.opts.mark_builtins_as_external = transpiler.options.target.isBun() or transpiler.options.target == .node; - - this.* = .{ - .transpiler = transpiler, - .client_transpiler = null, - .ssr_transpiler = transpiler, - .framework = null, - .graph = .{ - .pool = undefined, - .heap = heap, - .kit_referenced_server_data = false, - .kit_referenced_client_data = false, - .build_graphs = .initFill(.{}), - }, - .linker = .{ - .loop = event_loop, - .graph = .{ - .allocator = heap.allocator(), - }, - }, - .bun_watcher = null, - .plugins = null, - .completion = null, - .file_map = null, - .source_code_length = 0, - .thread_lock = .initLocked(), - }; - if (bake_options) |bo| { - this.client_transpiler = bo.client_transpiler; - this.ssr_transpiler = bo.ssr_transpiler; - this.framework = bo.framework; - this.linker.framework = &this.framework.?; - this.plugins = bo.plugins; - if (transpiler.options.server_components) { - bun.assert(this.client_transpiler.?.options.server_components); - if (bo.framework.server_components.?.separate_ssr_graph) - bun.assert(this.ssr_transpiler.options.server_components); - } - } - this.transpiler.allocator = heap.allocator(); - this.transpiler.resolver.allocator = heap.allocator(); - this.transpiler.linker.allocator = heap.allocator(); - this.transpiler.log.msgs.allocator = heap.allocator(); - this.transpiler.log.clone_line_text = true; - - // We don't expose an option to disable this. Bake forbids tree-shaking - // since every export must is always exist in case a future module - // starts depending on it. - if (this.transpiler.options.output_format == .internal_bake_dev) { - this.transpiler.options.tree_shaking = false; - this.transpiler.resolver.opts.tree_shaking = false; - } else { - this.transpiler.options.tree_shaking = true; - this.transpiler.resolver.opts.tree_shaking = true; - } - - this.linker.resolver = &this.transpiler.resolver; - this.linker.graph.code_splitting = transpiler.options.code_splitting; - - this.linker.options.minify_syntax = transpiler.options.minify_syntax; - this.linker.options.minify_identifiers = transpiler.options.minify_identifiers; - this.linker.options.minify_whitespace = transpiler.options.minify_whitespace; - this.linker.options.emit_dce_annotations = transpiler.options.emit_dce_annotations; - this.linker.options.ignore_dce_annotations = transpiler.options.ignore_dce_annotations; - this.linker.options.banner = transpiler.options.banner; - this.linker.options.footer = transpiler.options.footer; - this.linker.options.css_chunking = transpiler.options.css_chunking; - this.linker.options.compile_to_standalone_html = transpiler.options.compile_to_standalone_html; - this.linker.options.source_maps = transpiler.options.source_map; - this.linker.options.tree_shaking = transpiler.options.tree_shaking; - this.linker.options.public_path = transpiler.options.public_path; - this.linker.options.target = transpiler.options.target; - this.linker.options.output_format = transpiler.options.output_format; - this.linker.options.generate_bytecode_cache = transpiler.options.bytecode; - this.linker.options.compile = transpiler.options.compile; - this.linker.options.metafile = transpiler.options.metafile; - this.linker.options.metafile_json_path = transpiler.options.metafile_json_path; - this.linker.options.metafile_markdown_path = transpiler.options.metafile_markdown_path; - - this.linker.dev_server = transpiler.options.dev_server; - - const pool = try this.allocator().create(ThreadPool); - if (cli_watch_flag) { - Watcher.enableHotModuleReloading(this, null); - } - // errdefer pool.destroy(); - errdefer this.graph.heap.deinit(); - - pool.* = try .init(this, thread_pool); - this.graph.pool = pool; - pool.start(); - return this; - } - - pub fn allocator(this: *const BundleV2) std.mem.Allocator { - return this.graph.heap.allocator(); - } - - const logScanCounter = bun.Output.scoped(.scan_counter, .visible); - - pub fn incrementScanCounter(this: *BundleV2) void { - this.thread_lock.assertLocked(); - this.graph.pending_items += 1; - logScanCounter(".pending_items + 1 = {d}", .{this.graph.pending_items}); - } - - pub fn decrementScanCounter(this: *BundleV2) void { - this.thread_lock.assertLocked(); - this.graph.pending_items -= 1; - logScanCounter(".pending_items - 1 = {d}", .{this.graph.pending_items}); - this.onAfterDecrementScanCounter(); - } - - pub fn onAfterDecrementScanCounter(this: *BundleV2) void { - if (this.asynchronous and this.isDone()) { - this.finishFromBakeDevServer(this.transpiler.options.dev_server orelse - @panic("No dev server attached in asynchronous bundle job")) catch - bun.outOfMemory(); - } - } - - pub fn enqueueEntryPoints( - this: *BundleV2, - comptime variant: enum { normal, dev_server, bake_production }, - data: switch (variant) { - .normal => []const []const u8, - .dev_server => struct { - files: bake.DevServer.EntryPointList, - css_data: *std.AutoArrayHashMapUnmanaged(Index, CssEntryPointMeta), - }, - .bake_production => bake.production.EntryPointMap, - }, - ) !void { - { - // Add the runtime - const rt = ParseTask.getRuntimeSource(this.transpiler.options.target); - try this.graph.input_files.append(this.allocator(), Graph.InputFile{ - .source = rt.source, - .loader = .js, - .side_effects = _resolver.SideEffects.no_side_effects__pure_data, - }); - - // try this.graph.entry_points.append(allocator, Index.runtime); - try this.graph.ast.append(this.allocator(), JSAst.empty); - try this.pathToSourceIndexMap(this.transpiler.options.target).put(this.allocator(), "bun:wrap", Index.runtime.get()); - var runtime_parse_task = try this.allocator().create(ParseTask); - runtime_parse_task.* = rt.parse_task; - runtime_parse_task.ctx = this; - runtime_parse_task.tree_shaking = true; - runtime_parse_task.loader = .js; - this.incrementScanCounter(); - this.graph.pool.schedule(runtime_parse_task); - } - - // Bake reserves two source indexes at the start of the file list, but - // gets its content set after the scan+parse phase, but before linking. - // - // The dev server does not use these, as it is implement in the HMR runtime. - if (variant != .dev_server) { - try this.reserveSourceIndexesForBake(); - } else { - bun.assert(this.transpiler.options.dev_server != null); - } - - { - // Setup entry points - const num_entry_points = switch (variant) { - .normal => data.len, - .bake_production => data.files.count(), - .dev_server => data.files.set.count(), - }; - - try this.graph.entry_points.ensureUnusedCapacity(this.allocator(), num_entry_points); - try this.graph.input_files.ensureUnusedCapacity(this.allocator(), num_entry_points); - - switch (variant) { - .normal => { - for (data) |entry_point| { - if (this.enqueueEntryPointOnResolvePluginIfNeeded(entry_point, this.transpiler.options.target)) { - continue; - } - - // Check FileMap first for in-memory entry points - if (this.file_map) |file_map| { - if (file_map.resolve("", entry_point)) |file_map_result| { - _ = try this.enqueueEntryItem( - file_map_result, - true, - this.transpiler.options.target, - ); - continue; - } - } - - // no plugins were matched - const resolved = this.transpiler.resolveEntryPoint(entry_point) catch - continue; - - _ = try this.enqueueEntryItem( - resolved, - true, - brk: { - const main_target = this.transpiler.options.target; - - if (main_target.isServerSide()) { - if (resolved.pathConst()) |path| { - if (path.loader(&this.transpiler.options.loaders)) |loader| { - if (loader == .html) { - this.ensureClientTranspiler(); - break :brk .browser; - } - } - } - } - - break :brk main_target; - }, - ); - } - }, - .dev_server => { - for (data.files.set.keys(), data.files.set.values()) |abs_path, flags| { - - // Ensure we have the proper conditions set for client-side entrypoints. - const transpiler = if (flags.client and !flags.server and !flags.ssr) - this.transpilerForTarget(.browser) - else - this.transpiler; - - const targets_to_check = [_]struct { - should_dispatch: bool, - target: options.Target, - }{ - .{ .should_dispatch = flags.client, .target = .browser }, - .{ .should_dispatch = flags.server, .target = this.transpiler.options.target }, - .{ .should_dispatch = flags.ssr, .target = .bake_server_components_ssr }, - }; - - var any_plugin_matched = false; - for (targets_to_check) |target_info| { - if (target_info.should_dispatch) { - if (this.enqueueEntryPointOnResolvePluginIfNeeded(abs_path, target_info.target)) { - any_plugin_matched = true; - } - } - } - - if (any_plugin_matched) { - continue; - } - - // Fall back to normal resolution if no plugins matched - const resolved = transpiler.resolveEntryPoint(abs_path) catch |err| { - const dev = this.transpiler.options.dev_server orelse unreachable; - dev.handleParseTaskFailure( - err, - if (flags.client) .client else .server, - abs_path, - transpiler.log, - this, - ) catch |e| bun.handleOom(e); - transpiler.log.reset(); - continue; - }; - - if (flags.client) brk: { - const source_index = try this.enqueueEntryItem(resolved, true, .browser) orelse break :brk; - if (flags.css) { - try data.css_data.putNoClobber(this.allocator(), Index.init(source_index), .{ .imported_on_server = false }); - } - } - if (flags.server) _ = try this.enqueueEntryItem(resolved, true, this.transpiler.options.target); - if (flags.ssr) _ = try this.enqueueEntryItem(resolved, true, .bake_server_components_ssr); - } - }, - .bake_production => { - for (data.files.keys()) |key| { - const abs_path = key.absPath(); - const target = switch (key.side) { - .client => options.Target.browser, - .server => this.transpiler.options.target, - }; - - if (this.enqueueEntryPointOnResolvePluginIfNeeded(abs_path, target)) { - continue; - } - - // no plugins matched - const resolved = this.transpiler.resolveEntryPoint(abs_path) catch - continue; - - // TODO: wrap client files so the exports arent preserved. - _ = try this.enqueueEntryItem(resolved, true, target) orelse continue; - } - }, - } - } - } - - fn cloneAST(this: *BundleV2) !void { - const trace = bun.perf.trace("Bundler.cloneAST"); - defer trace.end(); - bun.safety.alloc.assertEq(this.allocator(), this.transpiler.allocator); - bun.safety.alloc.assertEq(this.allocator(), this.linker.graph.allocator); - this.linker.graph.ast = try this.graph.ast.clone(this.allocator()); - - for (this.linker.graph.ast.items(.module_scope)) |*module_scope| { - for (module_scope.children.slice()) |child| { - child.parent = module_scope; - } - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.graph.heap.helpCatchMemoryIssues(); - } - - module_scope.generated = try module_scope.generated.clone(this.allocator()); - } - - // Some parts of the AST are owned by worker allocators at this point. - // Transfer ownership to the graph heap. - this.linker.graph.takeAstOwnership(); - } - - /// This generates the two asts for 'bun:bake/client' and 'bun:bake/server'. Both are generated - /// at the same time in one pass over the SCB list. - pub fn processServerComponentManifestFiles(this: *BundleV2) OOM!void { - // If a server components is not configured, do nothing - const fw = this.framework orelse return; - const sc = fw.server_components orelse return; - - if (!this.graph.kit_referenced_server_data and - !this.graph.kit_referenced_client_data) return; - - const alloc = this.allocator(); - - var server = try AstBuilder.init(this.allocator(), &bake.server_virtual_source, this.transpiler.options.hot_module_reloading); - var client = try AstBuilder.init(this.allocator(), &bake.client_virtual_source, this.transpiler.options.hot_module_reloading); - - var server_manifest_props: std.ArrayListUnmanaged(G.Property) = .{}; - var client_manifest_props: std.ArrayListUnmanaged(G.Property) = .{}; - - const scbs = this.graph.server_component_boundaries.list.slice(); - const named_exports_array = this.graph.ast.items(.named_exports); - - const id_string = server.newExpr(E.String{ .data = "id" }); - const name_string = server.newExpr(E.String{ .data = "name" }); - const chunks_string = server.newExpr(E.String{ .data = "chunks" }); - const specifier_string = server.newExpr(E.String{ .data = "specifier" }); - const empty_array = server.newExpr(E.Array{}); - - for ( - scbs.items(.use_directive), - scbs.items(.source_index), - scbs.items(.ssr_source_index), - ) |use, source_id, ssr_index| { - if (use == .client) { - // TODO(@paperclover/bake): this file is being generated far too - // early. we don't know which exports are dead and which exports - // are live. Tree-shaking figures that out. However, - // tree-shaking happens after import binding, which would - // require this ast. - // - // The plan: change this to generate a stub ast which only has - // `export const serverManifest = undefined;`, and then - // re-generate this file later with the properly decided - // manifest. However, I will probably reconsider how this - // manifest is being generated when I write the whole - // "production build" part of Bake. - - const keys = named_exports_array[source_id].keys(); - const client_manifest_items = try alloc.alloc(G.Property, keys.len); - - if (!sc.separate_ssr_graph) bun.todoPanic(@src(), "separate_ssr_graph=false", .{}); - - const client_path = server.newExpr(E.String{ - .data = try std.fmt.allocPrint(alloc, "{f}S{d:0>8}", .{ - bun.fmt.hexIntLower(this.unique_key), - source_id, - }), - }); - const ssr_path = server.newExpr(E.String{ - .data = try std.fmt.allocPrint(alloc, "{f}S{d:0>8}", .{ - bun.fmt.hexIntLower(this.unique_key), - ssr_index, - }), - }); - - for (keys, client_manifest_items) |export_name_string, *client_item| { - const server_key_string = try std.fmt.allocPrint(alloc, "{f}S{d:0>8}#{s}", .{ - bun.fmt.hexIntLower(this.unique_key), - source_id, - export_name_string, - }); - const export_name = server.newExpr(E.String{ .data = export_name_string }); - - // write dependencies on the underlying module, not the proxy - try server_manifest_props.append(alloc, .{ - .key = server.newExpr(E.String{ .data = server_key_string }), - .value = server.newExpr(E.Object{ - .properties = try G.Property.List.fromSlice(alloc, &.{ - .{ .key = id_string, .value = client_path }, - .{ .key = name_string, .value = export_name }, - .{ .key = chunks_string, .value = empty_array }, - }), - }), - }); - client_item.* = .{ - .key = export_name, - .value = server.newExpr(E.Object{ - .properties = try G.Property.List.fromSlice(alloc, &.{ - .{ .key = name_string, .value = export_name }, - .{ .key = specifier_string, .value = ssr_path }, - }), - }), - }; - } - - try client_manifest_props.append(alloc, .{ - .key = client_path, - .value = server.newExpr(E.Object{ - .properties = G.Property.List.fromOwnedSlice(client_manifest_items), - }), - }); - } else { - bun.todoPanic(@src(), "\"use server\"", .{}); - } - } - - try server.appendStmt(S.Local{ - .kind = .k_const, - .decls = try G.Decl.List.fromSlice(alloc, &.{.{ - .binding = Binding.alloc(alloc, B.Identifier{ - .ref = try server.newSymbol(.other, "serverManifest"), - }, Logger.Loc.Empty), - .value = server.newExpr(E.Object{ - .properties = G.Property.List.moveFromList(&server_manifest_props), - }), - }}), - .is_export = true, - }); - try server.appendStmt(S.Local{ - .kind = .k_const, - .decls = try G.Decl.List.fromSlice(alloc, &.{.{ - .binding = Binding.alloc(alloc, B.Identifier{ - .ref = try server.newSymbol(.other, "ssrManifest"), - }, Logger.Loc.Empty), - .value = server.newExpr(E.Object{ - .properties = G.Property.List.moveFromList(&client_manifest_props), - }), - }}), - .is_export = true, - }); - - this.graph.ast.set(Index.bake_server_data.get(), try server.toBundledAst(.bun)); - this.graph.ast.set(Index.bake_client_data.get(), try client.toBundledAst(.browser)); - } - - pub fn enqueueParseTask( - this: *BundleV2, - noalias resolve_result: *const _resolver.Result, - source: *const Logger.Source, - loader: Loader, - known_target: options.Target, - ) OOM!Index.Int { - const source_index = Index.init(@as(u32, @intCast(this.graph.ast.len))); - this.graph.ast.append(this.allocator(), JSAst.empty) catch unreachable; - - this.graph.input_files.append(this.allocator(), .{ - .source = source.*, - .loader = loader, - .side_effects = loader.sideEffects(), - }) catch |err| bun.handleOom(err); - var task = bun.handleOom(this.allocator().create(ParseTask)); - task.* = ParseTask.init(resolve_result, source_index, this); - task.loader = loader; - task.jsx = this.transpilerForTarget(known_target).options.jsx; - task.task.node.next = null; - task.io_task.node.next = null; - task.tree_shaking = this.linker.options.tree_shaking; - task.known_target = known_target; - - this.incrementScanCounter(); - - // Handle onLoad plugins - if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling()) { - var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = task.source_index.get() })); - this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; - this.graph.estimated_file_loader_count += 1; - } - - this.graph.pool.schedule(task); - } - - return source_index.get(); - } - - pub fn enqueueParseTask2( - this: *BundleV2, - source: *const Logger.Source, - loader: Loader, - known_target: options.Target, - ) OOM!Index.Int { - const source_index = Index.init(@as(u32, @intCast(this.graph.ast.len))); - this.graph.ast.append(this.allocator(), JSAst.empty) catch unreachable; - - this.graph.input_files.append(this.allocator(), .{ - .source = source.*, - .loader = loader, - .side_effects = loader.sideEffects(), - }) catch |err| bun.handleOom(err); - var task = bun.handleOom(this.allocator().create(ParseTask)); - task.* = .{ - .ctx = this, - .path = source.path, - .contents_or_fd = .{ - .contents = source.contents, - }, - .side_effects = .has_side_effects, - .jsx = if (known_target == .bake_server_components_ssr and !this.framework.?.server_components.?.separate_ssr_graph) - this.transpiler.options.jsx - else - this.transpilerForTarget(known_target).options.jsx, - .source_index = source_index, - .module_type = .unknown, - .emit_decorator_metadata = false, // TODO - .package_version = "", - .loader = loader, - .tree_shaking = this.linker.options.tree_shaking, - .known_target = known_target, - }; - task.task.node.next = null; - task.io_task.node.next = null; - - this.incrementScanCounter(); - - // Handle onLoad plugins - if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling()) { - var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = task.source_index.get() })); - this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; - this.graph.estimated_file_loader_count += 1; - } - - this.graph.pool.schedule(task); - } - return source_index.get(); - } - - /// Enqueue a ServerComponentParseTask. - /// `source_without_index` is copied and assigned a new source index. That index is returned. - pub fn enqueueServerComponentGeneratedFile( - this: *BundleV2, - data: ServerComponentParseTask.Data, - source_without_index: Logger.Source, - ) OOM!Index.Int { - var new_source: Logger.Source = source_without_index; - const source_index = this.graph.input_files.len; - new_source.index = Index.init(source_index); - try this.graph.input_files.append(this.allocator(), .{ - .source = new_source, - .loader = .js, - .side_effects = .has_side_effects, - }); - try this.graph.ast.append(this.allocator(), JSAst.empty); - - const task = bun.new(ServerComponentParseTask, .{ - .data = data, - .ctx = this, - .source = new_source, - }); - - this.incrementScanCounter(); - - this.graph.pool.worker_pool.schedule(.from(&task.task)); - - return @intCast(source_index); - } - - pub const DependenciesScanner = struct { - ctx: *anyopaque, - entry_points: []const []const u8, - - onFetch: *const fn ( - ctx: *anyopaque, - result: *DependenciesScanner.Result, - ) anyerror!void, - - pub const Result = struct { - dependencies: bun.StringSet, - reachable_files: []const Index, - bundle_v2: *BundleV2, - }; - }; - - pub fn getAllDependencies(this: *BundleV2, reachable_files: []const Index, fetcher: *const DependenciesScanner) !void { - - // Find all external dependencies from reachable files - var external_deps = bun.StringSet.init(bun.default_allocator); - defer external_deps.deinit(); - - const import_records = this.graph.ast.items(.import_records); - - for (reachable_files) |source_index| { - const records: []const ImportRecord = import_records[source_index.get()].slice(); - for (records) |*record| { - if (!record.source_index.isValid() and record.tag == .none) { - const path = record.path.text; - // External dependency - if (path.len > 0 and - // Check for either node or bun builtins - // We don't use the list from .bun because that includes third-party packages in some cases. - !jsc.ModuleLoader.HardcodedModule.Alias.has(path, .node, .{}) and - !strings.hasPrefixComptime(path, "bun:") and - !strings.eqlComptime(path, "bun")) - { - if (strings.isNPMPackageNameIgnoreLength(path)) { - try external_deps.insert(path); - } - } - } - } - } - var result = DependenciesScanner.Result{ - .dependencies = external_deps, - .bundle_v2 = this, - .reachable_files = reachable_files, - }; - try fetcher.onFetch(fetcher.ctx, &result); - } - - pub fn generateFromCLI( - transpiler: *Transpiler, - alloc: std.mem.Allocator, - event_loop: EventLoop, - enable_reloading: bool, - reachable_files_count: *usize, - minify_duration: *u64, - source_code_size: *u64, - fetcher: ?*DependenciesScanner, - ) !BuildResult { - var this = try BundleV2.init( - transpiler, - null, - alloc, - event_loop, - enable_reloading, - null, - .init(), - ); - this.unique_key = generateUniqueKey(); - - if (this.transpiler.log.hasErrors()) { - return error.BuildFailed; - } - - try this.enqueueEntryPoints(.normal, this.transpiler.options.entry_points); - - if (this.transpiler.log.hasErrors()) { - return error.BuildFailed; - } - - this.waitForParse(); - - minify_duration.* = @as(u64, @intCast(@divTrunc(@as(i64, @truncate(std.time.nanoTimestamp())) - @as(i64, @truncate(bun.cli.start_time)), @as(i64, std.time.ns_per_ms)))); - source_code_size.* = this.source_code_length; - - if (this.transpiler.log.hasErrors()) { - return error.BuildFailed; - } - - this.scanForSecondaryPaths(); - - try this.processServerComponentManifestFiles(); - - const reachable_files = try this.findReachableFiles(); - reachable_files_count.* = reachable_files.len -| 1; // - 1 for the runtime - - try this.processFilesToCopy(reachable_files); - - try this.addServerComponentBoundariesAsExtraEntryPoints(); - - try this.cloneAST(); - - const chunks = try this.linker.link( - this, - this.graph.entry_points.items, - this.graph.server_component_boundaries, - reachable_files, - ); - - // Do this at the very end, after processing all the imports/exports so that we can follow exports as needed. - if (fetcher) |fetch| { - try this.getAllDependencies(reachable_files, fetch); - return .{ - .output_files = std.array_list.Managed(options.OutputFile).init(alloc), - .metafile = null, - .metafile_markdown = null, - }; - } - - const output_files = try this.linker.generateChunksInParallel(chunks, false); - - // Generate metafile if requested (CLI writes files in build_command.zig) - const metafile: ?[]const u8 = if (this.linker.options.metafile) - LinkerContext.MetafileBuilder.generate(bun.default_allocator, &this.linker, chunks) catch |err| blk: { - bun.Output.warn("Failed to generate metafile: {s}", .{@errorName(err)}); - break :blk null; - } - else - null; - - // Markdown is generated later in build_command.zig for CLI - return .{ - .output_files = output_files, - .metafile = metafile, - .metafile_markdown = null, - }; - } - - /// Build only the parse graph for the given entry points and return the - /// BundleV2 instance. No linking or code generation is performed; this is - /// used by `bun test --changed` to walk import records and compute which - /// test entry points transitively depend on a given set of source files. - /// - /// The returned BundleV2, its ThreadLocalArena, and its worker pool are - /// intentionally left alive for the remainder of the process. Tearing - /// the pool down via `deinitWithoutFreeingArena()` blocks on worker - /// shutdown and contends with the runtime VM's own parse threads; the - /// sole caller exec()s (watch mode) or exits shortly after, so the leak - /// is bounded. Dupe anything you need out of the graph before returning - /// to the caller. - pub fn scanModuleGraphFromCLI( - transpiler: *Transpiler, - alloc: std.mem.Allocator, - event_loop: EventLoop, - entry_points: []const []const u8, - ) !*BundleV2 { - var this = try BundleV2.init( - transpiler, - null, - alloc, - event_loop, - false, - null, - .init(), - ); - this.unique_key = generateUniqueKey(); - - if (this.transpiler.log.hasErrors()) { - return error.BuildFailed; - } - - // enqueueEntryPoints schedules the runtime task before any fallible - // allocation. If a later allocation fails we must still drain the - // pool so workers aren't left holding pointers into the caller's - // stack-allocated Transpiler. - this.enqueueEntryPoints(.normal, entry_points) catch |err| { - this.waitForParse(); - return err; - }; - - // Even if entry point resolution produced errors we still wait for - // all enqueued parse tasks to finish so the graph is consistent. - this.waitForParse(); - - return this; - } - - pub fn generateFromBakeProductionCLI( - entry_points: bake.production.EntryPointMap, - server_transpiler: *Transpiler, - bake_options: BakeOptions, - alloc: std.mem.Allocator, - event_loop: EventLoop, - ) !std.array_list.Managed(options.OutputFile) { - var this = try BundleV2.init( - server_transpiler, - bake_options, - alloc, - event_loop, - false, - null, - .init(), - ); - this.unique_key = generateUniqueKey(); - - if (this.transpiler.log.hasErrors()) { - return error.BuildFailed; - } - - try this.enqueueEntryPoints(.bake_production, entry_points); - - if (this.transpiler.log.hasErrors()) { - return error.BuildFailed; - } - - this.waitForParse(); - - if (this.transpiler.log.hasErrors()) { - return error.BuildFailed; - } - - this.scanForSecondaryPaths(); - - try this.processServerComponentManifestFiles(); - - const reachable_files = try this.findReachableFiles(); - - try this.processFilesToCopy(reachable_files); - - try this.addServerComponentBoundariesAsExtraEntryPoints(); - - try this.cloneAST(); - - const chunks = try this.linker.link( - this, - this.graph.entry_points.items, - this.graph.server_component_boundaries, - reachable_files, - ); - - if (chunks.len == 0) { - return std.array_list.Managed(options.OutputFile).init(bun.default_allocator); - } - - return try this.linker.generateChunksInParallel(chunks, false); - } - - pub fn addServerComponentBoundariesAsExtraEntryPoints(this: *BundleV2) !void { - // Prepare server component boundaries. Each boundary turns into two - // entry points, a client entrypoint and a server entrypoint. - // - // TODO: This should be able to group components by the user specified - // entry points. This way, using two component files in a route does not - // create two separate chunks. (note: bake passes each route as an entrypoint) - { - const scbs = this.graph.server_component_boundaries.slice(); - try this.graph.entry_points.ensureUnusedCapacity(this.allocator(), scbs.list.len * 2); - for (scbs.list.items(.source_index), scbs.list.items(.ssr_source_index)) |original_index, ssr_index| { - inline for (.{ original_index, ssr_index }) |idx| { - this.graph.entry_points.appendAssumeCapacity(Index.init(idx)); - } - } - } - } - - pub fn processFilesToCopy(this: *BundleV2, reachable_files: []const Index) !void { - if (this.graph.estimated_file_loader_count > 0) { - const file_allocators = this.graph.input_files.items(.allocator); - const unique_key_for_additional_files = this.graph.input_files.items(.unique_key_for_additional_file); - const content_hashes_for_additional_files = this.graph.input_files.items(.content_hash_for_additional_file); - const sources: []const Logger.Source = this.graph.input_files.items(.source); - const targets: []const options.Target = this.graph.ast.items(.target); - var additional_output_files = std.array_list.Managed(options.OutputFile).init(this.transpiler.allocator); - - const additional_files: []BabyList(AdditionalFile) = this.graph.input_files.items(.additional_files); - const loaders = this.graph.input_files.items(.loader); - - for (reachable_files) |reachable_source| { - const index = reachable_source.get(); - const key = unique_key_for_additional_files[index]; - if (key.len > 0) { - var template = if (this.graph.html_imports.server_source_indices.len > 0 and this.transpiler.options.asset_naming.len == 0) - PathTemplate.assetWithTarget - else - PathTemplate.asset; - - const target = targets[index]; - const asset_naming = this.transpilerForTarget(target).options.asset_naming; - if (asset_naming.len > 0) { - template.data = asset_naming; - } - - const source = &sources[index]; - - const output_path = brk: { - var pathname = source.path.name; - - // TODO: outbase - pathname = Fs.PathName.init(bun.path.relativePlatform(this.transpiler.options.root_dir, source.path.text, .loose, false)); - - template.placeholder.name = pathname.base; - template.placeholder.dir = pathname.dir; - template.placeholder.ext = pathname.ext; - if (template.placeholder.ext.len > 0 and template.placeholder.ext[0] == '.') - template.placeholder.ext = template.placeholder.ext[1..]; - - if (template.needs(.hash)) { - template.placeholder.hash = content_hashes_for_additional_files[index]; - } - - if (template.needs(.target)) { - template.placeholder.target = @tagName(target); - } - break :brk bun.handleOom(std.fmt.allocPrint(bun.default_allocator, "{f}", .{template})); - }; - - const loader = loaders[index]; - - additional_output_files.append(options.OutputFile.init(.{ - .source_index = .init(index), - .data = .{ .buffer = .{ - .data = source.contents, - .allocator = file_allocators[index], - } }, - .size = source.contents.len, - .output_path = output_path, - .input_path = bun.handleOom(bun.default_allocator.dupe(u8, source.path.text)), - .input_loader = .file, - .output_kind = .asset, - .loader = loader, - .hash = content_hashes_for_additional_files[index], - .side = .client, - .entry_point_index = null, - .is_executable = false, - })) catch unreachable; - additional_files[index].append(this.allocator(), AdditionalFile{ - .output_file = @as(u32, @truncate(additional_output_files.items.len - 1)), - }) catch |err| bun.handleOom(err); - } - } - - this.graph.additional_output_files = additional_output_files.moveToUnmanaged(); - } - } - - pub const JSBundleThread = @import("../bundler_jsc/JSBundleCompletionTask.zig").JSBundleThread; - pub const createAndScheduleCompletionTask = @import("../bundler_jsc/JSBundleCompletionTask.zig").createAndScheduleCompletionTask; - pub const generateFromJavaScript = @import("../bundler_jsc/JSBundleCompletionTask.zig").generateFromJavaScript; - - pub const BuildResult = struct { - output_files: std.array_list.Managed(options.OutputFile), - metafile: ?[]const u8 = null, - metafile_markdown: ?[]const u8 = null, - - pub fn deinit(this: *BuildResult) void { - for (this.output_files.items) |*output_file| { - output_file.deinit(); - } - - this.output_files.clearAndFree(); - - if (this.metafile) |mf| { - bun.default_allocator.free(mf); - this.metafile = null; - } - - if (this.metafile_markdown) |md| { - bun.default_allocator.free(md); - this.metafile_markdown = null; - } - } - }; - - pub const Result = union(enum) { - pending: void, - err: anyerror, - value: BuildResult, - - pub fn deinit(this: *Result) void { - switch (this.*) { - .value => |*value| { - value.deinit(); - }, - else => {}, - } - } - }; - - pub const JSBundleCompletionTask = @import("../bundler_jsc/JSBundleCompletionTask.zig").JSBundleCompletionTask; - - pub fn onLoadAsync(this: *BundleV2, load: *bun.jsc.API.JSBundler.Load) void { - switch (this.loop().*) { - .js => |jsc_event_loop| { - jsc_event_loop.enqueueTaskConcurrent(jsc.ConcurrentTask.fromCallback(load, onLoadFromJsLoop)); - }, - .mini => |*mini| { - mini.enqueueTaskConcurrentWithExtraCtx( - bun.jsc.API.JSBundler.Load, - BundleV2, - load, - BundleV2.onLoad, - .task, - ); - }, - } - } - - pub fn onResolveAsync(this: *BundleV2, resolve: *bun.jsc.API.JSBundler.Resolve) void { - switch (this.loop().*) { - .js => |jsc_event_loop| { - jsc_event_loop.enqueueTaskConcurrent(jsc.ConcurrentTask.fromCallback(resolve, onResolveFromJsLoop)); - }, - .mini => |*mini| { - mini.enqueueTaskConcurrentWithExtraCtx( - bun.jsc.API.JSBundler.Resolve, - BundleV2, - resolve, - BundleV2.onResolve, - .task, - ); - }, - } - } - - pub fn onLoadFromJsLoop(load: *bun.jsc.API.JSBundler.Load) void { - onLoad(load, load.bv2); - } - - pub fn onLoad(load: *bun.jsc.API.JSBundler.Load, this: *BundleV2) void { - debug("onLoad: ({d}, {s})", .{ load.source_index.get(), @tagName(load.value) }); - defer load.deinit(); - defer { - if (comptime FeatureFlags.help_catch_memory_issues) { - this.graph.heap.helpCatchMemoryIssues(); - } - } - const log = this.transpiler.log; - - // TODO: watcher - - switch (load.value.consume()) { - .no_match => { - const source = &this.graph.input_files.items(.source)[load.source_index.get()]; - // If it's a file namespace, we should run it through the parser like normal. - // The file could be on disk. - if (source.path.isFile()) { - this.graph.pool.schedule(load.parse_task); - return; - } - - // When it's not a file, this is a build error and we should report it. - // we have no way of loading non-files. - log.addErrorFmt(source, Logger.Loc.Empty, bun.default_allocator, "Module not found {f} in namespace {f}", .{ - bun.fmt.quote(source.path.pretty), - bun.fmt.quote(source.path.namespace), - }) catch {}; - - // An error occurred, prevent spinning the event loop forever - this.decrementScanCounter(); - }, - .success => |code| { - // When a plugin returns a file loader, we always need to populate additional_files - const should_copy_for_bundling = code.loader.shouldCopyForBundling(); - if (should_copy_for_bundling) { - const source_index = load.source_index; - var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = source_index.get() })); - this.graph.input_files.items(.side_effects)[source_index.get()] = .no_side_effects__pure_data; - this.graph.estimated_file_loader_count += 1; - } - this.graph.input_files.items(.loader)[load.source_index.get()] = code.loader; - this.graph.input_files.items(.source)[load.source_index.get()].contents = code.source_code; - this.graph.input_files.items(.flags)[load.source_index.get()].is_plugin_file = true; - var parse_task = load.parse_task; - parse_task.loader = code.loader; - if (!should_copy_for_bundling) this.free_list.append(code.source_code) catch unreachable; - parse_task.contents_or_fd = .{ - .contents = code.source_code, - }; - this.graph.pool.schedule(parse_task); - - if (this.bun_watcher) |watcher| add_watchers: { - if (!this.shouldAddWatcherPlugin(load.namespace, load.path)) break :add_watchers; - - // TODO: support explicit watchFiles array. this is not done - // right now because DevServer requires a table to map - // watched files and dirs to their respective dependants. - const fd = if (bun.Watcher.requires_file_descriptors) - switch (bun.sys.open( - &(std.posix.toPosixPath(load.path) catch break :add_watchers), - bun.Watcher.watch_open_flags, - 0, - )) { - .result => |fd| fd, - .err => break :add_watchers, - } - else - bun.invalid_fd; - - _ = watcher.addFile( - fd, - load.path, - bun.Watcher.getHash(load.path), - code.loader, - bun.invalid_fd, - null, - true, - ); - } - }, - .err => |msg| { - if (this.transpiler.options.dev_server) |dev| { - const source = &this.graph.input_files.items(.source)[load.source_index.get()]; - // A stack-allocated Log object containing the singular message - var msg_mut = msg; - const temp_log: Logger.Log = .{ - .clone_line_text = false, - .errors = @intFromBool(msg.kind == .err), - .warnings = @intFromBool(msg.kind == .warn), - .msgs = std.array_list.Managed(Logger.Msg).fromOwnedSlice(this.allocator(), (&msg_mut)[0..1]), - }; - dev.handleParseTaskFailure( - error.Plugin, - load.bakeGraph(), - source.path.keyForIncrementalGraph(), - &temp_log, - this, - ) catch |err| bun.handleOom(err); - } else { - bun.handleOom(log.msgs.append(msg)); - log.errors += @intFromBool(msg.kind == .err); - log.warnings += @intFromBool(msg.kind == .warn); - } - - // An error occurred, prevent spinning the event loop forever - this.decrementScanCounter(); - }, - .pending, .consumed => unreachable, - } - } - - pub fn onResolveFromJsLoop(resolve: *bun.jsc.API.JSBundler.Resolve) void { - onResolve(resolve, resolve.bv2); - } - - pub fn onResolve(resolve: *bun.jsc.API.JSBundler.Resolve, this: *BundleV2) void { - defer resolve.deinit(); - defer this.decrementScanCounter(); - debug("onResolve: ({s}:{s}, {s})", .{ resolve.import_record.namespace, resolve.import_record.specifier, @tagName(resolve.value) }); - - defer { - if (comptime FeatureFlags.help_catch_memory_issues) { - this.graph.heap.helpCatchMemoryIssues(); - } - } - - switch (resolve.value.consume()) { - .no_match => { - // If it's a file namespace, we should run it through the resolver like normal. - // - // The file could be on disk. - if (strings.eqlComptime(resolve.import_record.namespace, "file")) { - if (resolve.import_record.kind == .entry_point_build) { - const target = resolve.import_record.original_target; - const resolved = this.transpilerForTarget(target).resolveEntryPoint(resolve.import_record.specifier) catch { - return; - }; - const source_index = this.enqueueEntryItem(resolved, true, target) catch { - return; - }; - - // Store the original entry point name for virtual entries that fall back to file resolution - if (source_index) |idx| { - this.graph.entry_point_original_names.put(this.allocator(), idx, resolve.import_record.specifier) catch |err| bun.handleOom(err); - } - return; - } - - this.runResolver(resolve.import_record, resolve.import_record.original_target); - return; - } - - const log = this.logForResolutionFailures(resolve.import_record.source_file, resolve.import_record.original_target.bakeGraph()); - - // When it's not a file, this is an error and we should report it. - // - // We have no way of loading non-files. - if (resolve.import_record.kind == .entry_point_build) { - log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "Module not found {f} in namespace {f}", .{ - bun.fmt.quote(resolve.import_record.specifier), - bun.fmt.quote(resolve.import_record.namespace), - }) catch {}; - } else { - const source = &this.graph.input_files.items(.source)[resolve.import_record.importer_source_index]; - log.addRangeErrorFmt( - source, - resolve.import_record.range, - bun.default_allocator, - "Module not found {f} in namespace {f}", - .{ - bun.fmt.quote(resolve.import_record.specifier), - bun.fmt.quote(resolve.import_record.namespace), - }, - ) catch {}; - } - }, - .success => |result| { - var out_source_index: ?Index = null; - if (!result.external) { - var path = Fs.Path.init(result.path); - if (result.namespace.len == 0 or strings.eqlComptime(result.namespace, "file")) { - path.namespace = "file"; - } else { - path.namespace = result.namespace; - } - - const existing = this.pathToSourceIndexMap(resolve.import_record.original_target) - .getOrPutPath(this.allocator(), &path) catch |err| bun.handleOom(err); - if (!existing.found_existing) { - this.free_list.appendSlice(&.{ result.namespace, result.path }) catch {}; - path = bun.handleOom(this.pathWithPrettyInitialized(path, resolve.import_record.original_target)); - existing.key_ptr.* = path.text; - - // We need to parse this - const source_index = Index.init(@as(u32, @intCast(this.graph.ast.len))); - existing.value_ptr.* = source_index.get(); - out_source_index = source_index; - this.graph.ast.append(this.allocator(), JSAst.empty) catch unreachable; - const loader = path.loader(&this.transpiler.options.loaders) orelse options.Loader.file; - - this.graph.input_files.append(this.allocator(), .{ - .source = .{ - .path = path, - .contents = "", - .index = source_index, - }, - .loader = loader, - .side_effects = .has_side_effects, - }) catch unreachable; - var task = bun.default_allocator.create(ParseTask) catch unreachable; - task.* = ParseTask{ - .ctx = this, - .path = path, - // unknown at this point: - .contents_or_fd = .{ - .fd = .{ - .dir = bun.invalid_fd, - .file = bun.invalid_fd, - }, - }, - .side_effects = .has_side_effects, - .jsx = this.transpilerForTarget(resolve.import_record.original_target).options.jsx, - .source_index = source_index, - .module_type = .unknown, - .loader = loader, - .tree_shaking = this.linker.options.tree_shaking, - .known_target = resolve.import_record.original_target, - }; - task.task.node.next = null; - task.io_task.node.next = null; - this.incrementScanCounter(); - - if (!this.enqueueOnLoadPluginIfNeeded(task)) { - if (loader.shouldCopyForBundling()) { - var additional_files: *BabyList(AdditionalFile) = &this.graph.input_files.items(.additional_files)[source_index.get()]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = task.source_index.get() })); - this.graph.input_files.items(.side_effects)[source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; - this.graph.estimated_file_loader_count += 1; - } - - this.graph.pool.schedule(task); - } - } else { - out_source_index = Index.init(existing.value_ptr.*); - bun.default_allocator.free(result.namespace); - bun.default_allocator.free(result.path); - } - } else { - bun.default_allocator.free(result.namespace); - bun.default_allocator.free(result.path); - } - - if (out_source_index) |source_index| { - if (resolve.import_record.kind == .entry_point_build) { - this.graph.entry_points.append(this.allocator(), source_index) catch |err| bun.handleOom(err); - - // Store the original entry point name for virtual entries - // This preserves the original name for output file naming - this.graph.entry_point_original_names.put(this.allocator(), source_index.get(), resolve.import_record.specifier) catch |err| bun.handleOom(err); - } else { - const source_import_records = &this.graph.ast.items(.import_records)[resolve.import_record.importer_source_index]; - if (source_import_records.len <= resolve.import_record.import_record_index) { - const entry = this.resolve_tasks_waiting_for_import_source_index.getOrPut( - this.allocator(), - resolve.import_record.importer_source_index, - ) catch |err| bun.handleOom(err); - if (!entry.found_existing) { - entry.value_ptr.* = .{}; - } - entry.value_ptr.append( - this.allocator(), - .{ - .to_source_index = source_index, - .import_record_index = resolve.import_record.import_record_index, - }, - ) catch |err| bun.handleOom(err); - } else { - const import_record: *ImportRecord = &source_import_records.slice()[resolve.import_record.import_record_index]; - import_record.source_index = source_index; - } - } - } - }, - .err => |err| { - const log = this.logForResolutionFailures(resolve.import_record.source_file, resolve.import_record.original_target.bakeGraph()); - log.msgs.append(err) catch unreachable; - log.errors += @as(u32, @intFromBool(err.kind == .err)); - log.warnings += @as(u32, @intFromBool(err.kind == .warn)); - }, - .pending, .consumed => unreachable, - } - } - - pub fn deinitWithoutFreeingArena(this: *BundleV2) void { - { - // We do this first to make it harder for any dangling pointers to data to be used in there. - var on_parse_finalizers = this.finalizers; - this.finalizers = .{}; - for (on_parse_finalizers.items) |finalizer| { - finalizer.call(); - } - on_parse_finalizers.deinit(bun.default_allocator); - } - - defer { - this.graph.ast.deinit(this.allocator()); - this.graph.input_files.deinit(this.allocator()); - this.graph.entry_points.deinit(this.allocator()); - this.graph.entry_point_original_names.deinit(this.allocator()); - } - - if (this.graph.pool.workers_assignments.count() > 0) { - { - this.graph.pool.workers_assignments_lock.lock(); - defer this.graph.pool.workers_assignments_lock.unlock(); - for (this.graph.pool.workers_assignments.values()) |worker| { - worker.deinitSoon(); - } - this.graph.pool.workers_assignments.deinit(); - } - - this.graph.pool.worker_pool.wakeForIdleEvents(); - } - this.graph.pool.deinit(); - - for (this.free_list.items) |free| { - bun.default_allocator.free(free); - } - - this.free_list.clearAndFree(); - } - - pub fn runFromJSInNewThread( - this: *BundleV2, - entry_points: []const []const u8, - ) !BuildResult { - this.unique_key = generateUniqueKey(); - - if (this.transpiler.log.errors > 0) { - return error.BuildFailed; - } - - this.graph.heap.helpCatchMemoryIssues(); - - try this.enqueueEntryPoints(.normal, entry_points); - - // We must wait for all the parse tasks to complete, even if there are errors. - this.waitForParse(); - - this.graph.heap.helpCatchMemoryIssues(); - - if (this.transpiler.log.errors > 0) { - return error.BuildFailed; - } - - this.scanForSecondaryPaths(); - - try this.processServerComponentManifestFiles(); - - this.graph.heap.helpCatchMemoryIssues(); - - try this.cloneAST(); - - this.graph.heap.helpCatchMemoryIssues(); - - const reachable_files = try this.findReachableFiles(); - - try this.processFilesToCopy(reachable_files); - - try this.addServerComponentBoundariesAsExtraEntryPoints(); - - const chunks = try this.linker.link( - this, - this.graph.entry_points.items, - this.graph.server_component_boundaries, - reachable_files, - ); - - if (this.transpiler.log.errors > 0) { - return error.BuildFailed; - } - - var output_files = try this.linker.generateChunksInParallel(chunks, false); - - // Generate metafile if requested - const metafile: ?[]const u8 = if (this.linker.options.metafile) - LinkerContext.MetafileBuilder.generate(bun.default_allocator, &this.linker, chunks) catch |err| blk: { - bun.Output.warn("Failed to generate metafile: {s}", .{@errorName(err)}); - break :blk null; - } - else - null; - - // Generate markdown if metafile was generated and path specified - const metafile_markdown: ?[]const u8 = if (this.linker.options.metafile_markdown_path.len > 0 and metafile != null) - LinkerContext.MetafileBuilder.generateMarkdown(bun.default_allocator, metafile.?) catch |err| blk: { - bun.Output.warn("Failed to generate metafile markdown: {s}", .{@errorName(err)}); - break :blk null; - } - else - null; - - // Write metafile outputs to disk and add them as OutputFiles. - // Metafile paths are relative to outdir, like all other output files. - const outdir = this.linker.resolver.opts.output_dir; - if (this.linker.options.metafile_json_path.len > 0) { - if (metafile) |mf| { - try writeMetafileOutput(&output_files, outdir, this.linker.options.metafile_json_path, mf, .@"metafile-json"); - } - } - if (this.linker.options.metafile_markdown_path.len > 0) { - if (metafile_markdown) |md| { - try writeMetafileOutput(&output_files, outdir, this.linker.options.metafile_markdown_path, md, .@"metafile-markdown"); - } - } - - return .{ - .output_files = output_files, - .metafile = metafile, - .metafile_markdown = metafile_markdown, - }; - } - - /// Writes a metafile (JSON or markdown) to disk and appends it to the output_files list. - /// Metafile paths are relative to outdir, like all other output files. - fn writeMetafileOutput( - output_files: *std.array_list.Managed(options.OutputFile), - outdir: []const u8, - file_path: []const u8, - content: []const u8, - output_kind: jsc.API.BuildArtifact.OutputKind, - ) !void { - if (outdir.len > 0) { - // Open the output directory - var root_dir = bun.FD.cwd().stdDir().makeOpenPath(outdir, .{}) catch |err| { - bun.Output.warn("Failed to open output directory '{s}': {s}", .{ outdir, @errorName(err) }); - return; - }; - defer root_dir.close(); - - // Create parent directories if needed (relative to outdir) - if (std.fs.path.dirname(file_path)) |parent| { - if (parent.len > 0) { - root_dir.makePath(parent) catch {}; - } - } - - // Write to disk relative to outdir - var path_buf: bun.PathBuffer = undefined; - _ = jsc.Node.fs.NodeFS.writeFileWithPathBuffer(&path_buf, .{ - .data = .{ .buffer = .{ - .buffer = .{ - .ptr = @constCast(content.ptr), - .len = @as(u32, @truncate(content.len)), - .byte_len = @as(u32, @truncate(content.len)), - }, - } }, - .encoding = .buffer, - .mode = 0o644, - .dirfd = bun.FD.fromStdDir(root_dir), - .file = .{ .path = .{ - .string = bun.PathString.init(file_path), - } }, - }).unwrap() catch |err| { - bun.Output.warn("Failed to write metafile to '{s}': {s}", .{ file_path, @errorName(err) }); - }; - } - - // Add as OutputFile so it appears in result.outputs - const is_json = output_kind == .@"metafile-json"; - try output_files.append(options.OutputFile.init(.{ - .loader = if (is_json) .json else .file, - .input_loader = if (is_json) .json else .file, - .input_path = bun.handleOom(bun.default_allocator.dupe(u8, if (is_json) "metafile.json" else "metafile.md")), - .output_path = bun.handleOom(bun.default_allocator.dupe(u8, file_path)), - .data = .{ .saved = content.len }, - .output_kind = output_kind, - .is_executable = false, - .side = null, - .entry_point_index = null, - })); - } - - fn shouldAddWatcherPlugin(bv2: *BundleV2, namespace: []const u8, path: []const u8) bool { - return bun.strings.eqlComptime(namespace, "file") and - std.fs.path.isAbsolute(path) and - bv2.shouldAddWatcher(path); - } - - fn shouldAddWatcher(bv2: *BundleV2, path: []const u8) bool { - return if (bv2.transpiler.options.dev_server != null) - bun.strings.indexOf(path, "/node_modules/") == null and - (if (Environment.isWindows) bun.strings.indexOf(path, "\\node_modules\\") == null else true) - else - true; // `bun build --watch` has always watched node_modules - } - - /// Dev Server uses this instead to run a subset of the transpiler, and to run it asynchronously. - pub fn startFromBakeDevServer(this: *BundleV2, bake_entry_points: bake.DevServer.EntryPointList) !DevServerInput { - this.unique_key = generateUniqueKey(); - - this.graph.heap.helpCatchMemoryIssues(); - - var ctx: DevServerInput = .{ - .css_entry_points = .{}, - }; - try this.enqueueEntryPoints(.dev_server, .{ - .files = bake_entry_points, - .css_data = &ctx.css_entry_points, - }); - - this.graph.heap.helpCatchMemoryIssues(); - - return ctx; - } - - pub fn finishFromBakeDevServer(this: *BundleV2, dev_server: *bake.DevServer) bun.OOM!void { - const start = &dev_server.current_bundle.?.start_data; - - this.graph.heap.helpCatchMemoryIssues(); - - try this.cloneAST(); - - this.graph.heap.helpCatchMemoryIssues(); - - this.dynamic_import_entry_points = .init(this.allocator()); - var html_files: std.AutoArrayHashMapUnmanaged(Index, void) = .{}; - - // Separate non-failing files into two lists: JS and CSS - const js_reachable_files = reachable_files: { - var css_total_files = try std.ArrayListUnmanaged(Index).initCapacity(this.allocator(), this.graph.css_file_count); - try start.css_entry_points.ensureUnusedCapacity(this.allocator(), this.graph.css_file_count); - var js_files = try std.ArrayListUnmanaged(Index).initCapacity(this.allocator(), this.graph.ast.len - this.graph.css_file_count - 1); - - const asts = this.graph.ast.slice(); - const css_asts = asts.items(.css); - - const input_files = this.graph.input_files.slice(); - const loaders = input_files.items(.loader); - const sources = input_files.items(.source); - for ( - asts.items(.parts)[1..], - asts.items(.import_records)[1..], - css_asts[1..], - asts.items(.target)[1..], - 1.., - ) |part_list, import_records, maybe_css, target, index| { - // Dev Server proceeds even with failed files. - // These files are filtered out via the lack of any parts. - // - // Actual empty files will contain a part exporting an empty object. - if (part_list.len != 0) { - if (maybe_css != null) { - // CSS has restrictions on what files can be imported. - // This means the file can become an error after - // resolution, which is not usually the case. - css_total_files.appendAssumeCapacity(Index.init(index)); - var log = Logger.Log.init(this.allocator()); - defer log.deinit(); - if (this.linker.scanCSSImports( - @intCast(index), - import_records.slice(), - css_asts, - sources, - loaders, - &log, - ) == .errors) { - // TODO: it could be possible for a plugin to change - // the type of loader from whatever it was into a - // css-compatible loader. - try dev_server.handleParseTaskFailure( - error.InvalidCssImport, - .client, - sources[index].path.text, - &log, - this, - ); - // Since there is an error, do not treat it as a - // valid CSS chunk. - _ = start.css_entry_points.swapRemove(Index.init(index)); - } - } else { - // HTML files are special cased because they correspond - // to routes in DevServer. They have a JS chunk too, - // derived off of the import record list. - if (loaders[index] == .html) { - try html_files.put(this.allocator(), Index.init(index), {}); - } else { - js_files.appendAssumeCapacity(Index.init(index)); - - // Mark every part live. - for (part_list.slice()) |*p| { - p.is_live = true; - } - } - - // Discover all CSS roots. - for (import_records.slice()) |*record| { - if (!record.source_index.isValid()) continue; - if (loaders[record.source_index.get()] != .css) continue; - if (asts.items(.parts)[record.source_index.get()].len == 0) { - record.source_index = Index.invalid; - continue; - } - - const gop = start.css_entry_points.getOrPutAssumeCapacity(record.source_index); - if (target != .browser) - gop.value_ptr.* = .{ .imported_on_server = true } - else if (!gop.found_existing) - gop.value_ptr.* = .{ .imported_on_server = false }; - } - } - } else { - // Treat empty CSS files for removal. - _ = start.css_entry_points.swapRemove(Index.init(index)); - } - } - - // Find CSS entry points. Originally, this was computed up front, but - // failed files do not remember their loader, and plugins can - // asynchronously decide a file is CSS. - const css = asts.items(.css); - for (this.graph.entry_points.items) |entry_point| { - if (css[entry_point.get()] != null) { - try start.css_entry_points.put( - this.allocator(), - entry_point, - .{ .imported_on_server = false }, - ); - } - } - - break :reachable_files js_files.items; - }; - - this.graph.heap.helpCatchMemoryIssues(); - - // HMR skips most of the linker! All linking errors are converted into - // runtime errors to avoid a more complicated dependency graph. For - // example, if you remove an exported symbol, we only rebuild the - // changed file, then detect the missing export at runtime. - // - // Additionally, notice that we run this code generation even if we have - // files that failed. This allows having a large build graph (importing - // a new npm dependency), where one file that fails doesnt prevent the - // passing files to get cached in the incremental graph. - - // The linker still has to be initialized as code generation expects - // much of its state to be valid memory, even if empty. - try this.linker.load( - this, - this.graph.entry_points.items, - this.graph.server_component_boundaries, - js_reachable_files, - ); - - this.graph.heap.helpCatchMemoryIssues(); - - // Compute line offset tables and quoted contents, used in source maps. - // Quoted contents will be default-allocated - if (Environment.isDebug) for (js_reachable_files) |idx| { - bun.assert(this.graph.ast.items(.parts)[idx.get()].len != 0); // will create a memory leak - }; - this.linker.computeDataForSourceMap(@as([]Index.Int, @ptrCast(js_reachable_files))); - errdefer { - // reminder that the caller cannot handle this error, since source contents - // are default-allocated. the only option is to crash here. - bun.outOfMemory(); - } - - this.graph.heap.helpCatchMemoryIssues(); - - // Generate chunks - const js_part_ranges = try this.allocator().alloc(PartRange, js_reachable_files.len); - const parts = this.graph.ast.items(.parts); - for (js_reachable_files, js_part_ranges) |source_index, *part_range| { - part_range.* = .{ - .source_index = source_index, - .part_index_begin = 0, - .part_index_end = parts[source_index.get()].len, - }; - } - - const chunks = try this.allocator().alloc( - Chunk, - 1 + start.css_entry_points.count() + html_files.count(), - ); - - // First is a chunk to contain all JavaScript modules. - chunks[0] = .{ - .entry_point = .{ - .entry_point_id = 0, - .source_index = 0, - .is_entry_point = true, - }, - .content = .{ - .javascript = .{ - // TODO(@paperclover): remove this ptrCast when Source Index is fixed - .files_in_chunk_order = @ptrCast(js_reachable_files), - .parts_in_chunk_in_order = js_part_ranges, - }, - }, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - }; - - // Then all the distinct CSS bundles (these are JS->CSS, not CSS->CSS) - for (chunks[1..][0..start.css_entry_points.count()], start.css_entry_points.keys()) |*chunk, entry_point| { - const order = this.linker.findImportedFilesInCSSOrder(this.allocator(), &.{entry_point}); - chunk.* = .{ - .entry_point = .{ - .entry_point_id = @intCast(entry_point.get()), - .source_index = entry_point.get(), - .is_entry_point = false, - }, - .content = .{ - .css = .{ - .imports_in_chunk_in_order = order, - .asts = try this.allocator().alloc(bun.css.BundlerStyleSheet, order.len), - }, - }, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - }; - } - - // Then all HTML files - for (html_files.keys(), chunks[1 + start.css_entry_points.count() ..]) |source_index, *chunk| { - chunk.* = .{ - .entry_point = .{ - .entry_point_id = @intCast(source_index.get()), - .source_index = source_index.get(), - .is_entry_point = false, - }, - .content = .html, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - }; - } - - this.graph.heap.helpCatchMemoryIssues(); - - try this.linker.generateChunksInParallel(chunks, true); - errdefer { - // reminder that the caller cannot handle this error, since - // the contents in this generation are default-allocated. - bun.outOfMemory(); - } - - this.graph.heap.helpCatchMemoryIssues(); - - try dev_server.finalizeBundle(this, &.{ - .chunks = chunks, - .css_file_list = start.css_entry_points, - .html_files = html_files, - }); - } - - pub fn enqueueOnResolvePluginIfNeeded( - this: *BundleV2, - source_index: Index.Int, - import_record: *const ImportRecord, - source_file: []const u8, - import_record_index: u32, - original_target: options.Target, - ) bool { - if (this.plugins) |plugins| { - if (plugins.hasAnyMatches(&import_record.path, false)) { - // This is where onResolve plugins are enqueued - var resolve: *jsc.API.JSBundler.Resolve = bun.default_allocator.create(jsc.API.JSBundler.Resolve) catch unreachable; - debug("enqueue onResolve: {s}:{s}", .{ - import_record.path.namespace, - import_record.path.text, - }); - this.incrementScanCounter(); - - resolve.* = jsc.API.JSBundler.Resolve.init(this, .{ - .kind = import_record.kind, - .source_file = source_file, - .namespace = import_record.path.namespace, - .specifier = import_record.path.text, - .importer_source_index = source_index, - .import_record_index = import_record_index, - .range = import_record.range, - .original_target = original_target, - }); - - resolve.dispatch(); - return true; - } - } - - return false; - } - - pub fn enqueueEntryPointOnResolvePluginIfNeeded( - this: *BundleV2, - entry_point: []const u8, - target: options.Target, - ) bool { - if (this.plugins) |plugins| { - var temp_path = Fs.Path.init(entry_point); - temp_path.namespace = "file"; - if (plugins.hasAnyMatches(&temp_path, false)) { - debug("Entry point '{s}' plugin match", .{entry_point}); - - var resolve: *jsc.API.JSBundler.Resolve = bun.default_allocator.create(jsc.API.JSBundler.Resolve) catch unreachable; - this.incrementScanCounter(); - - resolve.* = jsc.API.JSBundler.Resolve.init(this, .{ - .kind = .entry_point_build, - .source_file = "", // No importer for entry points - .namespace = "file", - .specifier = entry_point, - .importer_source_index = std.math.maxInt(u32), // Sentinel value for entry points - .import_record_index = 0, - .range = Logger.Range.None, - .original_target = target, - }); - - resolve.dispatch(); - return true; - } - } - return false; - } - - pub fn enqueueOnLoadPluginIfNeeded(this: *BundleV2, parse: *ParseTask) bool { - const had_matches = enqueueOnLoadPluginIfNeededImpl(this, parse); - if (had_matches) return true; - - if (bun.strings.eqlComptime(parse.path.namespace, "dataurl")) { - const maybe_data_url = DataURL.parse(parse.path.text) catch return false; - const data_url = maybe_data_url orelse return false; - const maybe_decoded = data_url.decodeData(bun.default_allocator) catch return false; - bun.handleOom(this.free_list.append(maybe_decoded)); - parse.contents_or_fd = .{ - .contents = maybe_decoded, - }; - parse.loader = switch (data_url.decodeMimeType().category) { - .javascript => .js, - .css => .css, - .json => .json, - else => parse.loader, - }; - } - - return false; - } - - pub fn enqueueOnLoadPluginIfNeededImpl(this: *BundleV2, parse: *ParseTask) bool { - if (this.plugins) |plugins| { - if (plugins.hasAnyMatches(&parse.path, true)) { - // This is where onLoad plugins are enqueued - debug("enqueue onLoad: {s}:{s}", .{ - parse.path.namespace, - parse.path.text, - }); - const load = bun.handleOom(bun.default_allocator.create(jsc.API.JSBundler.Load)); - load.* = jsc.API.JSBundler.Load.init(this, parse); - load.dispatch(); - return true; - } - } - - return false; - } - - fn pathWithPrettyInitialized(this: *BundleV2, path: Fs.Path, target: options.Target) !Fs.Path { - return genericPathWithPrettyInitialized(path, target, this.transpiler.fs.top_level_dir, this.allocator()); - } - - fn reserveSourceIndexesForBake(this: *BundleV2) !void { - const fw = this.framework orelse return; - _ = fw.server_components orelse return; - - // Call this after - bun.assert(this.graph.input_files.len == 1); - bun.assert(this.graph.ast.len == 1); - - try this.graph.ast.ensureUnusedCapacity(this.allocator(), 2); - try this.graph.input_files.ensureUnusedCapacity(this.allocator(), 2); - - const server_source = bake.server_virtual_source; - const client_source = bake.client_virtual_source; - - this.graph.input_files.appendAssumeCapacity(.{ - .source = server_source, - .loader = .js, - .side_effects = .no_side_effects__pure_data, - }); - this.graph.input_files.appendAssumeCapacity(.{ - .source = client_source, - .loader = .js, - .side_effects = .no_side_effects__pure_data, - }); - - bun.assert(this.graph.input_files.items(.source)[Index.bake_server_data.get()].index.get() == Index.bake_server_data.get()); - bun.assert(this.graph.input_files.items(.source)[Index.bake_client_data.get()].index.get() == Index.bake_client_data.get()); - - this.graph.ast.appendAssumeCapacity(JSAst.empty); - this.graph.ast.appendAssumeCapacity(JSAst.empty); - } - - /// See barrel_imports.zig for barrel optimization implementation. - const applyBarrelOptimization = barrel_imports.applyBarrelOptimization; - const scheduleBarrelDeferredImports = barrel_imports.scheduleBarrelDeferredImports; - - /// Returns true when barrel optimization is enabled. Barrel optimization - /// can apply to any package with sideEffects: false or listed in - /// optimize_imports, so it is always enabled during bundling. - fn isBarrelOptimizationEnabled(this: *const BundleV2) bool { - _ = this; - return true; - } - - // TODO: remove ResolveQueue - // - // Moving this to the Bundle thread was a significant perf improvement on Linux for first builds - // - // The problem is that module resolution has many mutexes. - // The downside is cached resolutions are faster to do in threads since they only lock very briefly. - fn runResolutionForParseTask(parse_result: *ParseTask.Result, this: *BundleV2) ResolveQueue { - const result = &parse_result.value.success; - // Capture these before resolveImportRecords, since on error we overwrite - // parse_result.value (invalidating the `result` pointer). - const source_index = result.source.index; - const target = result.ast.target; - var resolve_result = this.resolveImportRecords(.{ - .import_records = &result.ast.import_records, - .source = &result.source, - .loader = result.loader, - .target = target, - }); - - if (resolve_result.last_error) |err| { - debug("failed with error: {s}", .{@errorName(err)}); - resolve_result.resolve_queue.clearAndFree(); - - // Preserve the parsed import_records on the graph so any plugin - // onResolve tasks already dispatched for *other* records in this - // same file can still dereference - // `graph.ast.items(.import_records)[importer_source_index]` when - // they complete. Without this, the graph entry stays at - // JSAst.empty and the deferred plugin callback index-out-of- - // bounds crashes in BundleV2.onResolve / runResolver. The linker - // never runs because `transpiler.log.errors > 0` aborts the - // build before link time, so saving the AST is safe. - this.graph.ast.items(.import_records)[source_index.get()] = result.ast.import_records; - - parse_result.value = .{ - .err = .{ - .err = err, - .step = .resolve, - .log = Logger.Log.init(bun.default_allocator), - .source_index = source_index, - .target = target, - }, - }; - } - - return resolve_result.resolve_queue; - } - - pub const ResolveImportRecordCtx = struct { - import_records: *ImportRecord.List, - source: *const Logger.Source, - loader: Loader, - target: options.Target, - }; - - pub const ResolveImportRecordResult = struct { - resolve_queue: ResolveQueue, - last_error: ?anyerror, - }; - - /// Resolve all unresolved import records for a module. Skips records that - /// are already resolved (valid source_index), unused, or internal. - /// Returns a resolve queue of new modules to schedule, plus any fatal error. - /// Used by both initial parse resolution and barrel un-deferral. - pub fn resolveImportRecords(this: *BundleV2, ctx: ResolveImportRecordCtx) ResolveImportRecordResult { - const source = ctx.source; - const loader = ctx.loader; - const source_dir = source.path.sourceDir(); - var estimated_resolve_queue_count: usize = 0; - for (ctx.import_records.slice()) |*import_record| { - if (import_record.flags.is_internal) { - import_record.tag = .runtime; - import_record.source_index = Index.runtime; - } - - // For non-dev-server builds, barrel-deferred records need their - // source_index cleared so they don't get linked. For dev server, - // skip this — is_unused is also set by ConvertESMExportsForHmr - // deduplication, and clearing those source_indices breaks module - // identity (e.g., __esModule on ESM namespace objects). - if (import_record.flags.is_unused and this.transpiler.options.dev_server == null) { - import_record.source_index = Index.invalid; - } - - estimated_resolve_queue_count += @as(usize, @intFromBool(!(import_record.flags.is_internal or import_record.flags.is_unused or import_record.source_index.isValid()))); - } - var resolve_queue = ResolveQueue.init(this.allocator()); - bun.handleOom(resolve_queue.ensureTotalCapacity(@intCast(estimated_resolve_queue_count))); - - var last_error: ?anyerror = null; - - outer: for (ctx.import_records.slice(), 0..) |*import_record, i| { - // Preserve original import specifier before resolution modifies path - if (import_record.original_path.len == 0) { - import_record.original_path = import_record.path.text; - } - - if ( - // Don't resolve TypeScript types - import_record.flags.is_unused or - - // Don't resolve the runtime - import_record.flags.is_internal or - - // Don't resolve pre-resolved imports - import_record.source_index.isValid()) - { - continue; - } - - if (this.framework) |fw| if (fw.server_components != null) { - switch (ctx.target.isServerSide()) { - inline else => |is_server| { - const src = if (is_server) bake.server_virtual_source else bake.client_virtual_source; - if (strings.eqlComptime(import_record.path.text, src.path.pretty)) { - if (this.transpiler.options.dev_server != null) { - import_record.flags.is_external_without_side_effects = true; - import_record.source_index = Index.invalid; - } else { - if (is_server) { - this.graph.kit_referenced_server_data = true; - } else { - this.graph.kit_referenced_client_data = true; - } - import_record.path.namespace = "bun"; - import_record.source_index = src.index; - } - continue; - } - }, - } - }; - - if (strings.eqlComptime(import_record.path.text, "bun:wrap")) { - import_record.path.namespace = "bun"; - import_record.tag = .runtime; - import_record.path.text = "wrap"; - import_record.source_index = .runtime; - continue; - } - - if (ctx.target.isBun()) { - if (jsc.ModuleLoader.HardcodedModule.Alias.get(import_record.path.text, .bun, .{ .rewrite_jest_for_tests = this.transpiler.options.rewrite_jest_for_tests })) |replacement| { - // When bundling node builtins, remove the "node:" prefix. - // This supports special use cases where the bundle is put - // into a non-node module resolver that doesn't support - // node's prefix. https://github.com/oven-sh/bun/issues/18545 - import_record.path.text = if (replacement.node_builtin and !replacement.node_only_prefix) - replacement.path[5..] - else - replacement.path; - import_record.tag = replacement.tag; - import_record.source_index = Index.invalid; - import_record.flags.is_external_without_side_effects = true; - continue; - } - - if (strings.hasPrefixComptime(import_record.path.text, "bun:")) { - import_record.path = Fs.Path.init(import_record.path.text["bun:".len..]); - import_record.path.namespace = "bun"; - import_record.source_index = Index.invalid; - import_record.flags.is_external_without_side_effects = true; - - // don't link bun - continue; - } - } - - // By default, we treat .sqlite files as external. - if (import_record.loader != null and import_record.loader.? == .sqlite) { - import_record.flags.is_external_without_side_effects = true; - continue; - } - - if (import_record.loader != null and import_record.loader.? == .sqlite_embedded) { - import_record.flags.is_external_without_side_effects = true; - } - - if (this.enqueueOnResolvePluginIfNeeded(source.index.get(), import_record, source.path.text, @as(u32, @truncate(i)), ctx.target)) { - continue; - } - - const transpiler: *Transpiler, const bake_graph: bake.Graph, const target: options.Target = - if (import_record.tag == .bake_resolve_to_ssr_graph) brk: { - if (this.framework == null) { - this.logForResolutionFailures(source.path.text, .ssr).addErrorFmt( - source, - import_record.range.loc, - this.allocator(), - "The 'bunBakeGraph' import attribute cannot be used outside of a Bun Bake bundle", - .{}, - ) catch @panic("unexpected log error"); - continue; - } - - const is_supported = this.framework.?.server_components != null and - this.framework.?.server_components.?.separate_ssr_graph; - if (!is_supported) { - this.logForResolutionFailures(source.path.text, .ssr).addErrorFmt( - source, - import_record.range.loc, - this.allocator(), - "Framework does not have a separate SSR graph to put this import into", - .{}, - ) catch @panic("unexpected log error"); - continue; - } - - break :brk .{ - this.ssr_transpiler, - .ssr, - .bake_server_components_ssr, - }; - } else .{ - this.transpilerForTarget(ctx.target), - ctx.target.bakeGraph(), - ctx.target, - }; - - // Check the FileMap first for in-memory files - if (this.file_map) |file_map| { - if (file_map.resolve(source.path.text, import_record.path.text)) |_file_map_result| { - var file_map_result = _file_map_result; - var path_primary = file_map_result.path_pair.primary; - const import_record_loader = import_record.loader orelse Fs.Path.init(path_primary.text).loader(&transpiler.options.loaders) orelse .file; - import_record.loader = import_record_loader; - - if (this.pathToSourceIndexMap(target).get(path_primary.text)) |id| { - import_record.source_index = .init(id); - continue; - } - - const resolve_entry = resolve_queue.getOrPut(path_primary.text) catch |err| bun.handleOom(err); - if (resolve_entry.found_existing) { - import_record.path = resolve_entry.value_ptr.*.path; - continue; - } - - // For virtual files, use the path text as-is (no relative path computation needed). - path_primary.pretty = bun.handleOom(this.allocator().dupe(u8, path_primary.text)); - import_record.path = path_primary; - resolve_entry.key_ptr.* = path_primary.text; - debug("created ParseTask from FileMap: {s}", .{path_primary.text}); - const resolve_task = bun.handleOom(bun.default_allocator.create(ParseTask)); - file_map_result.path_pair.primary = path_primary; - resolve_task.* = ParseTask.init(&file_map_result, Index.invalid, this); - resolve_task.known_target = target; - // Use transpiler JSX options, applying force_node_env like the disk path does - resolve_task.jsx = transpiler.options.jsx; - resolve_task.jsx.development = switch (transpiler.options.force_node_env) { - .development => true, - .production => false, - .unspecified => transpiler.options.jsx.development, - }; - resolve_task.loader = import_record_loader; - resolve_task.tree_shaking = transpiler.options.tree_shaking; - resolve_task.side_effects = .has_side_effects; - resolve_entry.value_ptr.* = resolve_task; - continue; - } - } - - var had_busted_dir_cache = false; - var resolve_result: _resolver.Result = inner: while (true) break transpiler.resolver.resolveWithFramework( - source_dir, - import_record.path.text, - import_record.kind, - ) catch |err| { - const log = this.logForResolutionFailures(source.path.text, bake_graph); - - // Only perform directory busting when hot-reloading is enabled - if (err == error.ModuleNotFound) { - if (this.bun_watcher != null) { - if (!had_busted_dir_cache) { - bun.Output.scoped(.watcher, .visible)("busting dir cache {s} -> {s}", .{ source.path.text, import_record.path.text }); - // Only re-query if we previously had something cached. - if (transpiler.resolver.bustDirCacheFromSpecifier( - source.path.text, - import_record.path.text, - )) { - had_busted_dir_cache = true; - continue :inner; - } - } - if (this.transpiler.options.dev_server) |dev| { - // Tell DevServer about the resolution failure. - dev.directory_watchers.trackResolutionFailure( - source.path.text, - import_record.path.text, - ctx.target.bakeGraph(), // use the source file target not the altered one - loader, - ) catch |e| bun.handleOom(e); - } - } - } - - // Disable failing packages from being printed. - // This may cause broken code to write. - // However, doing this means we tell them all the resolve errors - // Rather than just the first one. - import_record.path.is_disabled = true; - - switch (err) { - error.ModuleNotFound => { - const addError = Logger.Log.addResolveErrorWithTextDupe; - - if (!import_record.flags.handles_import_errors and !this.transpiler.options.ignore_module_resolution_errors) { - last_error = err; - if (isPackagePath(import_record.path.text)) { - if (ctx.target == .browser and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { - addError( - log, - source, - import_record.range, - this.allocator(), - "Browser build cannot {s} Node.js builtin: \"{s}\"{s}", - .{ - import_record.kind.errorLabel(), - import_record.path.text, - if (this.transpiler.options.dev_server == null) - ". To use Node.js builtins, set target to 'node' or 'bun'" - else - "", - }, - import_record.kind, - ) catch |e| bun.handleOom(e); - } else if (!ctx.target.isBun() and strings.eqlComptime(import_record.path.text, "bun")) { - addError( - log, - source, - import_record.range, - this.allocator(), - "Browser build cannot {s} Bun builtin: \"{s}\"{s}", - .{ - import_record.kind.errorLabel(), - import_record.path.text, - if (this.transpiler.options.dev_server == null) - ". When bundling for Bun, set target to 'bun'" - else - "", - }, - import_record.kind, - ) catch |e| bun.handleOom(e); - } else if (!ctx.target.isBun() and strings.hasPrefixComptime(import_record.path.text, "bun:")) { - addError( - log, - source, - import_record.range, - this.allocator(), - "Browser build cannot {s} Bun builtin: \"{s}\"{s}", - .{ - import_record.kind.errorLabel(), - import_record.path.text, - if (this.transpiler.options.dev_server == null) - ". When bundling for Bun, set target to 'bun'" - else - "", - }, - import_record.kind, - ) catch |e| bun.handleOom(e); - } else { - addError( - log, - source, - import_record.range, - this.allocator(), - "Could not resolve: \"{s}\". Maybe you need to \"bun install\"?", - .{import_record.path.text}, - import_record.kind, - ) catch |e| bun.handleOom(e); - } - } else { - const buf = bun.path_buffer_pool.get(); - defer bun.path_buffer_pool.put(buf); - const specifier_to_use = if (loader == .html and bun.strings.hasPrefix(import_record.path.text, bun.fs.FileSystem.instance.top_level_dir)) brk: { - const specifier_to_use = import_record.path.text[bun.fs.FileSystem.instance.top_level_dir.len..]; - if (Environment.isWindows) { - break :brk bun.path.pathToPosixBuf(u8, specifier_to_use, buf); - } - break :brk specifier_to_use; - } else import_record.path.text; - addError( - log, - source, - import_record.range, - this.allocator(), - "Could not resolve: \"{s}\"", - .{specifier_to_use}, - import_record.kind, - ) catch |e| bun.handleOom(e); - } - } - }, - // assume other errors are already in the log - else => { - last_error = err; - }, - } - continue :outer; - }; - // if there were errors, lets go ahead and collect them all - if (last_error != null) continue; - - const path: *Fs.Path = resolve_result.path() orelse { - import_record.path.is_disabled = true; - import_record.source_index = Index.invalid; - - continue; - }; - - if (resolve_result.flags.is_external) { - if (resolve_result.flags.is_external_and_rewrite_import_path and !strings.eqlLong(resolve_result.path_pair.primary.text, import_record.path.text, true)) { - import_record.path = resolve_result.path_pair.primary; - } - import_record.flags.is_external_without_side_effects = resolve_result.primary_side_effects_data != .has_side_effects; - continue; - } - - if (this.transpiler.options.dev_server) |dev_server| brk: { - if (path.loader(&this.transpiler.options.loaders) == .html and (import_record.loader == null or import_record.loader.? == .html)) { - // This use case is currently not supported. This error - // blocks an assertion failure because the DevServer - // reserves the HTML file's spot in IncrementalGraph for the - // route definition. - const log = this.logForResolutionFailures(source.path.text, bake_graph); - log.addRangeErrorFmt( - source, - import_record.range, - this.allocator(), - "Browser builds cannot import HTML files.", - .{}, - ) catch |err| bun.handleOom(err); - continue; - } - - if (loader == .css) { - // Do not use cached files for CSS. - break :brk; - } - - import_record.source_index = Index.invalid; - - if (dev_server.isFileCached(path.text, bake_graph)) |entry| { - const rel = bun.path.relativePlatform(this.transpiler.fs.top_level_dir, path.text, .loose, false); - if (loader == .html and entry.kind == .asset) { - // Overload `path.text` to point to the final URL - // This information cannot be queried while printing because a lock wouldn't get held. - const hash = dev_server.assets.getHash(path.text) orelse @panic("cached asset not found"); - import_record.path.text = path.text; - import_record.path.namespace = "file"; - import_record.path.pretty = std.fmt.allocPrint(this.allocator(), bun.bake.DevServer.asset_prefix ++ "/{s}{s}", .{ - &std.fmt.bytesToHex(std.mem.asBytes(&hash), .lower), - std.fs.path.extension(path.text), - }) catch |err| bun.handleOom(err); - import_record.path.is_disabled = false; - } else { - import_record.path.text = path.text; - import_record.path.pretty = rel; - import_record.path = bun.handleOom(this.pathWithPrettyInitialized(path.*, target)); - if (loader == .html or entry.kind == .css) { - import_record.path.is_disabled = true; - } - } - continue; - } - } - - const import_record_loader = brk: { - const resolved_loader = import_record.loader orelse path.loader(&transpiler.options.loaders) orelse .file; - // When an HTML file references a URL asset (e.g. ), - // the file must be copied to the output directory as-is. If the resolved loader would - // parse/transform the file (e.g. .json, .toml) rather than copy it, force the .file loader - // so that `shouldCopyForBundling()` returns true and the asset is emitted. - // Only do this for HTML sources — CSS url() imports should retain their original behavior. - if (loader == .html and import_record.kind == .url and !resolved_loader.shouldCopyForBundling() and - !resolved_loader.isJavaScriptLike() and !resolved_loader.isCSS() and resolved_loader != .html) - { - break :brk Loader.file; - } - break :brk resolved_loader; - }; - import_record.loader = import_record_loader; - - const is_html_entrypoint = import_record_loader == .html and target.isServerSide() and this.transpiler.options.dev_server == null; - - if (this.pathToSourceIndexMap(target).get(path.text)) |id| { - if (this.transpiler.options.dev_server != null and loader != .html) { - import_record.path = this.graph.input_files.items(.source)[id].path; - } else { - import_record.source_index = .init(id); - } - continue; - } - - if (is_html_entrypoint) { - import_record.kind = .html_manifest; - } - - const resolve_entry = resolve_queue.getOrPut(path.text) catch |err| bun.handleOom(err); - if (resolve_entry.found_existing) { - import_record.path = resolve_entry.value_ptr.*.path; - continue; - } - - path.* = bun.handleOom(this.pathWithPrettyInitialized(path.*, target)); - - import_record.path = path.*; - resolve_entry.key_ptr.* = path.text; - debug("created ParseTask: {s}", .{path.text}); - const resolve_task = bun.handleOom(bun.default_allocator.create(ParseTask)); - resolve_task.* = ParseTask.init(&resolve_result, Index.invalid, this); - - resolve_task.known_target = if (import_record.kind == .html_manifest) - .browser - else - target; - - resolve_task.jsx = resolve_result.jsx; - resolve_task.jsx.development = switch (transpiler.options.force_node_env) { - .development => true, - .production => false, - .unspecified => transpiler.options.jsx.development, - }; - - resolve_task.loader = import_record_loader; - resolve_task.tree_shaking = transpiler.options.tree_shaking; - resolve_entry.value_ptr.* = resolve_task; - if (resolve_result.path_pair.secondary) |*secondary| { - if (!secondary.is_disabled and - secondary != path and - !strings.eqlLong(secondary.text, path.text, true)) - { - resolve_task.secondary_path_for_commonjs_interop = secondary.dupeAlloc(this.allocator()) catch |err| bun.handleOom(err); - } - } - - if (is_html_entrypoint) { - this.generateServerHTMLModule(path, target, import_record, path.text) catch unreachable; - } - } - - return .{ .resolve_queue = resolve_queue, .last_error = last_error }; - } - - /// Process a resolve queue: create input file slots and schedule parse tasks. - /// Returns the number of newly scheduled tasks (for pending_items accounting). - pub fn processResolveQueue(this: *BundleV2, resolve_queue: ResolveQueue, target: options.Target, importer_source_index: Index.Int) i32 { - var diff: i32 = 0; - const graph = &this.graph; - var iter = resolve_queue.iterator(); - const path_to_source_index_map = this.pathToSourceIndexMap(target); - while (iter.next()) |entry| { - const value: *ParseTask = entry.value_ptr.*; - const loader = value.loader orelse value.path.loader(&this.transpiler.options.loaders) orelse options.Loader.file; - const is_html_entrypoint = loader == .html and target.isServerSide() and this.transpiler.options.dev_server == null; - const map: *PathToSourceIndexMap = if (is_html_entrypoint) this.pathToSourceIndexMap(.browser) else path_to_source_index_map; - const existing = map.getOrPut(this.allocator(), entry.key_ptr.*) catch unreachable; - - if (!existing.found_existing) { - var new_task: *ParseTask = value; - var new_input_file = Graph.InputFile{ - .source = Logger.Source.initEmptyFile(new_task.path.text), - .side_effects = value.side_effects, - .secondary_path = if (value.secondary_path_for_commonjs_interop) |*secondary_path| secondary_path.text else "", - }; - - graph.has_any_secondary_paths = graph.has_any_secondary_paths or new_input_file.secondary_path.len > 0; - - new_input_file.source.index = Index.source(graph.input_files.len); - new_input_file.source.path = new_task.path; - new_input_file.loader = loader; - new_task.source_index = new_input_file.source.index; - new_task.ctx = this; - existing.value_ptr.* = new_task.source_index.get(); - - diff += 1; - - graph.input_files.append(this.allocator(), new_input_file) catch unreachable; - graph.ast.append(this.allocator(), JSAst.empty) catch unreachable; - - if (is_html_entrypoint) { - this.ensureClientTranspiler(); - this.graph.entry_points.append(this.allocator(), new_input_file.source.index) catch unreachable; - } - - if (this.enqueueOnLoadPluginIfNeeded(new_task)) { - continue; - } - - if (loader.shouldCopyForBundling()) { - var additional_files: *BabyList(AdditionalFile) = &graph.input_files.items(.additional_files)[importer_source_index]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = new_task.source_index.get() })); - graph.input_files.items(.side_effects)[new_task.source_index.get()] = _resolver.SideEffects.no_side_effects__pure_data; - graph.estimated_file_loader_count += 1; - } - - graph.pool.schedule(new_task); - } else { - if (loader.shouldCopyForBundling()) { - var additional_files: *BabyList(AdditionalFile) = &graph.input_files.items(.additional_files)[importer_source_index]; - bun.handleOom(additional_files.append(this.allocator(), .{ .source_index = existing.value_ptr.* })); - graph.estimated_file_loader_count += 1; - } - - bun.default_allocator.destroy(value); - } - } - return diff; - } - - pub const PatchImportRecordsCtx = struct { - source_index: Index, - source_path: []const u8, - loader: Loader, - target: options.Target, - redirect_import_record_index: u32 = std.math.maxInt(u32), - /// When true, always save source indices regardless of dev_server/loader. - /// Used for barrel un-deferral where records must always be connected. - force_save: bool = false, - }; - - /// Patch source_index on import records from pathToSourceIndexMap and - /// resolve_tasks_waiting_for_import_source_index. Called after - /// processResolveQueue has registered new modules. - pub fn patchImportRecordSourceIndices(this: *BundleV2, import_records: *ImportRecord.List, ctx: PatchImportRecordsCtx) void { - const graph = &this.graph; - const input_file_loaders = graph.input_files.items(.loader); - const save_import_record_source_index = ctx.force_save or - this.transpiler.options.dev_server == null or - ctx.loader == .html or - ctx.loader.isCSS(); - - if (this.resolve_tasks_waiting_for_import_source_index.fetchSwapRemove(ctx.source_index.get())) |pending_entry| { - var value = pending_entry.value; - for (value.slice()) |to_assign| { - if (save_import_record_source_index or - input_file_loaders[to_assign.to_source_index.get()].isCSS()) - { - import_records.slice()[to_assign.import_record_index].source_index = to_assign.to_source_index; - } - } - value.deinit(this.allocator()); - } - - const path_to_source_index_map = this.pathToSourceIndexMap(ctx.target); - for (import_records.slice(), 0..) |*record, i| { - if (path_to_source_index_map.getPath(&record.path)) |source_index| { - if (save_import_record_source_index or input_file_loaders[source_index].isCSS()) - record.source_index.value = source_index; - - if (getRedirectId(ctx.redirect_import_record_index)) |compare| { - if (compare == @as(u32, @truncate(i))) { - path_to_source_index_map.put( - this.allocator(), - ctx.source_path, - source_index, - ) catch unreachable; - } - } - } - } - } - - fn generateServerHTMLModule(this: *BundleV2, path: *const Fs.Path, target: options.Target, import_record: *ImportRecord, path_text: []const u8) !void { - // 1. Create the ast right here - // 2. Create a separate "virutal" module that becomes the manifest later on. - // 3. Add it to the graph - const graph = &this.graph; - const empty_html_file_source: Logger.Source = .{ - .path = path.*, - .index = Index.source(graph.input_files.len), - .contents = "", - }; - var js_parser_options = bun.js_parser.Parser.Options.init(this.transpilerForTarget(target).options.jsx, .html); - js_parser_options.bundle = true; - - const unique_key = try std.fmt.allocPrint(this.allocator(), "{f}H{d:0>8}", .{ - bun.fmt.hexIntLower(this.unique_key), - graph.html_imports.server_source_indices.len, - }); - - const transpiler = this.transpilerForTarget(target); - - const ast_for_html_entrypoint = JSAst.init((try bun.js_parser.newLazyExportAST( - this.allocator(), - transpiler.options.define, - js_parser_options, - transpiler.log, - Expr.init( - E.String, - E.String{ - .data = unique_key, - }, - Logger.Loc.Empty, - ), - &empty_html_file_source, - - // We replace this runtime API call's ref later via .link on the Symbol. - "__jsonParse", - )).?); - - var fake_input_file = Graph.InputFile{ - .source = empty_html_file_source, - .side_effects = .no_side_effects__pure_data, - }; - - try graph.input_files.append(this.allocator(), fake_input_file); - try graph.ast.append(this.allocator(), ast_for_html_entrypoint); - - import_record.source_index = fake_input_file.source.index; - try this.pathToSourceIndexMap(target).put(this.allocator(), path_text, fake_input_file.source.index.get()); - try graph.html_imports.server_source_indices.append(this.allocator(), fake_input_file.source.index.get()); - this.ensureClientTranspiler(); - } - - const ResolveQueue = bun.StringHashMap(*ParseTask); - - pub fn onNotifyDefer(this: *BundleV2) void { - this.thread_lock.assertLocked(); - this.graph.deferred_pending += 1; - this.decrementScanCounter(); - } - - pub fn onNotifyDeferMini(_: *bun.jsc.API.JSBundler.Load, this: *BundleV2) void { - this.onNotifyDefer(); - } - - pub fn onParseTaskComplete(parse_result: *ParseTask.Result, this: *BundleV2) void { - const trace = bun.perf.trace("Bundler.onParseTaskComplete"); - const graph = &this.graph; - defer trace.end(); - if (parse_result.external.function != null) { - const source = switch (parse_result.value) { - inline .empty, .err => |data| data.source_index.get(), - .success => |val| val.source.index.get(), - }; - const loader: Loader = graph.input_files.items(.loader)[source]; - if (!loader.shouldCopyForBundling()) { - bun.handleOom(this.finalizers.append(bun.default_allocator, parse_result.external)); - } else { - graph.input_files.items(.allocator)[source] = ExternalFreeFunctionAllocator.create(parse_result.external.function.?, parse_result.external.ctx.?); - } - } - - defer bun.default_allocator.destroy(parse_result); - - var diff: i32 = -1; - defer { - logScanCounter("in parse task .pending_items += {d} = {d}\n", .{ diff, @as(i32, @intCast(graph.pending_items)) + diff }); - graph.pending_items = @intCast(@as(i32, @intCast(graph.pending_items)) + diff); - if (diff < 0) - this.onAfterDecrementScanCounter(); - } - - var resolve_queue = ResolveQueue.init(this.allocator()); - defer resolve_queue.deinit(); - var process_log = true; - - if (parse_result.value == .success) { - this.applyBarrelOptimization(parse_result); - - resolve_queue = runResolutionForParseTask(parse_result, this); - if (parse_result.value == .err) { - process_log = false; - } - } - - // To minimize contention, watchers are appended on the bundle thread. - if (this.bun_watcher) |watcher| { - if (parse_result.watcher_data.fd != bun.invalid_fd) { - const source = switch (parse_result.value) { - inline .empty, .err => |data| graph.input_files.items(.source)[data.source_index.get()], - .success => |val| val.source, - }; - if (this.shouldAddWatcher(source.path.text)) { - _ = watcher.addFile( - parse_result.watcher_data.fd, - source.path.text, - bun.hash32(source.path.text), - graph.input_files.items(.loader)[source.index.get()], - parse_result.watcher_data.dir_fd, - null, - bun.Environment.isWindows, - ); - } - } - } - - switch (parse_result.value) { - .empty => |empty_result| { - const input_files = graph.input_files.slice(); - const side_effects = input_files.items(.side_effects); - side_effects[empty_result.source_index.get()] = .no_side_effects__empty_ast; - if (comptime Environment.allow_assert) { - debug("onParse({d}, {s}) = empty", .{ - empty_result.source_index.get(), - input_files.items(.source)[empty_result.source_index.get()].path.text, - }); - } - }, - .success => |*result| { - result.log.cloneToWithRecycled(this.transpiler.log, true) catch unreachable; - - this.has_any_top_level_await_modules = this.has_any_top_level_await_modules or !result.ast.top_level_await_keyword.isEmpty(); - - // Warning: `input_files` and `ast` arrays may resize in this function call - // It is not safe to cache slices from them. - graph.input_files.items(.source)[result.source.index.get()] = result.source; - this.source_code_length += if (!result.source.index.isRuntime()) - result.source.contents.len - else - @as(usize, 0); - - graph.input_files.items(.unique_key_for_additional_file)[result.source.index.get()] = result.unique_key_for_additional_file; - graph.input_files.items(.content_hash_for_additional_file)[result.source.index.get()] = result.content_hash_for_additional_file; - if (result.unique_key_for_additional_file.len > 0 and result.loader.shouldCopyForBundling()) { - if (this.transpiler.options.dev_server) |dev| { - dev.putOrOverwriteAsset( - &result.source.path, - // SAFETY: when shouldCopyForBundling is true, the - // contents are allocated by bun.default_allocator - &.fromOwnedSlice(bun.default_allocator, @constCast(result.source.contents)), - result.content_hash_for_additional_file, - ) catch |err| bun.handleOom(err); - } - } - - // Record which loader we used for this file - graph.input_files.items(.loader)[result.source.index.get()] = result.loader; - - debug("onParse({d}, {s}) = {d} imports, {d} exports", .{ - result.source.index.get(), - result.source.path.text, - result.ast.import_records.len, - result.ast.named_exports.count(), - }); - - if (result.ast.css != null) { - graph.css_file_count += 1; - } - - diff += this.processResolveQueue(resolve_queue, result.ast.target, result.source.index.get()); - - var import_records = result.ast.import_records.clone(this.allocator()) catch unreachable; - this.patchImportRecordSourceIndices(&import_records, .{ - .source_index = result.source.index, - .source_path = result.source.path.text, - .loader = result.loader, - .target = result.ast.target, - .redirect_import_record_index = result.ast.redirect_import_record_index, - }); - result.ast.import_records = import_records; - - // Set is_export_star_target for barrel optimization. - // In dev server mode, source_index is not saved on JS import - // records, so fall back to resolving via the path map. - const path_to_source_index_map = this.pathToSourceIndexMap(result.ast.target); - for (result.ast.export_star_import_records) |star_record_idx| { - if (star_record_idx < import_records.len) { - const star_ir = import_records.slice()[star_record_idx]; - const resolved_index = if (star_ir.source_index.isValid()) - star_ir.source_index.get() - else - path_to_source_index_map.getPath(&star_ir.path) orelse continue; - graph.input_files.items(.flags)[resolved_index].is_export_star_target = true; - } - } - - graph.ast.set(result.source.index.get(), result.ast); - - // Barrel optimization: eagerly record import requests and - // un-defer barrel records that are now needed. - if (this.isBarrelOptimizationEnabled()) { - diff += bun.handleOom(this.scheduleBarrelDeferredImports(result)); - } - - // For files with use directives, index and prepare the other side. - if (result.use_directive != .none and if (this.framework.?.server_components.?.separate_ssr_graph) - ((result.use_directive == .client) == (result.ast.target == .browser)) - else - ((result.use_directive == .client) != (result.ast.target == .browser))) - { - if (result.use_directive == .server) - bun.todoPanic(@src(), "\"use server\"", .{}); - - const reference_source_index, const ssr_index = if (this.framework.?.server_components.?.separate_ssr_graph) brk: { - // Enqueue two files, one in server graph, one in ssr graph. - const reference_source_index = this.enqueueServerComponentGeneratedFile( - .{ .client_reference_proxy = .{ - .other_source = result.source, - .named_exports = result.ast.named_exports, - } }, - result.source, - ) catch |err| bun.handleOom(err); - - const ssr_source = &result.source; - ssr_source.path.pretty = ssr_source.path.text; - ssr_source.path = bun.handleOom(this.pathWithPrettyInitialized(ssr_source.path, .bake_server_components_ssr)); - const ssr_index = this.enqueueParseTask2( - ssr_source, - graph.input_files.items(.loader)[result.source.index.get()], - .bake_server_components_ssr, - ) catch |err| bun.handleOom(err); - - break :brk .{ reference_source_index, ssr_index }; - } else brk: { - // Enqueue only one file - const server_source = &result.source; - server_source.path.pretty = server_source.path.text; - server_source.path = bun.handleOom(this.pathWithPrettyInitialized(server_source.path, this.transpiler.options.target)); - const server_index = this.enqueueParseTask2( - server_source, - graph.input_files.items(.loader)[result.source.index.get()], - .browser, - ) catch |err| bun.handleOom(err); - - break :brk .{ server_index, Index.invalid.get() }; - }; - - graph.pathToSourceIndexMap(result.ast.target).put( - this.allocator(), - result.source.path.text, - reference_source_index, - ) catch |err| bun.handleOom(err); - - graph.server_component_boundaries.put( - this.allocator(), - result.source.index.get(), - result.use_directive, - reference_source_index, - ssr_index, - ) catch |err| bun.handleOom(err); - } - }, - .err => |*err| { - if (comptime Environment.enable_logs) { - debug("onParse() = err", .{}); - } - - if (process_log) { - if (this.transpiler.options.dev_server) |dev_server| { - dev_server.handleParseTaskFailure( - err.err, - err.target.bakeGraph(), - graph.input_files.items(.source)[err.source_index.get()].path.text, - &err.log, - this, - ) catch |e| bun.handleOom(e); - } else if (err.log.msgs.items.len > 0) { - err.log.cloneToWithRecycled(this.transpiler.log, true) catch unreachable; - } else { - this.transpiler.log.addErrorFmt( - null, - Logger.Loc.Empty, - this.transpiler.log.msgs.allocator, - "{s} while {s}", - .{ @errorName(err.err), @tagName(err.step) }, - ) catch unreachable; - } - } - - if (Environment.allow_assert and this.transpiler.options.dev_server != null) { - bun.assert(graph.ast.items(.parts)[err.source_index.get()].len == 0); - } - }, - } - } - - /// To satisfy the interface from NewHotReloader() - pub fn getLoaders(vm: *BundleV2) *bun.options.Loader.HashTable { - return &vm.transpiler.options.loaders; - } - - /// To satisfy the interface from NewHotReloader() - pub fn bustDirCache(vm: *BundleV2, path: []const u8) bool { - return vm.transpiler.resolver.bustDirCache(path); - } -}; - -pub const BundleThread = @import("./BundleThread.zig").BundleThread; - -pub const UseDirective = js_ast.UseDirective; -pub const ServerComponentBoundary = js_ast.ServerComponentBoundary; -pub const ServerComponentParseTask = @import("./ServerComponentParseTask.zig").ServerComponentParseTask; - -const RefVoidMap = std.ArrayHashMapUnmanaged(Ref, void, Ref.ArrayHashCtx, false); -pub const RefImportData = std.ArrayHashMapUnmanaged(Ref, ImportData, Ref.ArrayHashCtx, false); -pub const ResolvedExports = bun.StringArrayHashMapUnmanaged(ExportData); -pub const TopLevelSymbolToParts = js_ast.Ast.TopLevelSymbolToParts; - -pub const WrapKind = enum(u2) { - none, - cjs, - esm, -}; - -pub const ImportData = struct { - // This is an array of intermediate statements that re-exported this symbol - // in a chain before getting to the final symbol. This can be done either with - // "export * from" or "export {} from". If this is done with "export * from" - // then this may not be the result of a single chain but may instead form - // a diamond shape if this same symbol was re-exported multiple times from - // different files. - re_exports: Dependency.List = Dependency.List{}, - - data: ImportTracker = .{}, -}; - -pub const ExportData = struct { - // Export star resolution happens first before import resolution. That means - // it cannot yet determine if duplicate names from export star resolution are - // ambiguous (point to different symbols) or not (point to the same symbol). - // This issue can happen in the following scenario: - // - // // entry.js - // export * from './a' - // export * from './b' - // - // // a.js - // export * from './c' - // - // // b.js - // export {x} from './c' - // - // // c.js - // export let x = 1, y = 2 - // - // In this case "entry.js" should have two exports "x" and "y", neither of - // which are ambiguous. To handle this case, ambiguity resolution must be - // deferred until import resolution time. That is done using this array. - potentially_ambiguous_export_star_refs: BabyList(ImportData) = .{}, - - // This is the file that the named export above came from. This will be - // different from the file that contains this object if this is a re-export. - data: ImportTracker = .{}, -}; - -pub const JSMeta = struct { - /// This is only for TypeScript files. If an import symbol is in this map, it - /// means the import couldn't be found and doesn't actually exist. This is not - /// an error in TypeScript because the import is probably just a type. - /// - /// Normally we remove all unused imports for TypeScript files during parsing, - /// which automatically removes type-only imports. But there are certain re- - /// export situations where it's impossible to tell if an import is a type or - /// not: - /// - /// import {typeOrNotTypeWhoKnows} from 'path'; - /// export {typeOrNotTypeWhoKnows}; - /// - /// Really people should be using the TypeScript "isolatedModules" flag with - /// bundlers like this one that compile TypeScript files independently without - /// type checking. That causes the TypeScript type checker to emit the error - /// "Re-exporting a type when the '--isolatedModules' flag is provided requires - /// using 'export type'." But we try to be robust to such code anyway. - probably_typescript_type: RefVoidMap = .{}, - - /// Imports are matched with exports in a separate pass from when the matched - /// exports are actually bound to the imports. Here "binding" means adding non- - /// local dependencies on the parts in the exporting file that declare the - /// exported symbol to all parts in the importing file that use the imported - /// symbol. - /// - /// This must be a separate pass because of the "probably TypeScript type" - /// check above. We can't generate the part for the export namespace until - /// we've matched imports with exports because the generated code must omit - /// type-only imports in the export namespace code. And we can't bind exports - /// to imports until the part for the export namespace is generated since that - /// part needs to participate in the binding. - /// - /// This array holds the deferred imports to bind so the pass can be split - /// into two separate passes. - imports_to_bind: RefImportData = .{}, - - /// This includes both named exports and re-exports. - /// - /// Named exports come from explicit export statements in the original file, - /// and are copied from the "NamedExports" field in the AST. - /// - /// Re-exports come from other files and are the result of resolving export - /// star statements (i.e. "export * from 'foo'"). - resolved_exports: ResolvedExports = .{}, - resolved_export_star: ExportData = ExportData{}, - - /// Never iterate over "resolvedExports" directly. Instead, iterate over this - /// array. Some exports in that map aren't meant to end up in generated code. - /// This array excludes these exports and is also sorted, which avoids non- - /// determinism due to random map iteration order. - sorted_and_filtered_export_aliases: []const string = &[_]string{}, - - /// This is merged on top of the corresponding map from the parser in the AST. - /// You should call "TopLevelSymbolToParts" to access this instead of accessing - /// it directly. - top_level_symbol_to_parts_overlay: TopLevelSymbolToParts = .{}, - - /// If this is an entry point, this array holds a reference to one free - /// temporary symbol for each entry in "sortedAndFilteredExportAliases". - /// These may be needed to store copies of CommonJS re-exports in ESM. - cjs_export_copies: []const Ref = &[_]Ref{}, - - /// The index of the automatically-generated part used to represent the - /// CommonJS or ESM wrapper. This part is empty and is only useful for tree - /// shaking and code splitting. The wrapper can't be inserted into the part - /// because the wrapper contains other parts, which can't be represented by - /// the current part system. Only wrapped files have one of these. - wrapper_part_index: Index = Index.invalid, - - /// The index of the automatically-generated part used to handle entry point - /// specific stuff. If a certain part is needed by the entry point, it's added - /// as a dependency of this part. This is important for parts that are marked - /// as removable when unused and that are not used by anything else. Only - /// entry point files have one of these. - entry_point_part_index: Index = Index.invalid, - - flags: Flags = .{}, - - pub const Flags = packed struct(u8) { - /// This is true if this file is affected by top-level await, either by having - /// a top-level await inside this file or by having an import/export statement - /// that transitively imports such a file. It is forbidden to call "require()" - /// on these files since they are evaluated asynchronously. - is_async_or_has_async_dependency: bool = false, - - /// If true, we need to insert "var exports = {};". This is the case for ESM - /// files when the import namespace is captured via "import * as" and also - /// when they are the target of a "require()" call. - needs_exports_variable: bool = false, - - /// If true, the "__export(exports, { ... })" call will be force-included even - /// if there are no parts that reference "exports". Otherwise this call will - /// be removed due to the tree shaking pass. This is used when for entry point - /// files when code related to the current output format needs to reference - /// the "exports" variable. - force_include_exports_for_entry_point: bool = false, - - /// This is set when we need to pull in the "__export" symbol in to the part - /// at "nsExportPartIndex". This can't be done in "createExportsForFile" - /// because of concurrent map hazards. Instead, it must be done later. - needs_export_symbol_from_runtime: bool = false, - - /// Wrapped files must also ensure that their dependencies are wrapped. This - /// flag is used during the traversal that enforces this invariant, and is used - /// to detect when the fixed point has been reached. - did_wrap_dependencies: bool = false, - - /// When a converted CommonJS module is import() dynamically - /// We need ensure that the "default" export is set to the equivalent of module.exports - /// (unless a "default" export already exists) - needs_synthetic_default_export: bool = false, - - wrap: WrapKind = WrapKind.none, - }; -}; - -pub const AdditionalFile = union(enum) { - source_index: Index.Int, - output_file: Index.Int, -}; - -pub const EntryPoint = struct { - /// This may be an absolute path or a relative path. If absolute, it will - /// eventually be turned into a relative path by computing the path relative - /// to the "outbase" directory. Then this relative path will be joined onto - /// the "outdir" directory to form the final output path for this entry point. - output_path: bun.PathString = bun.PathString.empty, - - /// This is the source index of the entry point. This file must have a valid - /// entry point kind (i.e. not "none"). - source_index: Index.Int = 0, - - /// Manually specified output paths are ignored when computing the default - /// "outbase" directory, which is computed as the lowest common ancestor of - /// all automatically generated output paths. - output_path_was_auto_generated: bool = false, - - pub const List = MultiArrayList(EntryPoint); - - pub const Kind = enum { - none, - user_specified, - dynamic_import, - html, - - pub fn outputKind(this: Kind) jsc.API.BuildArtifact.OutputKind { - return switch (this) { - .user_specified => .@"entry-point", - else => .chunk, - }; - } - - pub inline fn isEntryPoint(this: Kind) bool { - return this != .none; - } - - pub inline fn isUserSpecifiedEntryPoint(this: Kind) bool { - return this == .user_specified; - } - - // TODO: delete - pub inline fn isServerEntryPoint(this: Kind) bool { - return this == .user_specified; - } - }; -}; - -const AstSourceIDMapping = struct { - id: Index.Int, - source_index: Index.Int, -}; - -pub const PartRange = struct { - source_index: Index = Index.invalid, - part_index_begin: u32 = 0, - part_index_end: u32 = 0, -}; - -pub const StableRef = packed struct(u96) { - stable_source_index: Index.Int, - ref: Ref, - - pub fn isLessThan(_: void, a: StableRef, b: StableRef) bool { - return a.stable_source_index < b.stable_source_index or - (a.stable_source_index == b.stable_source_index and a.ref.innerIndex() < b.ref.innerIndex()); - } -}; - -pub const ImportTracker = struct { - source_index: Index = Index.invalid, - name_loc: Logger.Loc = Logger.Loc.Empty, - import_ref: Ref = Ref.None, - - pub const Status = enum { - /// The imported file has no matching export - no_match, - - /// The imported file has a matching export - found, - - /// The imported file is CommonJS and has unknown exports - cjs, - - /// The import is missing but there is a dynamic fallback object - dynamic_fallback, - - /// The import is missing but there is a dynamic fallback object - /// and the file was originally CommonJS. - dynamic_fallback_interop_default, - - /// The import was treated as a CommonJS import but the file is known to have no exports - cjs_without_exports, - - /// The imported file was disabled by mapping it to false in the "browser" - /// field of package.json - disabled, - - /// The imported file is external and has unknown exports - external, - - /// This is a missing re-export in a TypeScript file, so it's probably a type - probably_typescript_type, - }; - - pub const Iterator = struct { - status: Status = Status.no_match, - value: ImportTracker = .{}, - import_data: []ImportData = &.{}, - }; -}; - -pub const PathTemplate = options.PathTemplate; - -pub const Chunk = @import("./Chunk.zig").Chunk; -pub const ChunkImport = @import("./Chunk.zig").ChunkImport; - -pub const CrossChunkImport = struct { - chunk_index: Index.Int = 0, - sorted_import_items: CrossChunkImport.Item.List = undefined, - - pub const Item = struct { - export_alias: string = "", - ref: Ref = Ref.None, - - pub const List = bun.BabyList(Item); - - pub fn lessThan(_: void, a: CrossChunkImport.Item, b: CrossChunkImport.Item) bool { - return strings.order(a.export_alias, b.export_alias) == .lt; - } - }; - - pub fn lessThan(_: void, a: CrossChunkImport, b: CrossChunkImport) bool { - return std.math.order(a.chunk_index, b.chunk_index) == .lt; - } - - pub const List = std.array_list.Managed(CrossChunkImport); - - pub fn sortedCrossChunkImports( - list: *List, - chunks: []Chunk, - imports_from_other_chunks: *Chunk.ImportsFromOtherChunks, - ) !void { - var result = list.*; - defer { - list.* = result; - } - - result.clearRetainingCapacity(); - try result.ensureTotalCapacity(imports_from_other_chunks.count()); - - const import_items_list = imports_from_other_chunks.values(); - const chunk_indices = imports_from_other_chunks.keys(); - for (chunk_indices, import_items_list) |chunk_index, import_items| { - var chunk = &chunks[chunk_index]; - - // Sort imports from a single chunk by alias for determinism - const exports_to_other_chunks = &chunk.content.javascript.exports_to_other_chunks; - // TODO: do we need to clone this array? - for (import_items.slice()) |*item| { - item.export_alias = exports_to_other_chunks.get(item.ref).?; - bun.assert(item.export_alias.len > 0); - } - std.sort.pdq(CrossChunkImport.Item, import_items.slice(), {}, CrossChunkImport.Item.lessThan); - - result.append(CrossChunkImport{ - .chunk_index = chunk_index, - .sorted_import_items = import_items, - }) catch unreachable; - } - - std.sort.pdq(CrossChunkImport, result.items, {}, CrossChunkImport.lessThan); - } -}; - -pub const CompileResult = union(enum) { - pub const DeclInfo = struct { - pub const Kind = enum(u1) { declared, lexical }; - name: []const u8, - kind: Kind, - }; - - javascript: struct { - source_index: Index.Int, - result: js_printer.PrintResult, - /// Top-level declarations collected from converted statements during - /// parallel printing. Used by postProcessJSChunk to populate ModuleInfo - /// without re-scanning the original (unconverted) AST. - decls: []const DeclInfo = &.{}, - - pub fn code(this: @This()) []const u8 { - return switch (this.result) { - .result => |result| result.code, - else => "", - }; - } - }, - css: struct { - result: bun.Maybe([]const u8, anyerror), - source_index: Index.Int, - source_map: ?bun.SourceMap.Chunk = null, - }, - html: struct { - source_index: Index.Int, - code: []const u8, - /// Offsets are used for DevServer to inject resources without re-bundling - script_injection_offset: u32, - }, - - pub const empty = CompileResult{ - .javascript = .{ - .source_index = 0, - .result = js_printer.PrintResult{ - .result = .{ - .code = "", - }, - }, - }, - }; - - pub fn code(this: *const CompileResult) []const u8 { - return switch (this.*) { - .javascript => |r| r.code(), - .css => |*c| switch (c.result) { - .result => |v| v, - .err => "", - }, - .html => |*c| c.code, - }; - } - - pub fn sourceMapChunk(this: *const CompileResult) ?SourceMap.Chunk { - return switch (this.*) { - .javascript => |r| switch (r.result) { - .result => |r2| r2.source_map, - else => null, - }, - .css => |*c| c.source_map, - .html => null, - }; - } - - pub fn sourceIndex(this: *const CompileResult) Index.Int { - return switch (this.*) { - inline else => |*r| r.source_index, - }; - } -}; - -pub const CompileResultForSourceMap = struct { - source_map_chunk: SourceMap.Chunk, - generated_offset: SourceMap.LineColumnOffset, - source_index: u32, -}; - -pub const ContentHasher = struct { - pub const Hash = std.hash.XxHash64; - - // xxhash64 outperforms Wyhash if the file is > 1KB or so - hasher: Hash = .init(0), - - const log = bun.Output.scoped(.ContentHasher, .hidden); - - pub fn write(self: *ContentHasher, bytes: []const u8) void { - log("HASH_UPDATE {d}:\n{s}\n----------\n", .{ bytes.len, std.mem.sliceAsBytes(bytes) }); - self.hasher.update(std.mem.asBytes(&bytes.len)); - self.hasher.update(bytes); - } - - pub fn run(bytes: []const u8) u64 { - var hasher = ContentHasher{}; - hasher.write(bytes); - return hasher.digest(); - } - - pub fn writeInts(self: *ContentHasher, i: []const u32) void { - log("HASH_UPDATE: {any}\n", .{i}); - self.hasher.update(std.mem.sliceAsBytes(i)); - } - - pub fn digest(self: *ContentHasher) u64 { - return self.hasher.final(); - } -}; - -// non-allocating -// meant to be fast but not 100% thorough -// users can correctly put in a trailing slash if they want -// this is just being nice -pub fn cheapPrefixNormalizer(prefix: []const u8, suffix: []const u8) [2]string { - if (prefix.len == 0) { - const suffix_no_slash = bun.strings.removeLeadingDotSlash(suffix); - return .{ - if (strings.hasPrefixComptime(suffix_no_slash, "../")) "" else "./", - suffix_no_slash, - }; - } - - // There are a few cases here we want to handle: - // ["https://example.com/", "/out.js"] => "https://example.com/out.js" - // ["/foo/", "/bar.js"] => "/foo/bar.js" - if (strings.endsWithChar(prefix, '/') or (Environment.isWindows and strings.endsWithChar(prefix, '\\'))) { - if (strings.startsWithChar(suffix, '/') or (Environment.isWindows and strings.startsWithChar(suffix, '\\'))) { - return .{ - prefix[0..prefix.len], - suffix[1..suffix.len], - }; - } - - // It gets really complicated if we try to deal with URLs more than this - // These would be ideal: - // - example.com + ./out.js => example.com/out.js - // - example.com/foo + ./out.js => example.com/fooout.js - // - example.com/bar/ + ./out.js => example.com/bar/out.js - // But it's not worth the complexity to handle these cases right now. - } - - return .{ - prefix, - bun.strings.removeLeadingDotSlash(suffix), - }; -} - -fn getRedirectId(id: u32) ?u32 { - if (id == std.math.maxInt(u32)) { - return null; - } - return id; -} - -pub fn targetFromHashbang(buffer: []const u8) ?options.Target { - if (buffer.len > "#!/usr/bin/env bun".len) { - if (strings.hasPrefixComptime(buffer, "#!/usr/bin/env bun")) { - switch (buffer["#!/usr/bin/env bun".len]) { - '\n', ' ' => return options.Target.bun, - else => {}, - } - } - } - return null; -} - -pub const AstBuilder = @import("./AstBuilder.zig").AstBuilder; - -pub const CssEntryPointMeta = struct { - /// When this is true, a stub file is added to the Server's IncrementalGraph - imported_on_server: bool, -}; - -/// The lifetime of this structure is tied to the bundler's arena -pub const DevServerInput = struct { - css_entry_points: std.AutoArrayHashMapUnmanaged(Index, CssEntryPointMeta), -}; - -/// The lifetime of this structure is tied to the bundler's arena -pub const DevServerOutput = struct { - chunks: []Chunk, - css_file_list: std.AutoArrayHashMapUnmanaged(Index, CssEntryPointMeta), - html_files: std.AutoArrayHashMapUnmanaged(Index, void), - - pub fn jsPseudoChunk(out: *const DevServerOutput) *Chunk { - return &out.chunks[0]; - } - - pub fn cssChunks(out: *const DevServerOutput) []Chunk { - return out.chunks[1..][0..out.css_file_list.count()]; - } - - pub fn htmlChunks(out: *const DevServerOutput) []Chunk { - return out.chunks[1 + out.css_file_list.count() ..][0..out.html_files.count()]; - } -}; - -pub fn generateUniqueKey() u64 { - const key = std.crypto.random.int(u64) & @as(u64, 0x0FFFFFFF_FFFFFFFF); - // without this check, putting unique_key in an object key would - // sometimes get converted to an identifier. ensuring it starts - // with a number forces that optimization off. - if (Environment.isDebug) { - var buf: [16]u8 = undefined; - const hex = std.fmt.bufPrint(&buf, "{f}", .{bun.fmt.hexIntLower(key)}) catch - unreachable; - switch (hex[0]) { - '0'...'9' => {}, - else => Output.panic("unique key is a valid identifier: {s}", .{hex}), - } - } - return key; -} - -const ExternalFreeFunctionAllocator = struct { - free_callback: *const fn (ctx: *anyopaque) callconv(.c) void, - context: *anyopaque, - - const vtable: std.mem.Allocator.VTable = .{ - .alloc = &alloc, - .free = &free, - .resize = &std.mem.Allocator.noResize, - .remap = &std.mem.Allocator.noRemap, - }; - - pub fn create(free_callback: *const fn (ctx: *anyopaque) callconv(.c) void, context: *anyopaque) std.mem.Allocator { - return .{ - .ptr = bun.create(bun.default_allocator, ExternalFreeFunctionAllocator, .{ - .free_callback = free_callback, - .context = context, - }), - .vtable = &vtable, - }; - } - - fn alloc(_: *anyopaque, _: usize, _: std.mem.Alignment, _: usize) ?[*]u8 { - return null; - } - - fn free(ext_free_function: *anyopaque, _: []u8, _: std.mem.Alignment, _: usize) void { - const info: *ExternalFreeFunctionAllocator = @ptrCast(@alignCast(ext_free_function)); - info.free_callback(info.context); - bun.default_allocator.destroy(info); - } -}; - -/// Returns true if `allocator` definitely has a valid `.ptr`. -/// May return false even if `.ptr` is valid. -/// -/// This function should check whether `allocator` matches any internal allocator types known to -/// have valid pointers. Allocators defined outside of this file, like `std.heap.ArenaAllocator`, -/// don't need to be checked. -pub fn allocatorHasPointer(allocator: std.mem.Allocator) bool { - return allocator.vtable == &ExternalFreeFunctionAllocator.vtable; -} - -pub const std = @import("std"); -pub const lex = @import("../js_parser/lexer.zig"); -pub const Logger = @import("../logger/logger.zig"); -pub const Part = js_ast.Part; -pub const js_printer = @import("../js_printer/js_printer.zig"); -pub const js_ast = bun.ast; -pub const linker = @import("./linker.zig"); -pub const SourceMap = bun.SourceMap; -pub const StringJoiner = bun.StringJoiner; -pub const base64 = bun.base64; -pub const Ref = bun.ast.Ref; -pub const ThreadLocalArena = bun.allocators.MimallocArena; -pub const BabyList = bun.collections.BabyList; -pub const Fs = @import("../resolver/fs.zig"); -pub const api = bun.schema.api; -pub const _resolver = @import("../resolver/resolver.zig"); -pub const ImportRecord = bun.ImportRecord; -pub const ImportKind = bun.ImportKind; -pub const allocators = bun.allocators; -pub const resolve_path = @import("../paths/resolve_path.zig"); -pub const runtime = @import("../js_parser/runtime.zig"); -pub const Timer = @import("../perf/system_timer.zig"); -pub const OOM = bun.OOM; - -pub const HTMLScanner = @import("./HTMLScanner.zig"); -pub const isPackagePath = _resolver.isPackagePath; -pub const NodeFallbackModules = @import("../resolver/node_fallbacks.zig"); -pub const CacheEntry = @import("./cache.zig").Fs.Entry; -pub const URL = @import("../url/url.zig").URL; -pub const Resolver = _resolver.Resolver; -pub const TOML = bun.interchange.toml.TOML; -pub const Dependency = js_ast.Dependency; -pub const JSAst = js_ast.BundledAst; -pub const Loader = options.Loader; -pub const Index = bun.ast.Index; -pub const Symbol = js_ast.Symbol; -pub const EventLoop = bun.jsc.AnyEventLoop; -pub const MultiArrayList = bun.MultiArrayList; -pub const Stmt = js_ast.Stmt; -pub const Expr = js_ast.Expr; -pub const E = js_ast.E; -pub const S = js_ast.S; -pub const G = js_ast.G; -pub const B = js_ast.B; -pub const Binding = js_ast.Binding; -pub const AutoBitSet = bun.bit_set.AutoBitSet; -pub const renamer = bun.renamer; -pub const StableSymbolCount = renamer.StableSymbolCount; -pub const MinifyRenamer = renamer.MinifyRenamer; -pub const Scope = js_ast.Scope; -pub const jsc = bun.jsc; -pub const debugTreeShake = Output.scoped(.TreeShake, .hidden); -pub const debugPartRanges = Output.scoped(.PartRanges, .hidden); -pub const BitSet = bun.bit_set.DynamicBitSetUnmanaged; -pub const Async = bun.Async; -pub const Loc = Logger.Loc; -pub const bake = bun.bake; -pub const lol = bun.LOLHTML; -pub const DataURL = @import("../resolver/resolver.zig").DataURL; -pub const IndexStringMap = @import("./IndexStringMap.zig"); -pub const DeferredBatchTask = @import("./DeferredBatchTask.zig").DeferredBatchTask; -pub const ThreadPool = @import("./ThreadPool.zig").ThreadPool; -pub const ParseTask = @import("./ParseTask.zig").ParseTask; -pub const LinkerContext = @import("./LinkerContext.zig").LinkerContext; -pub const LinkerGraph = @import("./LinkerGraph.zig").LinkerGraph; -pub const Graph = @import("./Graph.zig"); - -const string = []const u8; - -// C++ binding for lazy metafile getter (defined in BundlerMetafile.cpp) -// Uses jsc.conv (SYSV_ABI on Windows x64) for proper calling convention -// Sets up metafile object with { json: , markdown?: string } - -const options = @import("./options.zig"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const FeatureFlags = bun.FeatureFlags; -const Output = bun.Output; -const ThreadPoolLib = bun.ThreadPool; -const Transpiler = bun.Transpiler; -const default_allocator = bun.default_allocator; -const strings = bun.strings; diff --git a/src/bundler/bundled_ast.zig b/src/bundler/bundled_ast.zig deleted file mode 100644 index c8ede2e497e5..000000000000 --- a/src/bundler/bundled_ast.zig +++ /dev/null @@ -1,235 +0,0 @@ -//! Like Ast but slimmer and for bundling only. -//! -//! On Linux, the hottest function in the bundler is: -//! src.multi_array_list.MultiArrayList(src.js_ast.Ast).ensureTotalCapacity -//! https://share.firefox.dev/3NNlRKt -//! -//! So we make a slimmer version of Ast for bundling that doesn't allocate as much memory - -approximate_newline_count: u32 = 0, -nested_scope_slot_counts: SlotCounts = .{}, - -exports_kind: ExportsKind = .none, - -/// These are stored at the AST level instead of on individual AST nodes so -/// they can be manipulated efficiently without a full AST traversal -import_records: ImportRecord.List = .{}, - -hashbang: string = "", -parts: Part.List = .{}, -css: ?*bun.css.BundlerStyleSheet = null, -url_for_css: []const u8 = "", -symbols: Symbol.List = .{}, -module_scope: Scope = .{}, -char_freq: CharFreq = undefined, -exports_ref: Ref = Ref.None, -module_ref: Ref = Ref.None, -wrapper_ref: Ref = Ref.None, -require_ref: Ref = Ref.None, -top_level_await_keyword: logger.Range, -tla_check: TlaCheck = .{}, - -// These are used when bundling. They are filled in during the parser pass -// since we already have to traverse the AST then anyway and the parser pass -// is conveniently fully parallelized. -named_imports: NamedImports = .{}, -named_exports: NamedExports = .{}, -export_star_import_records: []u32 = &.{}, - -top_level_symbols_to_parts: TopLevelSymbolToParts = .{}, - -commonjs_named_exports: CommonJSNamedExports = .{}, - -redirect_import_record_index: u32 = std.math.maxInt(u32), - -/// Only populated when bundling. When --server-components is passed, this -/// will be .browser when it is a client component, and the server's target -/// on the server. -target: bun.options.Target = .browser, - -// const_values: ConstValuesMap = .{}, -ts_enums: Ast.TsEnumsMap = .{}, - -flags: BundledAst.Flags = .{}, - -pub const Flags = packed struct(u16) { - // This is a list of CommonJS features. When a file uses CommonJS features, - // it's not a candidate for "flat bundling" and must be wrapped in its own - // closure. - uses_exports_ref: bool = false, - uses_module_ref: bool = false, - // uses_require_ref: bool = false, - uses_export_keyword: bool = false, - has_char_freq: bool = false, - force_cjs_to_esm: bool = false, - has_lazy_export: bool = false, - commonjs_module_exports_assigned_deoptimized: bool = false, - has_explicit_use_strict_directive: bool = false, - has_import_meta: bool = false, - _padding: u7 = 0, -}; - -pub const empty = BundledAst.init(Ast.empty); - -pub fn toAST(this: *const BundledAst) Ast { - return .{ - .approximate_newline_count = this.approximate_newline_count, - .nested_scope_slot_counts = this.nested_scope_slot_counts, - - .exports_kind = this.exports_kind, - - .import_records = this.import_records, - - .hashbang = this.hashbang, - .parts = this.parts, - // This list may be mutated later, so we should store the capacity - .symbols = this.symbols, - .module_scope = this.module_scope, - .char_freq = if (this.flags.has_char_freq) this.char_freq else null, - .exports_ref = this.exports_ref, - .module_ref = this.module_ref, - .wrapper_ref = this.wrapper_ref, - .require_ref = this.require_ref, - .top_level_await_keyword = this.top_level_await_keyword, - - // These are used when bundling. They are filled in during the parser pass - // since we already have to traverse the AST then anyway and the parser pass - // is conveniently fully parallelized. - .named_imports = this.named_imports, - .named_exports = this.named_exports, - .export_star_import_records = this.export_star_import_records, - - .top_level_symbols_to_parts = this.top_level_symbols_to_parts, - - .commonjs_named_exports = this.commonjs_named_exports, - - .redirect_import_record_index = this.redirect_import_record_index, - - .target = this.target, - - // .const_values = this.const_values, - .ts_enums = this.ts_enums, - - .uses_exports_ref = this.flags.uses_exports_ref, - .uses_module_ref = this.flags.uses_module_ref, - // .uses_require_ref = ast.uses_require_ref, - .export_keyword = .{ .len = if (this.flags.uses_export_keyword) 1 else 0, .loc = .{} }, - .force_cjs_to_esm = this.flags.force_cjs_to_esm, - .has_lazy_export = this.flags.has_lazy_export, - .commonjs_module_exports_assigned_deoptimized = this.flags.commonjs_module_exports_assigned_deoptimized, - .directive = if (this.flags.has_explicit_use_strict_directive) "use strict" else null, - .has_import_meta = this.flags.has_import_meta, - }; -} - -pub fn init(ast: Ast) BundledAst { - return .{ - .approximate_newline_count = @as(u32, @truncate(ast.approximate_newline_count)), - .nested_scope_slot_counts = ast.nested_scope_slot_counts, - - .exports_kind = ast.exports_kind, - - .import_records = ast.import_records, - - .hashbang = ast.hashbang, - .parts = ast.parts, - // This list may be mutated later, so we should store the capacity - .symbols = ast.symbols, - .module_scope = ast.module_scope, - .char_freq = ast.char_freq orelse undefined, - .exports_ref = ast.exports_ref, - .module_ref = ast.module_ref, - .wrapper_ref = ast.wrapper_ref, - .require_ref = ast.require_ref, - .top_level_await_keyword = ast.top_level_await_keyword, - // These are used when bundling. They are filled in during the parser pass - // since we already have to traverse the AST then anyway and the parser pass - // is conveniently fully parallelized. - .named_imports = ast.named_imports, - .named_exports = ast.named_exports, - .export_star_import_records = ast.export_star_import_records, - - // .allocator = ast.allocator, - .top_level_symbols_to_parts = ast.top_level_symbols_to_parts, - - .commonjs_named_exports = ast.commonjs_named_exports, - - .redirect_import_record_index = ast.redirect_import_record_index orelse std.math.maxInt(u32), - - .target = ast.target, - - // .const_values = ast.const_values, - .ts_enums = ast.ts_enums, - - .flags = .{ - .uses_exports_ref = ast.uses_exports_ref, - .uses_module_ref = ast.uses_module_ref, - // .uses_require_ref = ast.uses_require_ref, - .uses_export_keyword = ast.export_keyword.len > 0, - .has_char_freq = ast.char_freq != null, - .force_cjs_to_esm = ast.force_cjs_to_esm, - .has_lazy_export = ast.has_lazy_export, - .commonjs_module_exports_assigned_deoptimized = ast.commonjs_module_exports_assigned_deoptimized, - .has_explicit_use_strict_directive = strings.eqlComptime(ast.directive orelse "", "use strict"), - .has_import_meta = ast.has_import_meta, - }, - }; -} - -/// TODO: Move this from being done on all parse tasks into the start of the linker. This currently allocates base64 encoding for every small file loaded thing. -pub fn addUrlForCss( - this: *BundledAst, - allocator: std.mem.Allocator, - source: *const logger.Source, - mime_type_: ?[]const u8, - unique_key: ?[]const u8, - force_inline: bool, -) void { - { - const mime_type = if (mime_type_) |m| m else MimeType.byExtension(bun.strings.trimLeadingChar(std.fs.path.extension(source.path.text), '.')).value; - const contents = source.contents; - // TODO: make this configurable - const COPY_THRESHOLD = 128 * 1024; // 128kb - const should_copy = !force_inline and contents.len >= COPY_THRESHOLD and unique_key != null; - if (should_copy) return; - this.url_for_css = url_for_css: { - - // Encode as base64 - const encode_len = bun.base64.encodeLen(contents); - const data_url_prefix_len = "data:".len + mime_type.len + ";base64,".len; - const total_buffer_len = data_url_prefix_len + encode_len; - var encoded = bun.handleOom(allocator.alloc(u8, total_buffer_len)); - _ = std.fmt.bufPrint(encoded[0..data_url_prefix_len], "data:{s};base64,", .{mime_type}) catch unreachable; - const len = bun.base64.encode(encoded[data_url_prefix_len..], contents); - break :url_for_css encoded[0 .. data_url_prefix_len + len]; - }; - } -} - -pub const CommonJSNamedExports = Ast.CommonJSNamedExports; -pub const ConstValuesMap = Ast.ConstValuesMap; -pub const NamedExports = Ast.NamedExports; -pub const NamedImports = Ast.NamedImports; -pub const TopLevelSymbolToParts = Ast.TopLevelSymbolToParts; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const ImportRecord = bun.ImportRecord; -const logger = bun.logger; -const strings = bun.strings; -const MimeType = bun.http.MimeType; - -const js_ast = bun.ast; -const Ast = js_ast.Ast; -const BundledAst = js_ast.BundledAst; -const CharFreq = js_ast.CharFreq; -const ExportsKind = js_ast.ExportsKind; -const Part = js_ast.Part; -const Ref = js_ast.Ref; -const Scope = js_ast.Scope; -const SlotCounts = js_ast.SlotCounts; -const Symbol = js_ast.Symbol; -const TlaCheck = js_ast.TlaCheck; diff --git a/src/bundler/cache.zig b/src/bundler/cache.zig deleted file mode 100644 index 3fab1ab9347d..000000000000 --- a/src/bundler/cache.zig +++ /dev/null @@ -1,334 +0,0 @@ -pub const Set = struct { - js: JavaScript, - fs: Fs, - json: Json, - - pub fn init(allocator: std.mem.Allocator) Set { - return Set{ - .js = JavaScript.init(allocator), - .fs = Fs{ - .shared_buffer = MutableString.init(allocator, 0) catch unreachable, - .macro_shared_buffer = MutableString.init(allocator, 0) catch unreachable, - }, - .json = Json{}, - }; - } -}; -const debug = Output.scoped(.fs, .visible); -pub const Fs = struct { - pub const Entry = struct { - contents: string, - fd: FD, - /// When `contents` comes from a native plugin, this field is populated - /// with information on how to free it. - external_free_function: ExternalFreeFunction = .none, - - pub const ExternalFreeFunction = struct { - ctx: ?*anyopaque, - function: ?*const fn (?*anyopaque) callconv(.c) void, - - pub const none: ExternalFreeFunction = .{ .ctx = null, .function = null }; - - pub fn call(this: *const @This()) void { - if (this.function) |func| { - func(this.ctx); - } - } - }; - - pub fn deinit(entry: *Entry, allocator: std.mem.Allocator) void { - if (entry.external_free_function.function) |func| { - func(entry.external_free_function.ctx); - } else if (entry.contents.len > 0) { - allocator.free(entry.contents); - entry.contents = ""; - } - } - - pub fn closeFD(entry: *Entry) ?bun.sys.Error { - if (entry.fd.isValid()) { - defer entry.fd = .invalid; - return entry.fd.closeAllowingBadFileDescriptor(@returnAddress()); - } - return null; - } - }; - - shared_buffer: MutableString, - macro_shared_buffer: MutableString, - - use_alternate_source_cache: bool = false, - stream: bool = false, - - // When we are in a macro, the shared buffer may be in use by the in-progress macro. - // so we have to dynamically switch it out. - pub inline fn sharedBuffer(this: *Fs) *MutableString { - return if (!this.use_alternate_source_cache) - &this.shared_buffer - else - &this.macro_shared_buffer; - } - - /// When we need to suspend/resume something that has pointers into the shared buffer, we need to - /// switch out the shared buffer so that it is not in use - /// The caller must - pub fn resetSharedBuffer(this: *Fs, buffer: *MutableString) void { - if (buffer == &this.shared_buffer) { - this.shared_buffer = MutableString.initEmpty(bun.default_allocator); - } else if (buffer == &this.macro_shared_buffer) { - this.macro_shared_buffer = MutableString.initEmpty(bun.default_allocator); - } else { - bun.unreachablePanic("resetSharedBuffer: invalid buffer", .{}); - } - } - - pub fn deinit(c: *Fs) void { - var iter = c.entries.iterator(); - while (iter.next()) |entry| { - entry.value.deinit(c.entries.allocator); - } - c.entries.deinit(); - } - - pub fn readFileShared( - this: *Fs, - _fs: *fs.FileSystem, - path: [:0]const u8, - cached_file_descriptor: ?FD, - shared: *MutableString, - ) !Entry { - var rfs = _fs.fs; - - const file_handle: std.fs.File = if (cached_file_descriptor) |fd| handle: { - const handle = std.fs.File{ .handle = fd }; - try handle.seekTo(0); - break :handle handle; - } else try std.fs.openFileAbsoluteZ(path, .{ .mode = .read_only }); - - defer { - if (rfs.needToCloseFiles() and cached_file_descriptor == null) { - file_handle.close(); - } - } - - const file = if (this.stream) - rfs.readFileWithHandle(path, null, file_handle, true, shared, true) catch |err| { - if (comptime Environment.isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - } - else - rfs.readFileWithHandle(path, null, file_handle, true, shared, false) catch |err| { - if (comptime Environment.isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - }; - - return Entry{ - .contents = file.contents, - .fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0, - }; - } - - pub fn readFile( - c: *Fs, - _fs: *fs.FileSystem, - path: string, - dirname_fd: FD, - comptime use_shared_buffer: bool, - _file_handle: ?FD, - ) !Entry { - return c.readFileWithAllocator(bun.default_allocator, _fs, path, dirname_fd, use_shared_buffer, _file_handle); - } - - pub fn readFileWithAllocator( - c: *Fs, - allocator: std.mem.Allocator, - _fs: *fs.FileSystem, - path: string, - dirname_fd: FD, - comptime use_shared_buffer: bool, - _file_handle: ?FD, - ) !Entry { - var rfs = _fs.fs; - - var file_handle: std.fs.File = if (_file_handle) |__file| __file.stdFile() else undefined; - - if (_file_handle == null) { - if (FeatureFlags.store_file_descriptors and dirname_fd.isValid()) { - file_handle = (bun.sys.openatA(dirname_fd, std.fs.path.basename(path), bun.O.RDONLY, 0).unwrap() catch |err| brk: { - switch (err) { - error.ENOENT => { - const handle = try bun.openFile(path, .{ .mode = .read_only }); - Output.prettyErrorln( - "Internal error: directory mismatch for directory \"{s}\", fd {f}. You don't need to do anything, but this indicates a bug.", - .{ path, dirname_fd }, - ); - break :brk bun.FD.fromStdFile(handle); - }, - else => return err, - } - }).stdFile(); - } else { - file_handle = try bun.openFile(path, .{ .mode = .read_only }); - } - } else { - try file_handle.seekTo(0); - } - - if (comptime !Environment.isWindows) // skip on Windows because NTCreateFile will do it. - debug("openat({f}, {s}) = {f}", .{ dirname_fd, path, bun.FD.fromStdFile(file_handle) }); - - const will_close = rfs.needToCloseFiles() and _file_handle == null; - defer { - if (will_close) { - debug("readFileWithAllocator close({f})", .{bun.fs.printHandle(file_handle.handle)}); - file_handle.close(); - } - } - - const file = if (c.stream) - rfs.readFileWithHandleAndAllocator(allocator, path, null, file_handle, use_shared_buffer, c.sharedBuffer(), true) catch |err| { - if (Environment.isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - } - else - rfs.readFileWithHandleAndAllocator(allocator, path, null, file_handle, use_shared_buffer, c.sharedBuffer(), false) catch |err| { - if (Environment.isDebug) { - Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); - } - return err; - }; - - return Entry{ - .contents = file.contents, - .fd = if (FeatureFlags.store_file_descriptors and !will_close) .fromStdFile(file_handle) else bun.invalid_fd, - }; - } -}; - -pub const Css = struct { - pub const Entry = struct {}; - pub const Result = struct { - ok: bool, - value: void, - }; - pub fn parse(_: *@This(), _: *logger.Log, _: logger.Source) !Result { - Global.notimpl(); - } -}; - -pub const JavaScript = struct { - pub const Result = js_ast.Result; - - pub fn init(_: std.mem.Allocator) JavaScript { - return JavaScript{}; - } - // For now, we're not going to cache JavaScript ASTs. - // It's probably only relevant when bundling for production. - pub fn parse( - _: *const @This(), - allocator: std.mem.Allocator, - opts: js_parser.Parser.Options, - defines: *Define, - log: *logger.Log, - source: *const logger.Source, - ) anyerror!?js_ast.Result { - var temp_log = logger.Log.init(allocator); - temp_log.level = log.level; - var parser = js_parser.Parser.init(opts, &temp_log, source, defines, allocator) catch { - temp_log.appendToMaybeRecycled(log, source) catch {}; - return null; - }; - - const result = parser.parse() catch |err| { - if (temp_log.errors == 0) { - log.addRangeError(source, parser.lexer.range(), @errorName(err)) catch unreachable; - } - - temp_log.appendToMaybeRecycled(log, source) catch {}; - return null; - }; - - temp_log.appendToMaybeRecycled(log, source) catch {}; - return result; - } - - pub fn scan( - _: *@This(), - allocator: std.mem.Allocator, - scan_pass_result: *js_parser.ScanPassResult, - opts: js_parser.Parser.Options, - defines: *Define, - log: *logger.Log, - source: *const logger.Source, - ) anyerror!void { - if (strings.trim(source.contents, "\n\t\r ").len == 0) { - return; - } - - var temp_log = logger.Log.init(allocator); - defer temp_log.appendToMaybeRecycled(log, source) catch {}; - - var parser = js_parser.Parser.init(opts, &temp_log, source, defines, allocator) catch return; - - return try parser.scanImports(scan_pass_result); - } -}; - -pub const Json = struct { - pub fn init(_: std.mem.Allocator) Json { - return Json{}; - } - fn parse(_: *@This(), log: *logger.Log, source: *const logger.Source, allocator: std.mem.Allocator, comptime func: anytype, comptime force_utf8: bool) anyerror!?js_ast.Expr { - var temp_log = logger.Log.init(allocator); - defer { - temp_log.appendToMaybeRecycled(log, source) catch {}; - } - return func(source, &temp_log, allocator, force_utf8) catch handler: { - break :handler null; - }; - } - pub fn parseJSON(cache: *@This(), log: *logger.Log, source: *const logger.Source, allocator: std.mem.Allocator, mode: enum { json, jsonc }, comptime force_utf8: bool) anyerror!?js_ast.Expr { - // tsconfig.* and jsconfig.* files are JSON files, but they are not valid JSON files. - // They are JSON files with comments and trailing commas. - // Sometimes tooling expects this to work. - if (mode == .jsonc) { - return try parse(cache, log, source, allocator, json_parser.parseTSConfig, force_utf8); - } - - return try parse(cache, log, source, allocator, json_parser.parse, force_utf8); - } - - pub fn parsePackageJSON(cache: *@This(), log: *logger.Log, source: *const logger.Source, allocator: std.mem.Allocator, comptime force_utf8: bool) anyerror!?js_ast.Expr { - return try parse(cache, log, source, allocator, json_parser.parseTSConfig, force_utf8); - } - - pub fn parseTSConfig(cache: *@This(), log: *logger.Log, source: *const logger.Source, allocator: std.mem.Allocator) anyerror!?js_ast.Expr { - return try parse(cache, log, source, allocator, json_parser.parseTSConfig, true); - } -}; - -const string = []const u8; - -const fs = @import("../resolver/fs.zig"); -const std = @import("std"); -const Define = @import("./defines.zig").Define; - -const bun = @import("bun"); -const Environment = bun.Environment; -const FD = bun.FD; -const FeatureFlags = bun.FeatureFlags; -const Global = bun.Global; -const MutableString = bun.MutableString; -const Output = bun.Output; -const default_allocator = bun.default_allocator; -const js_ast = bun.ast; -const js_parser = bun.js_parser; -const json_parser = bun.json; -const logger = bun.logger; -const strings = bun.strings; diff --git a/src/bundler/defines-table.zig b/src/bundler/defines-table.zig deleted file mode 100644 index bcb67659da51..000000000000 --- a/src/bundler/defines-table.zig +++ /dev/null @@ -1,931 +0,0 @@ -// If something is in this list, then a direct identifier expression or property -// access chain matching this will be assumed to have no side effects and will -// be removed. -// -// This also means code is allowed to be reordered past things in this list. For -// example, if "console.log" is in this list, permitting reordering allows for -// "if (a) console.log(b); else console.log(c)" to be reordered and transformed -// into "console.log(a ? b : c)". Notice that "a" and "console.log" are in a -// different order, which can only happen if evaluating the "console.log" -// property access can be assumed to not change the value of "a". -// -// Note that membership in this list says nothing about whether calling any of -// these functions has any side effects. It only says something about -// referencing these function without calling them. -pub const global_no_side_effect_property_accesses = &[_][]const string{ - // Array: Static methods - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#Static_methods - &[_]string{ "Array", "from" }, - &[_]string{ "Array", "isArray" }, - &[_]string{ "Array", "of" }, - - // JSON: Static methods - &[_]string{ "JSON", "parse" }, - &[_]string{ "JSON", "stringify" }, - - // Math: Static properties - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math#Static_properties - &[_]string{ "Math", "E" }, - &[_]string{ "Math", "LN10" }, - &[_]string{ "Math", "LN2" }, - &[_]string{ "Math", "LOG10E" }, - &[_]string{ "Math", "LOG2E" }, - &[_]string{ "Math", "PI" }, - &[_]string{ "Math", "SQRT1_2" }, - &[_]string{ "Math", "SQRT2" }, - - // Math: Static methods - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math#Static_methods - &[_]string{ "Math", "abs" }, - &[_]string{ "Math", "acos" }, - &[_]string{ "Math", "acosh" }, - &[_]string{ "Math", "asin" }, - &[_]string{ "Math", "asinh" }, - &[_]string{ "Math", "atan" }, - &[_]string{ "Math", "atan2" }, - &[_]string{ "Math", "atanh" }, - &[_]string{ "Math", "cbrt" }, - &[_]string{ "Math", "ceil" }, - &[_]string{ "Math", "clz32" }, - &[_]string{ "Math", "cos" }, - &[_]string{ "Math", "cosh" }, - &[_]string{ "Math", "exp" }, - &[_]string{ "Math", "expm1" }, - &[_]string{ "Math", "floor" }, - &[_]string{ "Math", "fround" }, - &[_]string{ "Math", "hypot" }, - &[_]string{ "Math", "imul" }, - &[_]string{ "Math", "log" }, - &[_]string{ "Math", "log10" }, - &[_]string{ "Math", "log1p" }, - &[_]string{ "Math", "log2" }, - &[_]string{ "Math", "max" }, - &[_]string{ "Math", "min" }, - &[_]string{ "Math", "pow" }, - &[_]string{ "Math", "random" }, - &[_]string{ "Math", "round" }, - &[_]string{ "Math", "sign" }, - &[_]string{ "Math", "sin" }, - &[_]string{ "Math", "sinh" }, - &[_]string{ "Math", "sqrt" }, - &[_]string{ "Math", "tan" }, - &[_]string{ "Math", "tanh" }, - &[_]string{ "Math", "trunc" }, - - // Number: Static methods - &[_]string{ "Number", "isFinite" }, - &[_]string{ "Number", "isInteger" }, - &[_]string{ "Number", "isNaN" }, - &[_]string{ "Number", "isSafeInteger" }, - &[_]string{ "Number", "parseFloat" }, - &[_]string{ "Number", "parseInt" }, - - // Object: Static methods - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#Static_methods - &[_]string{ "Object", "assign" }, - &[_]string{ "Object", "create" }, - &[_]string{ "Object", "defineProperties" }, - &[_]string{ "Object", "defineProperty" }, - &[_]string{ "Object", "entries" }, - &[_]string{ "Object", "freeze" }, - &[_]string{ "Object", "fromEntries" }, - &[_]string{ "Object", "getOwnPropertyDescriptor" }, - &[_]string{ "Object", "getOwnPropertyDescriptors" }, - &[_]string{ "Object", "getOwnPropertyNames" }, - &[_]string{ "Object", "getOwnPropertySymbols" }, - &[_]string{ "Object", "getPrototypeOf" }, - &[_]string{ "Object", "groupBy" }, - &[_]string{ "Object", "hasOwn" }, - &[_]string{ "Object", "is" }, - &[_]string{ "Object", "isExtensible" }, - &[_]string{ "Object", "isFrozen" }, - &[_]string{ "Object", "isSealed" }, - &[_]string{ "Object", "keys" }, - &[_]string{ "Object", "preventExtensions" }, - &[_]string{ "Object", "seal" }, - &[_]string{ "Object", "setPrototypeOf" }, - &[_]string{ "Object", "values" }, - - // Object: Instance methods - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#Instance_methods - &[_]string{ "Object", "prototype", "__defineGetter__" }, - &[_]string{ "Object", "prototype", "__defineSetter__" }, - &[_]string{ "Object", "prototype", "__lookupGetter__" }, - &[_]string{ "Object", "prototype", "__lookupSetter__" }, - &[_]string{ "Object", "prototype", "hasOwnProperty" }, - &[_]string{ "Object", "prototype", "isPrototypeOf" }, - &[_]string{ "Object", "prototype", "propertyIsEnumerable" }, - &[_]string{ "Object", "prototype", "toLocaleString" }, - &[_]string{ "Object", "prototype", "toString" }, - &[_]string{ "Object", "prototype", "unwatch" }, - &[_]string{ "Object", "prototype", "valueOf" }, - &[_]string{ "Object", "prototype", "watch" }, - - // Reflect: Static methods - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect#static_methods - &[_]string{ "Reflect", "apply" }, - &[_]string{ "Reflect", "construct" }, - &[_]string{ "Reflect", "defineProperty" }, - &[_]string{ "Reflect", "deleteProperty" }, - &[_]string{ "Reflect", "get" }, - &[_]string{ "Reflect", "getOwnPropertyDescriptor" }, - &[_]string{ "Reflect", "getPrototypeOf" }, - &[_]string{ "Reflect", "has" }, - &[_]string{ "Reflect", "isExtensible" }, - &[_]string{ "Reflect", "ownKeys" }, - &[_]string{ "Reflect", "preventExtensions" }, - &[_]string{ "Reflect", "set" }, - &[_]string{ "Reflect", "setPrototypeOf" }, - - // Symbol: Static properties - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#static_properties - &[_]string{ "Symbol", "asyncDispose" }, - &[_]string{ "Symbol", "asyncIterator" }, - &[_]string{ "Symbol", "dispose" }, - &[_]string{ "Symbol", "hasInstance" }, - &[_]string{ "Symbol", "isConcatSpreadable" }, - &[_]string{ "Symbol", "iterator" }, - &[_]string{ "Symbol", "match" }, - &[_]string{ "Symbol", "matchAll" }, - &[_]string{ "Symbol", "replace" }, - &[_]string{ "Symbol", "search" }, - &[_]string{ "Symbol", "species" }, - &[_]string{ "Symbol", "split" }, - &[_]string{ "Symbol", "toPrimitive" }, - &[_]string{ "Symbol", "toStringTag" }, - &[_]string{ "Symbol", "unscopables" }, - - // Symbol: Static methods - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol#static_methods - &[_]string{ "Symbol", "keyFor" }, - - // Console method references are assumed to have no side effects - // https://developer.mozilla.org/en-US/docs/Web/API/console - &[_]string{ "console", "assert" }, - &[_]string{ "console", "clear" }, - &[_]string{ "console", "count" }, - &[_]string{ "console", "countReset" }, - &[_]string{ "console", "debug" }, - &[_]string{ "console", "dir" }, - &[_]string{ "console", "dirxml" }, - &[_]string{ "console", "error" }, - &[_]string{ "console", "group" }, - &[_]string{ "console", "groupCollapsed" }, - &[_]string{ "console", "groupEnd" }, - &[_]string{ "console", "info" }, - &[_]string{ "console", "log" }, - &[_]string{ "console", "table" }, - &[_]string{ "console", "time" }, - &[_]string{ "console", "timeEnd" }, - &[_]string{ "console", "timeLog" }, - &[_]string{ "console", "trace" }, - &[_]string{ "console", "warn" }, - - &[_]string{ "Promise", "resolve" }, - &[_]string{ "Promise", "reject" }, - &[_]string{ "Promise", "all" }, - - // Crypto: Static methods - &[_]string{ "crypto", "randomUUID" }, -}; - -pub const global_no_side_effect_function_calls_safe_for_to_string = &[_][]const string{ - - // Calling Symbol.for("foo") never throws (unless it's a rope string) - // This improves React bundle sizes slightly. - &[_]string{ "Symbol", "for" }, - - // Haven't seen a bundle size improvement from adding more to this list yet. -}; - -const pure_global_identifier_define = &defines.IdentifierDefine{ - .flags = .{ - .valueless = true, - .can_be_removed_if_unused = true, - }, - .value = .{ .e_undefined = .{} }, -}; - -const identifiers = struct { - const nan_val = js_ast.E.Number{ .value = std.math.nan(f64) }; - - const inf_val = js_ast.E.Number{ .value = std.math.inf(f64) }; - - // Step 2. Swap in certain literal values because those can be constant folded - pub const @"undefined" = &defines.IdentifierDefine{ - .value = js_ast.Expr.Data{ .e_undefined = .{} }, - .flags = .{ - .valueless = false, - .can_be_removed_if_unused = true, - }, - }; - pub const NaN = &defines.IdentifierDefine{ - .value = js_ast.Expr.Data{ .e_number = nan_val }, - }; - pub const Infinity = &defines.IdentifierDefine{ - .value = js_ast.Expr.Data{ .e_number = inf_val }, - }; -}; - -const PureGlobalIdentifierValue = enum { - NaN, - Infinity, - @"strict undefined", - other, - - pub fn value(this: PureGlobalIdentifierValue) *const defines.IdentifierDefine { - return switch (this) { - .NaN => identifiers.NaN, - .Infinity => identifiers.Infinity, - .@"strict undefined" => identifiers.undefined, - .other => pure_global_identifier_define, - }; - } -}; - -pub const pure_global_identifier_map = bun.ComptimeStringMap(PureGlobalIdentifierValue, .{ - .{ "NaN", PureGlobalIdentifierValue.NaN }, - .{ "Infinity", PureGlobalIdentifierValue.Infinity }, - .{ "undefined", PureGlobalIdentifierValue.@"strict undefined" }, - - // These global identifiers should exist in all JavaScript environments. This - // deliberately omits "NaN", "Infinity", and "undefined" because these are - // treated as automatically-inlined constants instead of identifiers. - .{ "Array", PureGlobalIdentifierValue.other }, - .{ "Boolean", PureGlobalIdentifierValue.other }, - .{ "Function", PureGlobalIdentifierValue.other }, - .{ "Math", PureGlobalIdentifierValue.other }, - .{ "Number", PureGlobalIdentifierValue.other }, - .{ "Object", PureGlobalIdentifierValue.other }, - .{ "RegExp", PureGlobalIdentifierValue.other }, - .{ "String", PureGlobalIdentifierValue.other }, - - // Other globals present in both the browser and node (except "eval" because - // it has special behavior) - .{ "AbortController", PureGlobalIdentifierValue.other }, - .{ "AbortSignal", PureGlobalIdentifierValue.other }, - .{ "AggregateError", PureGlobalIdentifierValue.other }, - .{ "ArrayBuffer", PureGlobalIdentifierValue.other }, - .{ "BigInt", PureGlobalIdentifierValue.other }, - .{ "DataView", PureGlobalIdentifierValue.other }, - .{ "Date", PureGlobalIdentifierValue.other }, - .{ "Error", PureGlobalIdentifierValue.other }, - .{ "EvalError", PureGlobalIdentifierValue.other }, - .{ "Event", PureGlobalIdentifierValue.other }, - .{ "EventTarget", PureGlobalIdentifierValue.other }, - .{ "Float16Array", PureGlobalIdentifierValue.other }, - .{ "Float32Array", PureGlobalIdentifierValue.other }, - .{ "Float64Array", PureGlobalIdentifierValue.other }, - .{ "Int16Array", PureGlobalIdentifierValue.other }, - .{ "Int32Array", PureGlobalIdentifierValue.other }, - .{ "Int8Array", PureGlobalIdentifierValue.other }, - .{ "Intl", PureGlobalIdentifierValue.other }, - .{ "JSON", PureGlobalIdentifierValue.other }, - .{ "Map", PureGlobalIdentifierValue.other }, - .{ "MessageChannel", PureGlobalIdentifierValue.other }, - .{ "MessageEvent", PureGlobalIdentifierValue.other }, - .{ "MessagePort", PureGlobalIdentifierValue.other }, - .{ "Promise", PureGlobalIdentifierValue.other }, - .{ "Proxy", PureGlobalIdentifierValue.other }, - .{ "RangeError", PureGlobalIdentifierValue.other }, - .{ "ReferenceError", PureGlobalIdentifierValue.other }, - .{ "Reflect", PureGlobalIdentifierValue.other }, - .{ "Set", PureGlobalIdentifierValue.other }, - .{ "Symbol", PureGlobalIdentifierValue.other }, - .{ "SyntaxError", PureGlobalIdentifierValue.other }, - .{ "TextDecoder", PureGlobalIdentifierValue.other }, - .{ "TextEncoder", PureGlobalIdentifierValue.other }, - .{ "TypeError", PureGlobalIdentifierValue.other }, - .{ "URIError", PureGlobalIdentifierValue.other }, - .{ "URL", PureGlobalIdentifierValue.other }, - .{ "URLSearchParams", PureGlobalIdentifierValue.other }, - .{ "Uint16Array", PureGlobalIdentifierValue.other }, - .{ "Uint32Array", PureGlobalIdentifierValue.other }, - .{ "Uint8Array", PureGlobalIdentifierValue.other }, - .{ "Uint8ClampedArray", PureGlobalIdentifierValue.other }, - .{ "WeakMap", PureGlobalIdentifierValue.other }, - .{ "WeakSet", PureGlobalIdentifierValue.other }, - .{ "WebAssembly", PureGlobalIdentifierValue.other }, - .{ "clearInterval", PureGlobalIdentifierValue.other }, - .{ "clearTimeout", PureGlobalIdentifierValue.other }, - .{ "console", PureGlobalIdentifierValue.other }, - .{ "decodeURI", PureGlobalIdentifierValue.other }, - .{ "decodeURIComponent", PureGlobalIdentifierValue.other }, - .{ "encodeURI", PureGlobalIdentifierValue.other }, - .{ "encodeURIComponent", PureGlobalIdentifierValue.other }, - .{ "escape", PureGlobalIdentifierValue.other }, - .{ "globalThis", PureGlobalIdentifierValue.other }, - .{ "isFinite", PureGlobalIdentifierValue.other }, - .{ "isNaN", PureGlobalIdentifierValue.other }, - .{ "parseFloat", PureGlobalIdentifierValue.other }, - .{ "parseInt", PureGlobalIdentifierValue.other }, - .{ "queueMicrotask", PureGlobalIdentifierValue.other }, - .{ "setInterval", PureGlobalIdentifierValue.other }, - .{ "setTimeout", PureGlobalIdentifierValue.other }, - .{ "unescape", PureGlobalIdentifierValue.other }, - - // CSSOM APIs - .{ "CSSAnimation", PureGlobalIdentifierValue.other }, - .{ "CSSFontFaceRule", PureGlobalIdentifierValue.other }, - .{ "CSSImportRule", PureGlobalIdentifierValue.other }, - .{ "CSSKeyframeRule", PureGlobalIdentifierValue.other }, - .{ "CSSKeyframesRule", PureGlobalIdentifierValue.other }, - .{ "CSSMediaRule", PureGlobalIdentifierValue.other }, - .{ "CSSNamespaceRule", PureGlobalIdentifierValue.other }, - .{ "CSSPageRule", PureGlobalIdentifierValue.other }, - .{ "CSSRule", PureGlobalIdentifierValue.other }, - .{ "CSSRuleList", PureGlobalIdentifierValue.other }, - .{ "CSSStyleDeclaration", PureGlobalIdentifierValue.other }, - .{ "CSSStyleRule", PureGlobalIdentifierValue.other }, - .{ "CSSStyleSheet", PureGlobalIdentifierValue.other }, - .{ "CSSSupportsRule", PureGlobalIdentifierValue.other }, - .{ "CSSTransition", PureGlobalIdentifierValue.other }, - - // SVG DOM - .{ "SVGAElement", PureGlobalIdentifierValue.other }, - .{ "SVGAngle", PureGlobalIdentifierValue.other }, - .{ "SVGAnimateElement", PureGlobalIdentifierValue.other }, - .{ "SVGAnimateMotionElement", PureGlobalIdentifierValue.other }, - .{ "SVGAnimateTransformElement", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedAngle", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedBoolean", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedEnumeration", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedInteger", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedLength", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedLengthList", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedNumber", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedNumberList", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedPreserveAspectRatio", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedRect", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedString", PureGlobalIdentifierValue.other }, - .{ "SVGAnimatedTransformList", PureGlobalIdentifierValue.other }, - .{ "SVGAnimationElement", PureGlobalIdentifierValue.other }, - .{ "SVGCircleElement", PureGlobalIdentifierValue.other }, - .{ "SVGClipPathElement", PureGlobalIdentifierValue.other }, - .{ "SVGComponentTransferFunctionElement", PureGlobalIdentifierValue.other }, - .{ "SVGDefsElement", PureGlobalIdentifierValue.other }, - .{ "SVGDescElement", PureGlobalIdentifierValue.other }, - .{ "SVGElement", PureGlobalIdentifierValue.other }, - .{ "SVGEllipseElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEBlendElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEColorMatrixElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEComponentTransferElement", PureGlobalIdentifierValue.other }, - .{ "SVGFECompositeElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEConvolveMatrixElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEDiffuseLightingElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEDisplacementMapElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEDistantLightElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEDropShadowElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEFloodElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEFuncAElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEFuncBElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEFuncGElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEFuncRElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEGaussianBlurElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEImageElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEMergeElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEMergeNodeElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEMorphologyElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEOffsetElement", PureGlobalIdentifierValue.other }, - .{ "SVGFEPointLightElement", PureGlobalIdentifierValue.other }, - .{ "SVGFESpecularLightingElement", PureGlobalIdentifierValue.other }, - .{ "SVGFESpotLightElement", PureGlobalIdentifierValue.other }, - .{ "SVGFETileElement", PureGlobalIdentifierValue.other }, - .{ "SVGFETurbulenceElement", PureGlobalIdentifierValue.other }, - .{ "SVGFilterElement", PureGlobalIdentifierValue.other }, - .{ "SVGForeignObjectElement", PureGlobalIdentifierValue.other }, - .{ "SVGGElement", PureGlobalIdentifierValue.other }, - .{ "SVGGeometryElement", PureGlobalIdentifierValue.other }, - .{ "SVGGradientElement", PureGlobalIdentifierValue.other }, - .{ "SVGGraphicsElement", PureGlobalIdentifierValue.other }, - .{ "SVGImageElement", PureGlobalIdentifierValue.other }, - .{ "SVGLength", PureGlobalIdentifierValue.other }, - .{ "SVGLengthList", PureGlobalIdentifierValue.other }, - .{ "SVGLineElement", PureGlobalIdentifierValue.other }, - .{ "SVGLinearGradientElement", PureGlobalIdentifierValue.other }, - .{ "SVGMPathElement", PureGlobalIdentifierValue.other }, - .{ "SVGMarkerElement", PureGlobalIdentifierValue.other }, - .{ "SVGMaskElement", PureGlobalIdentifierValue.other }, - .{ "SVGMatrix", PureGlobalIdentifierValue.other }, - .{ "SVGMetadataElement", PureGlobalIdentifierValue.other }, - .{ "SVGNumber", PureGlobalIdentifierValue.other }, - .{ "SVGNumberList", PureGlobalIdentifierValue.other }, - .{ "SVGPathElement", PureGlobalIdentifierValue.other }, - .{ "SVGPatternElement", PureGlobalIdentifierValue.other }, - .{ "SVGPoint", PureGlobalIdentifierValue.other }, - .{ "SVGPointList", PureGlobalIdentifierValue.other }, - .{ "SVGPolygonElement", PureGlobalIdentifierValue.other }, - .{ "SVGPolylineElement", PureGlobalIdentifierValue.other }, - .{ "SVGPreserveAspectRatio", PureGlobalIdentifierValue.other }, - .{ "SVGRadialGradientElement", PureGlobalIdentifierValue.other }, - .{ "SVGRect", PureGlobalIdentifierValue.other }, - .{ "SVGRectElement", PureGlobalIdentifierValue.other }, - .{ "SVGSVGElement", PureGlobalIdentifierValue.other }, - .{ "SVGScriptElement", PureGlobalIdentifierValue.other }, - .{ "SVGSetElement", PureGlobalIdentifierValue.other }, - .{ "SVGStopElement", PureGlobalIdentifierValue.other }, - .{ "SVGStringList", PureGlobalIdentifierValue.other }, - .{ "SVGStyleElement", PureGlobalIdentifierValue.other }, - .{ "SVGSwitchElement", PureGlobalIdentifierValue.other }, - .{ "SVGSymbolElement", PureGlobalIdentifierValue.other }, - .{ "SVGTSpanElement", PureGlobalIdentifierValue.other }, - .{ "SVGTextContentElement", PureGlobalIdentifierValue.other }, - .{ "SVGTextElement", PureGlobalIdentifierValue.other }, - .{ "SVGTextPathElement", PureGlobalIdentifierValue.other }, - .{ "SVGTextPositioningElement", PureGlobalIdentifierValue.other }, - .{ "SVGTitleElement", PureGlobalIdentifierValue.other }, - .{ "SVGTransform", PureGlobalIdentifierValue.other }, - .{ "SVGTransformList", PureGlobalIdentifierValue.other }, - .{ "SVGUnitTypes", PureGlobalIdentifierValue.other }, - .{ "SVGUseElement", PureGlobalIdentifierValue.other }, - .{ "SVGViewElement", PureGlobalIdentifierValue.other }, - - // Other browser APIs - // - // This list contains all globals present in modern versions of Chrome, Safari, - // and Firefox except for the following properties, since they have a side effect - // of triggering layout (https://gist.github.com/paulirish/5d52fb081b3570c81e3a): - // - // - scrollX - // - scrollY - // - innerWidth - // - innerHeight - // - pageXOffset - // - pageYOffset - // - // The following globals have also been removed since they sometimes throw an - // exception when accessed, which is a side effect (for more information see - // https://stackoverflow.com/a/33047477): - // - // - localStorage - // - sessionStorage - // - .{ "AnalyserNode", PureGlobalIdentifierValue.other }, - .{ "Animation", PureGlobalIdentifierValue.other }, - .{ "AnimationEffect", PureGlobalIdentifierValue.other }, - .{ "AnimationEvent", PureGlobalIdentifierValue.other }, - .{ "AnimationPlaybackEvent", PureGlobalIdentifierValue.other }, - .{ "AnimationTimeline", PureGlobalIdentifierValue.other }, - .{ "Attr", PureGlobalIdentifierValue.other }, - .{ "Audio", PureGlobalIdentifierValue.other }, - .{ "AudioBuffer", PureGlobalIdentifierValue.other }, - .{ "AudioBufferSourceNode", PureGlobalIdentifierValue.other }, - .{ "AudioDestinationNode", PureGlobalIdentifierValue.other }, - .{ "AudioListener", PureGlobalIdentifierValue.other }, - .{ "AudioNode", PureGlobalIdentifierValue.other }, - .{ "AudioParam", PureGlobalIdentifierValue.other }, - .{ "AudioProcessingEvent", PureGlobalIdentifierValue.other }, - .{ "AudioScheduledSourceNode", PureGlobalIdentifierValue.other }, - .{ "BarProp", PureGlobalIdentifierValue.other }, - .{ "BeforeUnloadEvent", PureGlobalIdentifierValue.other }, - .{ "BiquadFilterNode", PureGlobalIdentifierValue.other }, - .{ "Blob", PureGlobalIdentifierValue.other }, - .{ "BlobEvent", PureGlobalIdentifierValue.other }, - .{ "ByteLengthQueuingStrategy", PureGlobalIdentifierValue.other }, - .{ "CDATASection", PureGlobalIdentifierValue.other }, - .{ "CSS", PureGlobalIdentifierValue.other }, - .{ "CanvasGradient", PureGlobalIdentifierValue.other }, - .{ "CanvasPattern", PureGlobalIdentifierValue.other }, - .{ "CanvasRenderingContext2D", PureGlobalIdentifierValue.other }, - .{ "ChannelMergerNode", PureGlobalIdentifierValue.other }, - .{ "ChannelSplitterNode", PureGlobalIdentifierValue.other }, - .{ "CharacterData", PureGlobalIdentifierValue.other }, - .{ "ClipboardEvent", PureGlobalIdentifierValue.other }, - .{ "CloseEvent", PureGlobalIdentifierValue.other }, - .{ "Comment", PureGlobalIdentifierValue.other }, - .{ "CompositionEvent", PureGlobalIdentifierValue.other }, - .{ "ConvolverNode", PureGlobalIdentifierValue.other }, - .{ "CountQueuingStrategy", PureGlobalIdentifierValue.other }, - .{ "Crypto", PureGlobalIdentifierValue.other }, - .{ "CustomElementRegistry", PureGlobalIdentifierValue.other }, - .{ "CustomEvent", PureGlobalIdentifierValue.other }, - .{ "DOMException", PureGlobalIdentifierValue.other }, - .{ "DOMImplementation", PureGlobalIdentifierValue.other }, - .{ "DOMMatrix", PureGlobalIdentifierValue.other }, - .{ "DOMMatrixReadOnly", PureGlobalIdentifierValue.other }, - .{ "DOMParser", PureGlobalIdentifierValue.other }, - .{ "DOMPoint", PureGlobalIdentifierValue.other }, - .{ "DOMPointReadOnly", PureGlobalIdentifierValue.other }, - .{ "DOMQuad", PureGlobalIdentifierValue.other }, - .{ "DOMRect", PureGlobalIdentifierValue.other }, - .{ "DOMRectList", PureGlobalIdentifierValue.other }, - .{ "DOMRectReadOnly", PureGlobalIdentifierValue.other }, - .{ "DOMStringList", PureGlobalIdentifierValue.other }, - .{ "DOMStringMap", PureGlobalIdentifierValue.other }, - .{ "DOMTokenList", PureGlobalIdentifierValue.other }, - .{ "DataTransfer", PureGlobalIdentifierValue.other }, - .{ "DataTransferItem", PureGlobalIdentifierValue.other }, - .{ "DataTransferItemList", PureGlobalIdentifierValue.other }, - .{ "DelayNode", PureGlobalIdentifierValue.other }, - .{ "Document", PureGlobalIdentifierValue.other }, - .{ "DocumentFragment", PureGlobalIdentifierValue.other }, - .{ "DocumentTimeline", PureGlobalIdentifierValue.other }, - .{ "DocumentType", PureGlobalIdentifierValue.other }, - .{ "DragEvent", PureGlobalIdentifierValue.other }, - .{ "DynamicsCompressorNode", PureGlobalIdentifierValue.other }, - .{ "Element", PureGlobalIdentifierValue.other }, - .{ "ErrorEvent", PureGlobalIdentifierValue.other }, - .{ "EventSource", PureGlobalIdentifierValue.other }, - .{ "File", PureGlobalIdentifierValue.other }, - .{ "FileList", PureGlobalIdentifierValue.other }, - .{ "FileReader", PureGlobalIdentifierValue.other }, - .{ "FocusEvent", PureGlobalIdentifierValue.other }, - .{ "FontFace", PureGlobalIdentifierValue.other }, - .{ "FormData", PureGlobalIdentifierValue.other }, - .{ "GainNode", PureGlobalIdentifierValue.other }, - .{ "Gamepad", PureGlobalIdentifierValue.other }, - .{ "GamepadButton", PureGlobalIdentifierValue.other }, - .{ "GamepadEvent", PureGlobalIdentifierValue.other }, - .{ "Geolocation", PureGlobalIdentifierValue.other }, - .{ "GeolocationPositionError", PureGlobalIdentifierValue.other }, - .{ "HTMLAllCollection", PureGlobalIdentifierValue.other }, - .{ "HTMLAnchorElement", PureGlobalIdentifierValue.other }, - .{ "HTMLAreaElement", PureGlobalIdentifierValue.other }, - .{ "HTMLAudioElement", PureGlobalIdentifierValue.other }, - .{ "HTMLBRElement", PureGlobalIdentifierValue.other }, - .{ "HTMLBaseElement", PureGlobalIdentifierValue.other }, - .{ "HTMLBodyElement", PureGlobalIdentifierValue.other }, - .{ "HTMLButtonElement", PureGlobalIdentifierValue.other }, - .{ "HTMLCanvasElement", PureGlobalIdentifierValue.other }, - .{ "HTMLCollection", PureGlobalIdentifierValue.other }, - .{ "HTMLDListElement", PureGlobalIdentifierValue.other }, - .{ "HTMLDataElement", PureGlobalIdentifierValue.other }, - .{ "HTMLDataListElement", PureGlobalIdentifierValue.other }, - .{ "HTMLDetailsElement", PureGlobalIdentifierValue.other }, - .{ "HTMLDirectoryElement", PureGlobalIdentifierValue.other }, - .{ "HTMLDivElement", PureGlobalIdentifierValue.other }, - .{ "HTMLDocument", PureGlobalIdentifierValue.other }, - .{ "HTMLElement", PureGlobalIdentifierValue.other }, - .{ "HTMLEmbedElement", PureGlobalIdentifierValue.other }, - .{ "HTMLFieldSetElement", PureGlobalIdentifierValue.other }, - .{ "HTMLFontElement", PureGlobalIdentifierValue.other }, - .{ "HTMLFormControlsCollection", PureGlobalIdentifierValue.other }, - .{ "HTMLFormElement", PureGlobalIdentifierValue.other }, - .{ "HTMLFrameElement", PureGlobalIdentifierValue.other }, - .{ "HTMLFrameSetElement", PureGlobalIdentifierValue.other }, - .{ "HTMLHRElement", PureGlobalIdentifierValue.other }, - .{ "HTMLHeadElement", PureGlobalIdentifierValue.other }, - .{ "HTMLHeadingElement", PureGlobalIdentifierValue.other }, - .{ "HTMLHtmlElement", PureGlobalIdentifierValue.other }, - .{ "HTMLIFrameElement", PureGlobalIdentifierValue.other }, - .{ "HTMLImageElement", PureGlobalIdentifierValue.other }, - .{ "HTMLInputElement", PureGlobalIdentifierValue.other }, - .{ "HTMLLIElement", PureGlobalIdentifierValue.other }, - .{ "HTMLLabelElement", PureGlobalIdentifierValue.other }, - .{ "HTMLLegendElement", PureGlobalIdentifierValue.other }, - .{ "HTMLLinkElement", PureGlobalIdentifierValue.other }, - .{ "HTMLMapElement", PureGlobalIdentifierValue.other }, - .{ "HTMLMarqueeElement", PureGlobalIdentifierValue.other }, - .{ "HTMLMediaElement", PureGlobalIdentifierValue.other }, - .{ "HTMLMenuElement", PureGlobalIdentifierValue.other }, - .{ "HTMLMetaElement", PureGlobalIdentifierValue.other }, - .{ "HTMLMeterElement", PureGlobalIdentifierValue.other }, - .{ "HTMLModElement", PureGlobalIdentifierValue.other }, - .{ "HTMLOListElement", PureGlobalIdentifierValue.other }, - .{ "HTMLObjectElement", PureGlobalIdentifierValue.other }, - .{ "HTMLOptGroupElement", PureGlobalIdentifierValue.other }, - .{ "HTMLOptionElement", PureGlobalIdentifierValue.other }, - .{ "HTMLOptionsCollection", PureGlobalIdentifierValue.other }, - .{ "HTMLOutputElement", PureGlobalIdentifierValue.other }, - .{ "HTMLParagraphElement", PureGlobalIdentifierValue.other }, - .{ "HTMLParamElement", PureGlobalIdentifierValue.other }, - .{ "HTMLPictureElement", PureGlobalIdentifierValue.other }, - .{ "HTMLPreElement", PureGlobalIdentifierValue.other }, - .{ "HTMLProgressElement", PureGlobalIdentifierValue.other }, - .{ "HTMLQuoteElement", PureGlobalIdentifierValue.other }, - .{ "HTMLScriptElement", PureGlobalIdentifierValue.other }, - .{ "HTMLSelectElement", PureGlobalIdentifierValue.other }, - .{ "HTMLSlotElement", PureGlobalIdentifierValue.other }, - .{ "HTMLSourceElement", PureGlobalIdentifierValue.other }, - .{ "HTMLSpanElement", PureGlobalIdentifierValue.other }, - .{ "HTMLStyleElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTableCaptionElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTableCellElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTableColElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTableElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTableRowElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTableSectionElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTemplateElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTextAreaElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTimeElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTitleElement", PureGlobalIdentifierValue.other }, - .{ "HTMLTrackElement", PureGlobalIdentifierValue.other }, - .{ "HTMLUListElement", PureGlobalIdentifierValue.other }, - .{ "HTMLUnknownElement", PureGlobalIdentifierValue.other }, - .{ "HTMLVideoElement", PureGlobalIdentifierValue.other }, - .{ "HashChangeEvent", PureGlobalIdentifierValue.other }, - .{ "Headers", PureGlobalIdentifierValue.other }, - .{ "History", PureGlobalIdentifierValue.other }, - .{ "IDBCursor", PureGlobalIdentifierValue.other }, - .{ "IDBCursorWithValue", PureGlobalIdentifierValue.other }, - .{ "IDBDatabase", PureGlobalIdentifierValue.other }, - .{ "IDBFactory", PureGlobalIdentifierValue.other }, - .{ "IDBIndex", PureGlobalIdentifierValue.other }, - .{ "IDBKeyRange", PureGlobalIdentifierValue.other }, - .{ "IDBObjectStore", PureGlobalIdentifierValue.other }, - .{ "IDBOpenDBRequest", PureGlobalIdentifierValue.other }, - .{ "IDBRequest", PureGlobalIdentifierValue.other }, - .{ "IDBTransaction", PureGlobalIdentifierValue.other }, - .{ "IDBVersionChangeEvent", PureGlobalIdentifierValue.other }, - .{ "Image", PureGlobalIdentifierValue.other }, - .{ "ImageData", PureGlobalIdentifierValue.other }, - .{ "InputEvent", PureGlobalIdentifierValue.other }, - .{ "IntersectionObserver", PureGlobalIdentifierValue.other }, - .{ "IntersectionObserverEntry", PureGlobalIdentifierValue.other }, - .{ "KeyboardEvent", PureGlobalIdentifierValue.other }, - .{ "KeyframeEffect", PureGlobalIdentifierValue.other }, - .{ "Location", PureGlobalIdentifierValue.other }, - .{ "MediaCapabilities", PureGlobalIdentifierValue.other }, - .{ "MediaElementAudioSourceNode", PureGlobalIdentifierValue.other }, - .{ "MediaEncryptedEvent", PureGlobalIdentifierValue.other }, - .{ "MediaError", PureGlobalIdentifierValue.other }, - .{ "MediaList", PureGlobalIdentifierValue.other }, - .{ "MediaQueryList", PureGlobalIdentifierValue.other }, - .{ "MediaQueryListEvent", PureGlobalIdentifierValue.other }, - .{ "MediaRecorder", PureGlobalIdentifierValue.other }, - .{ "MediaSource", PureGlobalIdentifierValue.other }, - .{ "MediaStream", PureGlobalIdentifierValue.other }, - .{ "MediaStreamAudioDestinationNode", PureGlobalIdentifierValue.other }, - .{ "MediaStreamAudioSourceNode", PureGlobalIdentifierValue.other }, - .{ "MediaStreamTrack", PureGlobalIdentifierValue.other }, - .{ "MediaStreamTrackEvent", PureGlobalIdentifierValue.other }, - .{ "MimeType", PureGlobalIdentifierValue.other }, - .{ "MimeTypeArray", PureGlobalIdentifierValue.other }, - .{ "MouseEvent", PureGlobalIdentifierValue.other }, - .{ "MutationEvent", PureGlobalIdentifierValue.other }, - .{ "MutationObserver", PureGlobalIdentifierValue.other }, - .{ "MutationRecord", PureGlobalIdentifierValue.other }, - .{ "NamedNodeMap", PureGlobalIdentifierValue.other }, - .{ "Navigator", PureGlobalIdentifierValue.other }, - .{ "Node", PureGlobalIdentifierValue.other }, - .{ "NodeFilter", PureGlobalIdentifierValue.other }, - .{ "NodeIterator", PureGlobalIdentifierValue.other }, - .{ "NodeList", PureGlobalIdentifierValue.other }, - .{ "Notification", PureGlobalIdentifierValue.other }, - .{ "OfflineAudioCompletionEvent", PureGlobalIdentifierValue.other }, - .{ "Option", PureGlobalIdentifierValue.other }, - .{ "OscillatorNode", PureGlobalIdentifierValue.other }, - .{ "PageTransitionEvent", PureGlobalIdentifierValue.other }, - .{ "Path2D", PureGlobalIdentifierValue.other }, - .{ "Performance", PureGlobalIdentifierValue.other }, - .{ "PerformanceEntry", PureGlobalIdentifierValue.other }, - .{ "PerformanceMark", PureGlobalIdentifierValue.other }, - .{ "PerformanceMeasure", PureGlobalIdentifierValue.other }, - .{ "PerformanceNavigation", PureGlobalIdentifierValue.other }, - .{ "PerformanceObserver", PureGlobalIdentifierValue.other }, - .{ "PerformanceObserverEntryList", PureGlobalIdentifierValue.other }, - .{ "PerformanceResourceTiming", PureGlobalIdentifierValue.other }, - .{ "PerformanceTiming", PureGlobalIdentifierValue.other }, - .{ "PeriodicWave", PureGlobalIdentifierValue.other }, - .{ "Plugin", PureGlobalIdentifierValue.other }, - .{ "PluginArray", PureGlobalIdentifierValue.other }, - .{ "PointerEvent", PureGlobalIdentifierValue.other }, - .{ "PopStateEvent", PureGlobalIdentifierValue.other }, - .{ "ProcessingInstruction", PureGlobalIdentifierValue.other }, - .{ "ProgressEvent", PureGlobalIdentifierValue.other }, - .{ "PromiseRejectionEvent", PureGlobalIdentifierValue.other }, - .{ "RTCCertificate", PureGlobalIdentifierValue.other }, - .{ "RTCDTMFSender", PureGlobalIdentifierValue.other }, - .{ "RTCDTMFToneChangeEvent", PureGlobalIdentifierValue.other }, - .{ "RTCDataChannel", PureGlobalIdentifierValue.other }, - .{ "RTCDataChannelEvent", PureGlobalIdentifierValue.other }, - .{ "RTCIceCandidate", PureGlobalIdentifierValue.other }, - .{ "RTCPeerConnection", PureGlobalIdentifierValue.other }, - .{ "RTCPeerConnectionIceEvent", PureGlobalIdentifierValue.other }, - .{ "RTCRtpReceiver", PureGlobalIdentifierValue.other }, - .{ "RTCRtpSender", PureGlobalIdentifierValue.other }, - .{ "RTCRtpTransceiver", PureGlobalIdentifierValue.other }, - .{ "RTCSessionDescription", PureGlobalIdentifierValue.other }, - .{ "RTCStatsReport", PureGlobalIdentifierValue.other }, - .{ "RTCTrackEvent", PureGlobalIdentifierValue.other }, - .{ "RadioNodeList", PureGlobalIdentifierValue.other }, - .{ "Range", PureGlobalIdentifierValue.other }, - .{ "ReadableStream", PureGlobalIdentifierValue.other }, - .{ "Request", PureGlobalIdentifierValue.other }, - .{ "ResizeObserver", PureGlobalIdentifierValue.other }, - .{ "ResizeObserverEntry", PureGlobalIdentifierValue.other }, - .{ "Response", PureGlobalIdentifierValue.other }, - .{ "Screen", PureGlobalIdentifierValue.other }, - .{ "ScriptProcessorNode", PureGlobalIdentifierValue.other }, - .{ "SecurityPolicyViolationEvent", PureGlobalIdentifierValue.other }, - .{ "Selection", PureGlobalIdentifierValue.other }, - .{ "ShadowRoot", PureGlobalIdentifierValue.other }, - .{ "SourceBuffer", PureGlobalIdentifierValue.other }, - .{ "SourceBufferList", PureGlobalIdentifierValue.other }, - .{ "SpeechSynthesisEvent", PureGlobalIdentifierValue.other }, - .{ "SpeechSynthesisUtterance", PureGlobalIdentifierValue.other }, - .{ "StaticRange", PureGlobalIdentifierValue.other }, - .{ "Storage", PureGlobalIdentifierValue.other }, - .{ "StorageEvent", PureGlobalIdentifierValue.other }, - .{ "StyleSheet", PureGlobalIdentifierValue.other }, - .{ "StyleSheetList", PureGlobalIdentifierValue.other }, - .{ "Text", PureGlobalIdentifierValue.other }, - .{ "TextMetrics", PureGlobalIdentifierValue.other }, - .{ "TextTrack", PureGlobalIdentifierValue.other }, - .{ "TextTrackCue", PureGlobalIdentifierValue.other }, - .{ "TextTrackCueList", PureGlobalIdentifierValue.other }, - .{ "TextTrackList", PureGlobalIdentifierValue.other }, - .{ "TimeRanges", PureGlobalIdentifierValue.other }, - .{ "TrackEvent", PureGlobalIdentifierValue.other }, - .{ "TransitionEvent", PureGlobalIdentifierValue.other }, - .{ "TreeWalker", PureGlobalIdentifierValue.other }, - .{ "UIEvent", PureGlobalIdentifierValue.other }, - .{ "VTTCue", PureGlobalIdentifierValue.other }, - .{ "ValidityState", PureGlobalIdentifierValue.other }, - .{ "VisualViewport", PureGlobalIdentifierValue.other }, - .{ "WaveShaperNode", PureGlobalIdentifierValue.other }, - .{ "WebGLActiveInfo", PureGlobalIdentifierValue.other }, - .{ "WebGLBuffer", PureGlobalIdentifierValue.other }, - .{ "WebGLContextEvent", PureGlobalIdentifierValue.other }, - .{ "WebGLFramebuffer", PureGlobalIdentifierValue.other }, - .{ "WebGLProgram", PureGlobalIdentifierValue.other }, - .{ "WebGLQuery", PureGlobalIdentifierValue.other }, - .{ "WebGLRenderbuffer", PureGlobalIdentifierValue.other }, - .{ "WebGLRenderingContext", PureGlobalIdentifierValue.other }, - .{ "WebGLSampler", PureGlobalIdentifierValue.other }, - .{ "WebGLShader", PureGlobalIdentifierValue.other }, - .{ "WebGLShaderPrecisionFormat", PureGlobalIdentifierValue.other }, - .{ "WebGLSync", PureGlobalIdentifierValue.other }, - .{ "WebGLTexture", PureGlobalIdentifierValue.other }, - .{ "WebGLUniformLocation", PureGlobalIdentifierValue.other }, - .{ "WebKitCSSMatrix", PureGlobalIdentifierValue.other }, - .{ "WebSocket", PureGlobalIdentifierValue.other }, - .{ "WheelEvent", PureGlobalIdentifierValue.other }, - .{ "Window", PureGlobalIdentifierValue.other }, - .{ "Worker", PureGlobalIdentifierValue.other }, - .{ "XMLDocument", PureGlobalIdentifierValue.other }, - .{ "XMLHttpRequest", PureGlobalIdentifierValue.other }, - .{ "XMLHttpRequestEventTarget", PureGlobalIdentifierValue.other }, - .{ "XMLHttpRequestUpload", PureGlobalIdentifierValue.other }, - .{ "XMLSerializer", PureGlobalIdentifierValue.other }, - .{ "XPathEvaluator", PureGlobalIdentifierValue.other }, - .{ "XPathExpression", PureGlobalIdentifierValue.other }, - .{ "XPathResult", PureGlobalIdentifierValue.other }, - .{ "XSLTProcessor", PureGlobalIdentifierValue.other }, - .{ "alert", PureGlobalIdentifierValue.other }, - .{ "atob", PureGlobalIdentifierValue.other }, - .{ "blur", PureGlobalIdentifierValue.other }, - .{ "btoa", PureGlobalIdentifierValue.other }, - .{ "cancelAnimationFrame", PureGlobalIdentifierValue.other }, - .{ "captureEvents", PureGlobalIdentifierValue.other }, - .{ "close", PureGlobalIdentifierValue.other }, - .{ "closed", PureGlobalIdentifierValue.other }, - .{ "confirm", PureGlobalIdentifierValue.other }, - .{ "customElements", PureGlobalIdentifierValue.other }, - .{ "devicePixelRatio", PureGlobalIdentifierValue.other }, - .{ "document", PureGlobalIdentifierValue.other }, - .{ "event", PureGlobalIdentifierValue.other }, - .{ "fetch", PureGlobalIdentifierValue.other }, - .{ "find", PureGlobalIdentifierValue.other }, - .{ "focus", PureGlobalIdentifierValue.other }, - .{ "frameElement", PureGlobalIdentifierValue.other }, - .{ "frames", PureGlobalIdentifierValue.other }, - .{ "getComputedStyle", PureGlobalIdentifierValue.other }, - .{ "getSelection", PureGlobalIdentifierValue.other }, - .{ "history", PureGlobalIdentifierValue.other }, - .{ "indexedDB", PureGlobalIdentifierValue.other }, - .{ "isSecureContext", PureGlobalIdentifierValue.other }, - .{ "length", PureGlobalIdentifierValue.other }, - .{ "location", PureGlobalIdentifierValue.other }, - .{ "locationbar", PureGlobalIdentifierValue.other }, - .{ "matchMedia", PureGlobalIdentifierValue.other }, - .{ "menubar", PureGlobalIdentifierValue.other }, - .{ "moveBy", PureGlobalIdentifierValue.other }, - .{ "moveTo", PureGlobalIdentifierValue.other }, - .{ "name", PureGlobalIdentifierValue.other }, - .{ "navigator", PureGlobalIdentifierValue.other }, - .{ "onabort", PureGlobalIdentifierValue.other }, - .{ "onafterprint", PureGlobalIdentifierValue.other }, - .{ "onanimationend", PureGlobalIdentifierValue.other }, - .{ "onanimationiteration", PureGlobalIdentifierValue.other }, - .{ "onanimationstart", PureGlobalIdentifierValue.other }, - .{ "onbeforeprint", PureGlobalIdentifierValue.other }, - .{ "onbeforeunload", PureGlobalIdentifierValue.other }, - .{ "onblur", PureGlobalIdentifierValue.other }, - .{ "oncanplay", PureGlobalIdentifierValue.other }, - .{ "oncanplaythrough", PureGlobalIdentifierValue.other }, - .{ "onchange", PureGlobalIdentifierValue.other }, - .{ "onclick", PureGlobalIdentifierValue.other }, - .{ "oncontextmenu", PureGlobalIdentifierValue.other }, - .{ "oncuechange", PureGlobalIdentifierValue.other }, - .{ "ondblclick", PureGlobalIdentifierValue.other }, - .{ "ondrag", PureGlobalIdentifierValue.other }, - .{ "ondragend", PureGlobalIdentifierValue.other }, - .{ "ondragenter", PureGlobalIdentifierValue.other }, - .{ "ondragleave", PureGlobalIdentifierValue.other }, - .{ "ondragover", PureGlobalIdentifierValue.other }, - .{ "ondragstart", PureGlobalIdentifierValue.other }, - .{ "ondrop", PureGlobalIdentifierValue.other }, - .{ "ondurationchange", PureGlobalIdentifierValue.other }, - .{ "onemptied", PureGlobalIdentifierValue.other }, - .{ "onended", PureGlobalIdentifierValue.other }, - .{ "onerror", PureGlobalIdentifierValue.other }, - .{ "onfocus", PureGlobalIdentifierValue.other }, - .{ "ongotpointercapture", PureGlobalIdentifierValue.other }, - .{ "onhashchange", PureGlobalIdentifierValue.other }, - .{ "oninput", PureGlobalIdentifierValue.other }, - .{ "oninvalid", PureGlobalIdentifierValue.other }, - .{ "onkeydown", PureGlobalIdentifierValue.other }, - .{ "onkeypress", PureGlobalIdentifierValue.other }, - .{ "onkeyup", PureGlobalIdentifierValue.other }, - .{ "onlanguagechange", PureGlobalIdentifierValue.other }, - .{ "onload", PureGlobalIdentifierValue.other }, - .{ "onloadeddata", PureGlobalIdentifierValue.other }, - .{ "onloadedmetadata", PureGlobalIdentifierValue.other }, - .{ "onloadstart", PureGlobalIdentifierValue.other }, - .{ "onlostpointercapture", PureGlobalIdentifierValue.other }, - .{ "onmessage", PureGlobalIdentifierValue.other }, - .{ "onmousedown", PureGlobalIdentifierValue.other }, - .{ "onmouseenter", PureGlobalIdentifierValue.other }, - .{ "onmouseleave", PureGlobalIdentifierValue.other }, - .{ "onmousemove", PureGlobalIdentifierValue.other }, - .{ "onmouseout", PureGlobalIdentifierValue.other }, - .{ "onmouseover", PureGlobalIdentifierValue.other }, - .{ "onmouseup", PureGlobalIdentifierValue.other }, - .{ "onoffline", PureGlobalIdentifierValue.other }, - .{ "ononline", PureGlobalIdentifierValue.other }, - .{ "onpagehide", PureGlobalIdentifierValue.other }, - .{ "onpageshow", PureGlobalIdentifierValue.other }, - .{ "onpause", PureGlobalIdentifierValue.other }, - .{ "onplay", PureGlobalIdentifierValue.other }, - .{ "onplaying", PureGlobalIdentifierValue.other }, - .{ "onpointercancel", PureGlobalIdentifierValue.other }, - .{ "onpointerdown", PureGlobalIdentifierValue.other }, - .{ "onpointerenter", PureGlobalIdentifierValue.other }, - .{ "onpointerleave", PureGlobalIdentifierValue.other }, - .{ "onpointermove", PureGlobalIdentifierValue.other }, - .{ "onpointerout", PureGlobalIdentifierValue.other }, - .{ "onpointerover", PureGlobalIdentifierValue.other }, - .{ "onpointerup", PureGlobalIdentifierValue.other }, - .{ "onpopstate", PureGlobalIdentifierValue.other }, - .{ "onprogress", PureGlobalIdentifierValue.other }, - .{ "onratechange", PureGlobalIdentifierValue.other }, - .{ "onrejectionhandled", PureGlobalIdentifierValue.other }, - .{ "onreset", PureGlobalIdentifierValue.other }, - .{ "onresize", PureGlobalIdentifierValue.other }, - .{ "onscroll", PureGlobalIdentifierValue.other }, - .{ "onseeked", PureGlobalIdentifierValue.other }, - .{ "onseeking", PureGlobalIdentifierValue.other }, - .{ "onselect", PureGlobalIdentifierValue.other }, - .{ "onstalled", PureGlobalIdentifierValue.other }, - .{ "onstorage", PureGlobalIdentifierValue.other }, - .{ "onsubmit", PureGlobalIdentifierValue.other }, - .{ "onsuspend", PureGlobalIdentifierValue.other }, - .{ "ontimeupdate", PureGlobalIdentifierValue.other }, - .{ "ontoggle", PureGlobalIdentifierValue.other }, - .{ "ontransitioncancel", PureGlobalIdentifierValue.other }, - .{ "ontransitionend", PureGlobalIdentifierValue.other }, - .{ "ontransitionrun", PureGlobalIdentifierValue.other }, - .{ "ontransitionstart", PureGlobalIdentifierValue.other }, - .{ "onunhandledrejection", PureGlobalIdentifierValue.other }, - .{ "onunload", PureGlobalIdentifierValue.other }, - .{ "onvolumechange", PureGlobalIdentifierValue.other }, - .{ "onwaiting", PureGlobalIdentifierValue.other }, - .{ "onwebkitanimationend", PureGlobalIdentifierValue.other }, - .{ "onwebkitanimationiteration", PureGlobalIdentifierValue.other }, - .{ "onwebkitanimationstart", PureGlobalIdentifierValue.other }, - .{ "onwebkittransitionend", PureGlobalIdentifierValue.other }, - .{ "onwheel", PureGlobalIdentifierValue.other }, - .{ "open", PureGlobalIdentifierValue.other }, - .{ "opener", PureGlobalIdentifierValue.other }, - .{ "origin", PureGlobalIdentifierValue.other }, - .{ "outerHeight", PureGlobalIdentifierValue.other }, - .{ "outerWidth", PureGlobalIdentifierValue.other }, - .{ "parent", PureGlobalIdentifierValue.other }, - .{ "performance", PureGlobalIdentifierValue.other }, - .{ "personalbar", PureGlobalIdentifierValue.other }, - .{ "postMessage", PureGlobalIdentifierValue.other }, - .{ "print", PureGlobalIdentifierValue.other }, - .{ "prompt", PureGlobalIdentifierValue.other }, - .{ "releaseEvents", PureGlobalIdentifierValue.other }, - .{ "requestAnimationFrame", PureGlobalIdentifierValue.other }, - .{ "resizeBy", PureGlobalIdentifierValue.other }, - .{ "resizeTo", PureGlobalIdentifierValue.other }, - .{ "screen", PureGlobalIdentifierValue.other }, - .{ "screenLeft", PureGlobalIdentifierValue.other }, - .{ "screenTop", PureGlobalIdentifierValue.other }, - .{ "screenX", PureGlobalIdentifierValue.other }, - .{ "screenY", PureGlobalIdentifierValue.other }, - .{ "scroll", PureGlobalIdentifierValue.other }, - .{ "scrollBy", PureGlobalIdentifierValue.other }, - .{ "scrollTo", PureGlobalIdentifierValue.other }, - .{ "scrollbars", PureGlobalIdentifierValue.other }, - .{ "self", PureGlobalIdentifierValue.other }, - .{ "speechSynthesis", PureGlobalIdentifierValue.other }, - .{ "status", PureGlobalIdentifierValue.other }, - .{ "statusbar", PureGlobalIdentifierValue.other }, - .{ "stop", PureGlobalIdentifierValue.other }, - .{ "toolbar", PureGlobalIdentifierValue.other }, - .{ "top", PureGlobalIdentifierValue.other }, - .{ "webkitURL", PureGlobalIdentifierValue.other }, - .{ "window", PureGlobalIdentifierValue.other }, - .{ "crypto", PureGlobalIdentifierValue.other }, -}); - -const string = []const u8; - -const defines = @import("./defines.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const js_ast = bun.ast; diff --git a/src/bundler/defines.zig b/src/bundler/defines.zig deleted file mode 100644 index 9f8ac0e5cc1a..000000000000 --- a/src/bundler/defines.zig +++ /dev/null @@ -1,429 +0,0 @@ -const Globals = struct { - pub const Undefined = js_ast.E.Undefined{}; - pub const UndefinedPtr = &Globals.Undefined; - - pub const NaN = js_ast.E.Number{ .value = std.math.nan(f64) }; - pub const NanPtr = &Globals.NaN; - - pub const Infinity = js_ast.E.Number{ .value = std.math.inf(f64) }; - pub const InfinityPtr = &Globals.Infinity; - pub const UndefinedData = js_ast.Expr.Data{ .e_undefined = Globals.UndefinedPtr }; - pub const NaNData = js_ast.Expr.Data{ .e_number = Globals.NanPtr }; - pub const InfinityData = js_ast.Expr.Data{ .e_number = Globals.InfinityPtr }; -}; - -const defines_path = fs.Path.initWithNamespace("defines.json", "internal"); -pub const RawDefines = bun.StringArrayHashMap(string); -pub const UserDefines = bun.StringHashMap(DefineData); -pub const UserDefinesArray = bun.StringArrayHashMap(DefineData); - -pub const DefineData = struct { - value: js_ast.Expr.Data, - - // Not using a slice here shrinks the size from 48 bytes to 40 bytes. - original_name_ptr: ?[*]const u8 = null, - original_name_len: u32 = 0, - - flags: Flags = .{}, - - pub const Flags = packed struct(u8) { - _padding: u3 = 0, - - valueless: bool = false, - - can_be_removed_if_unused: bool = false, - - call_can_be_unwrapped_if_unused: js_ast.E.CallUnwrap = .never, - - method_call_must_be_replaced_with_undefined: bool = false, - }; - - pub const Options = struct { - original_name: ?[]const u8 = null, - value: js_ast.Expr.Data, - valueless: bool = false, - can_be_removed_if_unused: bool = false, - call_can_be_unwrapped_if_unused: js_ast.E.CallUnwrap = .never, - method_call_must_be_replaced_with_undefined: bool = false, - }; - - pub fn init(options: Options) DefineData { - return DefineData{ - .value = options.value, - .flags = .{ - .valueless = options.valueless, - .can_be_removed_if_unused = options.can_be_removed_if_unused, - .call_can_be_unwrapped_if_unused = options.call_can_be_unwrapped_if_unused, - .method_call_must_be_replaced_with_undefined = options.method_call_must_be_replaced_with_undefined, - }, - .original_name_ptr = if (options.original_name) |name| name.ptr else null, - .original_name_len = if (options.original_name) |name| @truncate(name.len) else 0, - }; - } - - pub inline fn original_name(self: *const DefineData) ?[]const u8 { - if (self.original_name_len > 0) { - return self.original_name_ptr.?[0..self.original_name_len]; - } - return null; - } - - /// True if accessing this value is known to not have any side effects. For - /// example, a bare reference to "Object.create" can be removed because it - /// does not have any observable side effects. - pub inline fn can_be_removed_if_unused(self: *const DefineData) bool { - return self.flags.can_be_removed_if_unused; - } - - /// True if a call to this value is known to not have any side effects. For - /// example, a bare call to "Object()" can be removed because it does not - /// have any observable side effects. - pub inline fn call_can_be_unwrapped_if_unused(self: *const DefineData) js_ast.E.CallUnwrap { - return self.flags.call_can_be_unwrapped_if_unused; - } - - pub inline fn method_call_must_be_replaced_with_undefined(self: *const DefineData) bool { - return self.flags.method_call_must_be_replaced_with_undefined; - } - - pub inline fn valueless(self: *const DefineData) bool { - return self.flags.valueless; - } - - pub fn initBoolean(value: bool) DefineData { - return .{ - .value = .{ .e_boolean = .{ .value = value } }, - .flags = .{ .can_be_removed_if_unused = true }, - }; - } - - pub fn initStaticString(str: *const js_ast.E.String) DefineData { - return .{ - .value = .{ .e_string = @constCast(str) }, - .flags = .{ .can_be_removed_if_unused = true }, - }; - } - - pub fn merge(a: DefineData, b: DefineData) DefineData { - return DefineData{ - .value = b.value, - .flags = .{ - .can_be_removed_if_unused = a.can_be_removed_if_unused(), - .call_can_be_unwrapped_if_unused = a.call_can_be_unwrapped_if_unused(), - - // TODO: investigate if this is correct. This is what it was before. But that looks strange. - .valueless = a.method_call_must_be_replaced_with_undefined() or b.method_call_must_be_replaced_with_undefined(), - - .method_call_must_be_replaced_with_undefined = a.method_call_must_be_replaced_with_undefined() or b.method_call_must_be_replaced_with_undefined(), - }, - .original_name_ptr = b.original_name_ptr, - .original_name_len = b.original_name_len, - }; - } - - pub fn fromMergeableInputEntry(user_defines: *UserDefines, key: []const u8, value_str: []const u8, value_is_undefined: bool, method_call_must_be_replaced_with_undefined_: bool, log: *logger.Log, allocator: std.mem.Allocator) !void { - user_defines.putAssumeCapacity(key, try .parse( - key, - value_str, - value_is_undefined, - method_call_must_be_replaced_with_undefined_, - log, - allocator, - )); - } - - pub fn parse( - key: []const u8, - value_str: []const u8, - value_is_undefined: bool, - method_call_must_be_replaced_with_undefined_: bool, - log: *logger.Log, - allocator: std.mem.Allocator, - ) !DefineData { - var keySplitter = std.mem.splitScalar(u8, key, '.'); - while (keySplitter.next()) |part| { - if (!js_lexer.isIdentifier(part)) { - if (strings.eql(part, key)) { - try log.addErrorFmt(null, logger.Loc{}, allocator, "define key \"{s}\" must be a valid identifier", .{key}); - } else { - try log.addErrorFmt(null, logger.Loc{}, allocator, "define key \"{s}\" contains invalid identifier \"{s}\"", .{ part, value_str }); - } - break; - } - } - - // check for nested identifiers - var valueSplitter = std.mem.splitScalar(u8, value_str, '.'); - var isIdent = true; - - while (valueSplitter.next()) |part| { - if (!js_lexer.isIdentifier(part) or js_lexer.Keywords.has(part)) { - isIdent = false; - break; - } - } - - if (isIdent) { - // Special-case undefined. it's not an identifier here - // https://github.com/evanw/esbuild/issues/1407 - const value = if (value_is_undefined or strings.eqlComptime(value_str, "undefined")) - js_ast.Expr.Data{ .e_undefined = js_ast.E.Undefined{} } - else - js_ast.Expr.Data{ .e_identifier = .{ - .ref = Ref.None, - .can_be_removed_if_unused = true, - } }; - - return .{ - .value = value, - .original_name_ptr = if (value_str.len > 0) value_str.ptr else null, - .original_name_len = @truncate(value_str.len), - .flags = .{ - .can_be_removed_if_unused = true, - .valueless = value_is_undefined, - .method_call_must_be_replaced_with_undefined = method_call_must_be_replaced_with_undefined_, - }, - }; - } - const _log = log; - const source = &logger.Source{ - .contents = value_str, - .path = defines_path, - }; - const expr = try json_parser.parseEnvJSON(source, _log, allocator); - const cloned = try expr.data.deepClone(allocator); - return .{ - .value = cloned, - .original_name_ptr = if (value_str.len > 0) value_str.ptr else null, - .original_name_len = @truncate(value_str.len), - .flags = .{ - .can_be_removed_if_unused = expr.isPrimitiveLiteral(), - .valueless = value_is_undefined, - .method_call_must_be_replaced_with_undefined = method_call_must_be_replaced_with_undefined_, - }, - }; - } - - pub fn fromInput(defines: RawDefines, drop: []const []const u8, log: *logger.Log, allocator: std.mem.Allocator) !UserDefines { - var user_defines = UserDefines.init(allocator); - var iterator = defines.iterator(); - try user_defines.ensureUnusedCapacity(@truncate(defines.count() + drop.len)); - while (iterator.next()) |entry| { - try fromMergeableInputEntry(&user_defines, entry.key_ptr.*, entry.value_ptr.*, false, false, log, allocator); - } - - for (drop) |drop_item| { - if (drop_item.len > 0) { - try fromMergeableInputEntry(&user_defines, drop_item, "", true, true, log, allocator); - } - } - - return user_defines; - } -}; - -fn arePartsEqual(a: []const string, b: []const string) bool { - if (a.len != b.len) { - return false; - } - for (0..a.len) |i| { - if (!strings.eql(a[i], b[i])) { - return false; - } - } - return true; -} - -pub const IdentifierDefine = DefineData; - -pub const DotDefine = struct { - parts: []const string, - data: DefineData, -}; - -// var nan_val = try allocator.create(js_ast.E.Number); -const nan_val = js_ast.E.Number{ .value = std.math.nan(f64) }; - -pub const Define = struct { - identifiers: bun.StringHashMap(IdentifierDefine), - dots: bun.StringHashMap([]DotDefine), - drop_debugger: bool, - allocator: std.mem.Allocator, - - pub const Data = DefineData; - - pub fn forIdentifier(this: *const Define, name: []const u8) ?*const IdentifierDefine { - if (this.identifiers.getPtr(name)) |data| { - return data; - } - - if (table.pure_global_identifier_map.get(name)) |id| { - return id.value(); - } - - return null; - } - - pub fn insertFromIterator(define: *Define, allocator: std.mem.Allocator, comptime Iterator: type, iter: Iterator) !void { - while (iter.next()) |user_define| { - try define.insert(allocator, user_define.key_ptr.*, user_define.value_ptr.*); - } - } - - pub fn insert(define: *Define, allocator: std.mem.Allocator, key: []const u8, value: DefineData) !void { - // If it has a dot, then it's a DotDefine. - // e.g. process.env.NODE_ENV - if (strings.lastIndexOfChar(key, '.')) |last_dot| { - const tail = key[last_dot + 1 .. key.len]; - const remainder = key[0..last_dot]; - const count = std.mem.count(u8, remainder, ".") + 1; - var parts = try allocator.alloc(string, count + 1); - var splitter = std.mem.splitScalar(u8, remainder, '.'); - var i: usize = 0; - while (splitter.next()) |split| : (i += 1) { - parts[i] = split; - } - parts[i] = tail; - var initial_values: []DotDefine = &([_]DotDefine{}); - - // "NODE_ENV" - const gpe_entry = try define.dots.getOrPut(tail); - - if (gpe_entry.found_existing) { - for (gpe_entry.value_ptr.*) |*part| { - // ["process", "env"] === ["process", "env"] (if that actually worked) - if (arePartsEqual(part.parts, parts)) { - part.data = part.data.merge(value); - return; - } - } - - initial_values = gpe_entry.value_ptr.*; - } - - var list = try std.array_list.Managed(DotDefine).initCapacity(allocator, initial_values.len + 1); - if (initial_values.len > 0) { - list.appendSliceAssumeCapacity(initial_values); - } - - list.appendAssumeCapacity(DotDefine{ - .data = value, - // TODO: do we need to allocate this? - .parts = parts, - }); - gpe_entry.value_ptr.* = try list.toOwnedSlice(); - } else { - // e.g. IS_BROWSER - try define.identifiers.put(key, value); - } - } - - fn insertGlobal(define: *Define, allocator: std.mem.Allocator, global: []const string, value_define: *const DefineData) !void { - const key = global[global.len - 1]; - const gpe = try define.dots.getOrPut(key); - if (gpe.found_existing) { - var list = try std.array_list.Managed(DotDefine).initCapacity(allocator, gpe.value_ptr.*.len + 1); - list.appendSliceAssumeCapacity(gpe.value_ptr.*); - list.appendAssumeCapacity(DotDefine{ - .parts = global[0..global.len], - .data = value_define.*, - }); - - define.allocator.free(gpe.value_ptr.*); - gpe.value_ptr.* = try list.toOwnedSlice(); - } else { - var list = try std.array_list.Managed(DotDefine).initCapacity(allocator, 1); - list.appendAssumeCapacity(DotDefine{ - .parts = global[0..global.len], - .data = value_define.*, - }); - - gpe.value_ptr.* = try list.toOwnedSlice(); - } - } - - pub fn init(allocator: std.mem.Allocator, _user_defines: ?UserDefines, string_defines: ?UserDefinesArray, drop_debugger: bool, omit_unused_global_calls: bool) bun.OOM!*@This() { - const define = try allocator.create(Define); - errdefer allocator.destroy(define); - define.* = .{ - .allocator = allocator, - .identifiers = bun.StringHashMap(IdentifierDefine).init(allocator), - .dots = bun.StringHashMap([]DotDefine).init(allocator), - .drop_debugger = drop_debugger, - }; - try define.dots.ensureTotalCapacity(124); - - const value_define = &DefineData{ - .value = .{ .e_undefined = .{} }, - .flags = .{ - .valueless = true, - .can_be_removed_if_unused = true, - }, - }; - // Step 1. Load the globals into the hash tables - for (global_no_side_effect_property_accesses) |global| { - try define.insertGlobal(allocator, global, value_define); - } - - const to_string_safe = &DefineData{ - .value = .{ .e_undefined = .{} }, - .flags = .{ - .valueless = true, - .can_be_removed_if_unused = true, - .call_can_be_unwrapped_if_unused = .if_unused_and_toString_safe, - }, - }; - - if (omit_unused_global_calls) { - for (global_no_side_effect_function_calls_safe_for_to_string) |global| { - try define.insertGlobal(allocator, global, to_string_safe); - } - } else { - for (global_no_side_effect_function_calls_safe_for_to_string) |global| { - try define.insertGlobal(allocator, global, value_define); - } - } - - // Step 3. Load user data into hash tables - // At this stage, user data has already been validated. - if (_user_defines) |user_defines| { - var iter = user_defines.iterator(); - try define.insertFromIterator(allocator, @TypeOf(&iter), &iter); - } - - // Step 4. Load environment data into hash tables. - // These are only strings. We do not parse them as JSON. - if (string_defines) |string_defines_| { - var iter = string_defines_.iterator(); - try define.insertFromIterator(allocator, @TypeOf(&iter), &iter); - } - - return define; - } - - pub fn deinit(this: *Define) void { - var diter = this.dots.valueIterator(); - while (diter.next()) |key| this.allocator.free(key.*); - this.dots.clearAndFree(); - this.identifiers.clearAndFree(); - this.allocator.destroy(this); - } -}; - -const string = []const u8; - -const fs = @import("../resolver/fs.zig"); -const std = @import("std"); - -const table = @import("./defines-table.zig"); -const global_no_side_effect_function_calls_safe_for_to_string = table.global_no_side_effect_function_calls_safe_for_to_string; -const global_no_side_effect_property_accesses = table.global_no_side_effect_property_accesses; - -const bun = @import("bun"); -const js_lexer = bun.js_lexer; -const json_parser = bun.json; -const logger = bun.logger; -const strings = bun.strings; - -const js_ast = bun.ast; -const Ref = bun.ast.Ref; diff --git a/src/bundler/entry_points.zig b/src/bundler/entry_points.zig deleted file mode 100644 index 4ec53eda5746..000000000000 --- a/src/bundler/entry_points.zig +++ /dev/null @@ -1,374 +0,0 @@ -pub const FallbackEntryPoint = struct { - code_buffer: [8192]u8 = undefined, - path_buffer: bun.PathBuffer = undefined, - source: logger.Source = undefined, - built_code: string = "", - - pub fn generate( - entry: *FallbackEntryPoint, - input_path: string, - comptime TranspilerType: type, - transpiler: *TranspilerType, - ) !void { - // This is *extremely* naive. - // The basic idea here is this: - // -- - // import * as EntryPoint from 'entry-point'; - // import boot from 'framework'; - // boot(EntryPoint); - // -- - // We go through the steps of printing the code -- only to then parse/transpile it because - // we want it to go through the linker and the rest of the transpilation process - - const disable_css_imports = transpiler.options.framework.?.client_css_in_js != .auto_onimportcss; - - var code: string = undefined; - - if (disable_css_imports) { - const fmt = - \\globalThis.Bun_disableCSSImports = true; - \\import boot from '{s}'; - \\boot(globalThis.__BUN_DATA__); - ; - - const args = .{ - input_path, - }; - - const count = std.fmt.count(fmt, args); - if (count < entry.code_buffer.len) { - code = try std.fmt.bufPrint(&entry.code_buffer, fmt, args); - } else { - code = try std.fmt.allocPrint(transpiler.allocator, fmt, args); - } - } else { - const fmt = - \\import boot from '{s}'; - \\boot(globalThis.__BUN_DATA__); - ; - - const args = .{ - input_path, - }; - - const count = std.fmt.count(fmt, args); - if (count < entry.code_buffer.len) { - code = try std.fmt.bufPrint(&entry.code_buffer, fmt, args); - } else { - code = try std.fmt.allocPrint(transpiler.allocator, fmt, args); - } - } - - entry.source = logger.Source.initPathString(input_path, code); - entry.source.path.namespace = "fallback-entry"; - } -}; - -pub const ClientEntryPoint = struct { - code_buffer: [8192]u8 = undefined, - path_buffer: bun.PathBuffer = undefined, - source: logger.Source = undefined, - - pub fn isEntryPointPath(extname: string) bool { - return strings.startsWith("entry.", extname); - } - - pub fn generateEntryPointPath(outbuffer: []u8, original_path: Fs.PathName) string { - var joined_base_and_dir_parts = [_]string{ original_path.dir, original_path.base }; - var generated_path = Fs.FileSystem.instance.absBuf(&joined_base_and_dir_parts, outbuffer); - - bun.copy(u8, outbuffer[generated_path.len..], ".entry"); - generated_path = outbuffer[0 .. generated_path.len + ".entry".len]; - bun.copy(u8, outbuffer[generated_path.len..], original_path.ext); - return outbuffer[0 .. generated_path.len + original_path.ext.len]; - } - - pub fn decodeEntryPointPath(outbuffer: []u8, original_path: Fs.PathName) string { - var joined_base_and_dir_parts = [_]string{ original_path.dir, original_path.base }; - const generated_path = Fs.FileSystem.instance.absBuf(&joined_base_and_dir_parts, outbuffer); - var original_ext = original_path.ext; - if (strings.indexOf(original_path.ext, "entry")) |entry_i| { - original_ext = original_path.ext[entry_i + "entry".len ..]; - } - - bun.copy(u8, outbuffer[generated_path.len..], original_ext); - - return outbuffer[0 .. generated_path.len + original_ext.len]; - } - - pub fn generate(entry: *ClientEntryPoint, comptime TranspilerType: type, transpiler: *TranspilerType, original_path: Fs.PathName, client: string) !void { - - // This is *extremely* naive. - // The basic idea here is this: - // -- - // import * as EntryPoint from 'entry-point'; - // import boot from 'framework'; - // boot(EntryPoint); - // -- - // We go through the steps of printing the code -- only to then parse/transpile it because - // we want it to go through the linker and the rest of the transpilation process - - const dir_to_use: string = original_path.dirWithTrailingSlash(); - const disable_css_imports = transpiler.options.framework.?.client_css_in_js != .auto_onimportcss; - - var code: string = undefined; - - if (disable_css_imports) { - code = try std.fmt.bufPrint( - &entry.code_buffer, - \\globalThis.Bun_disableCSSImports = true; - \\import boot from '{s}'; - \\import * as EntryPoint from '{s}{s}'; - \\boot(EntryPoint); - , - .{ - client, - dir_to_use, - original_path.filename, - }, - ); - } else { - code = try std.fmt.bufPrint( - &entry.code_buffer, - \\import boot from '{s}'; - \\if ('setLoaded' in boot) boot.setLoaded(loaded); - \\import * as EntryPoint from '{s}{s}'; - \\boot(EntryPoint); - , - .{ - client, - dir_to_use, - original_path.filename, - }, - ); - } - - entry.source = logger.Source.initPathString(generateEntryPointPath(&entry.path_buffer, original_path), code); - entry.source.path.namespace = "client-entry"; - } -}; - -pub const ServerEntryPoint = struct { - /// The generated wrapper source for `bun:main`. Always a valid slice - /// (either empty or owned by `bun.default_allocator`) so readers never - /// see `undefined` memory regardless of the `generated` flag's state. - contents: []const u8 = "", - generated: bool = false, - - pub fn deinit(entry: *ServerEntryPoint) void { - if (entry.contents.len > 0) { - bun.default_allocator.free(entry.contents); - } - entry.contents = ""; - entry.generated = false; - } - - pub fn generate( - entry: *ServerEntryPoint, - is_hot_reload_enabled: bool, - path_to_use: string, - ) !void { - // Use the global allocator so this buffer's lifetime is decoupled - // from whichever arena the caller's VM happens to be using; the - // slice is read later from `getHardcodedModule` which outlives any - // per-transpile arena. - const allocator = bun.default_allocator; - const code = brk: { - if (is_hot_reload_enabled) { - break :brk try std.fmt.allocPrint( - allocator, - \\// @bun - \\import * as start from '{f}'; - \\var hmrSymbol = Symbol("BunServerHMR"); - \\var entryNamespace = start; - \\function isServerConfig(def) {{ - \\ return def && def !== globalThis && (typeof def.fetch === 'function' || def.app != undefined) && typeof def.stop !== 'function'; - \\}} - \\if (typeof entryNamespace?.then === 'function') {{ - \\ entryNamespace = entryNamespace.then((entryNamespace) => {{ - \\ var def = entryNamespace?.default; - \\ if (isServerConfig(def)) {{ - \\ var server = globalThis[hmrSymbol]; - \\ if (server) {{ - \\ server.reload(def); - \\ console.debug(`Reloaded ${{server.development ? 'development ' : ''}}server: ${{server.protocol}}://${{server.hostname}}:${{server.port}}`); - \\ }} else {{ - \\ server = globalThis[hmrSymbol] = Bun.serve(def); - \\ console.debug(`Started ${{server.development ? 'development ' : ''}}server: ${{server.protocol}}://${{server.hostname}}:${{server.port}}`); - \\ }} - \\ }} - \\ }}, reportError); - \\}} else if (isServerConfig(entryNamespace?.default)) {{ - \\ var server = globalThis[hmrSymbol]; - \\ if (server) {{ - \\ server.reload(entryNamespace.default); - \\ console.debug(`Reloaded ${{server.development ? 'development ' : ''}}server: ${{server.protocol}}://${{server.hostname}}:${{server.port}}`); - \\ }} else {{ - \\ server = globalThis[hmrSymbol] = Bun.serve(entryNamespace.default); - \\ console.debug(`Started ${{server.development ? 'development ' : ''}}server: ${{server.protocol}}://${{server.hostname}}:${{server.port}}`); - \\ }} - \\}} - \\ - , - .{ - strings.formatEscapes(path_to_use, .{ .quote_char = '\'' }), - }, - ); - } - break :brk try std.fmt.allocPrint( - allocator, - \\// @bun - \\import * as start from "{f}"; - \\var entryNamespace = start; - \\function isServerConfig(def) {{ - \\ return def && def !== globalThis && (typeof def.fetch === 'function' || def.app != undefined) && typeof def.stop !== 'function'; - \\}} - \\if (typeof entryNamespace?.then === 'function') {{ - \\ entryNamespace = entryNamespace.then((entryNamespace) => {{ - \\ if (isServerConfig(entryNamespace?.default)) {{ - \\ const server = Bun.serve(entryNamespace.default); - \\ console.debug(`Started ${{server.development ? 'development ' : ''}}server: ${{server.protocol}}://${{server.hostname}}:${{server.port}}`); - \\ }} - \\ }}, reportError); - \\}} else if (isServerConfig(entryNamespace?.default)) {{ - \\ const server = Bun.serve(entryNamespace.default); - \\ console.debug(`Started ${{server.development ? 'development ' : ''}}server: ${{server.protocol}}://${{server.hostname}}:${{server.port}}`); - \\}} - \\ - , - .{ - strings.formatEscapes(path_to_use, .{ .quote_char = '"' }), - }, - ); - }; - - // Free the previous buffer on regenerate (hot reload) instead of - // leaking it. `contents` is either "" or a prior allocPrint result. - if (entry.contents.len > 0) { - allocator.free(entry.contents); - } - entry.contents = code; - entry.generated = true; - } -}; - -// This is not very fast. The idea is: we want to generate a unique entry point -// per macro function export that registers the macro Registering the macro -// happens in VirtualMachine We "register" it which just marks the JSValue as -// protected. This is mostly a workaround for being unable to call ESM exported -// functions from C++. When that is resolved, we should remove this. -pub const MacroEntryPoint = struct { - code_buffer: [bun.MAX_PATH_BYTES * 2 + 500]u8 = undefined, - output_code_buffer: [bun.MAX_PATH_BYTES * 8 + 500]u8 = undefined, - source: logger.Source = undefined, - - pub fn generateID(entry_path: string, function_name: string, buf: []u8, len: *u32) i32 { - var hasher = bun.Wyhash11.init(0); - hasher.update(js_ast.Macro.namespaceWithColon); - hasher.update(entry_path); - hasher.update(function_name); - const hash = hasher.final(); - const fmt = bun.fmt.hexIntLower(hash); - - const specifier = std.fmt.bufPrint(buf, js_ast.Macro.namespaceWithColon ++ "//{f}.js", .{fmt}) catch unreachable; - len.* = @as(u32, @truncate(specifier.len)); - - return generateIDFromSpecifier(specifier); - } - - pub fn generateIDFromSpecifier(specifier: string) i32 { - return @as(i32, @bitCast(@as(u32, @truncate(bun.hash(specifier))))); - } - - pub fn generate( - entry: *MacroEntryPoint, - _: *Transpiler, - import_path: Fs.PathName, - function_name: string, - macro_id: i32, - macro_label_: string, - ) !void { - const dir_to_use: string = if (import_path.dir.len == 0) "" else import_path.dirWithTrailingSlash(); - bun.copy(u8, &entry.code_buffer, macro_label_); - const macro_label = entry.code_buffer[0..macro_label_.len]; - - const code = brk: { - if (strings.eqlComptime(import_path.base, "bun")) { - break :brk try std.fmt.bufPrint( - entry.code_buffer[macro_label.len..], - \\//Auto-generated file - \\var Macros; - \\try {{ - \\ Macros = globalThis.Bun; - \\}} catch (err) {{ - \\ console.error("Error importing macro"); - \\ throw err; - \\}} - \\const macro = Macros['{s}']; - \\if (!macro) {{ - \\ throw new Error("Macro '{s}' not found in 'bun'"); - \\}} - \\ - \\Bun.registerMacro({d}, macro); - , - .{ - function_name, - function_name, - macro_id, - }, - ); - } - - break :brk try std.fmt.bufPrint( - entry.code_buffer[macro_label.len..], - \\//Auto-generated file - \\var Macros; - \\try {{ - \\ Macros = await import('{f}{f}'); - \\}} catch (err) {{ - \\ console.error("Error importing macro"); - \\ throw err; - \\}} - \\if (!('{s}' in Macros)) {{ - \\ throw new Error("Macro '{s}' not found in '{f}{f}'"); - \\}} - \\ - \\Bun.registerMacro({d}, Macros['{s}']); - , - .{ - bun.fmt.fmtPath(u8, dir_to_use, .{ - .escape_backslashes = true, - }), - bun.fmt.fmtPath(u8, import_path.filename, .{ - .escape_backslashes = true, - }), - function_name, - function_name, - bun.fmt.fmtPath(u8, dir_to_use, .{ - .escape_backslashes = true, - }), - bun.fmt.fmtPath(u8, import_path.filename, .{ - .escape_backslashes = true, - }), - macro_id, - function_name, - }, - ); - }; - - entry.source = logger.Source.initPathString(macro_label, code); - entry.source.path.text = macro_label; - entry.source.path.namespace = js_ast.Macro.namespace; - } -}; - -const string = []const u8; - -const Fs = @import("../resolver/fs.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const Transpiler = bun.Transpiler; -const js_ast = bun.ast; -const logger = bun.logger; -const strings = bun.strings; diff --git a/src/bundler/linker.zig b/src/bundler/linker.zig deleted file mode 100644 index 34c30af76450..000000000000 --- a/src/bundler/linker.zig +++ /dev/null @@ -1,421 +0,0 @@ -// This file is the old linker, used by Bun.Transpiler. - -pub const CSSResolveError = error{ResolveMessage}; - -pub const OnImportCallback = *const fn (resolve_result: *const Resolver.Result, import_record: *ImportRecord, origin: URL) void; - -pub const Linker = struct { - const HashedFileNameMap = std.AutoHashMap(u64, string); - const ThisLinker = @This(); - allocator: std.mem.Allocator, - options: *Options.BundleOptions, - fs: *Fs.FileSystem, - log: *logger.Log, - resolve_queue: *ResolveQueue, - resolver: *ResolverType, - resolve_results: *_transpiler.ResolveResults, - any_needs_runtime: bool = false, - runtime_import_record: ?ImportRecord = null, - hashed_filenames: HashedFileNameMap, - import_counter: usize = 0, - tagged_resolutions: TaggedResolution = TaggedResolution{}, - - plugin_runner: ?*PluginRunner = null, - - pub const runtime_source_path = "bun:wrap"; - - pub const TaggedResolution = struct { - react_refresh: ?Resolver.Result = null, - - // These tags cannot safely be used - // Projects may use different JSX runtimes across folders - // jsx_import: ?Resolver.Result = null, - // jsx_classic: ?Resolver.Result = null, - }; - - pub fn init( - allocator: std.mem.Allocator, - log: *logger.Log, - resolve_queue: *ResolveQueue, - options: *Options.BundleOptions, - resolver: *ResolverType, - resolve_results: *_transpiler.ResolveResults, - fs: *Fs.FileSystem, - ) ThisLinker { - relative_paths_list = ImportPathsList.init(allocator); - - return ThisLinker{ - .allocator = allocator, - .options = options, - .fs = fs, - .log = log, - .resolve_queue = resolve_queue, - .resolver = resolver, - .resolve_results = resolve_results, - .hashed_filenames = HashedFileNameMap.init(allocator), - }; - } - - pub fn getModKey( - this: *ThisLinker, - file_path: Fs.Path, - fd: ?FileDescriptorType, - ) !Fs.FileSystem.RealFS.ModKey { - var file: std.fs.File = if (fd) |_fd| _fd.stdFile() else try std.fs.cwd().openFile(file_path.text, .{ .mode = .read_only }); - Fs.FileSystem.setMaxFd(file.handle); - const modkey = try Fs.FileSystem.RealFS.ModKey.generate(&this.fs.fs, file_path.text, file); - - if (fd == null) - file.close(); - return modkey; - } - - pub fn getHashedFilename( - this: *ThisLinker, - file_path: Fs.Path, - fd: ?FileDescriptorType, - ) !string { - if (Transpiler.isCacheEnabled) { - const hashed = bun.hash(file_path.text); - const hashed_result = try this.hashed_filenames.getOrPut(hashed); - if (hashed_result.found_existing) { - return hashed_result.value_ptr.*; - } - } - - const modkey = try this.getModKey(file_path, fd); - const hash_name = modkey.hashName(file_path.text); - - if (Transpiler.isCacheEnabled) { - const hashed = bun.hash(file_path.text); - try this.hashed_filenames.put(hashed, try this.allocator.dupe(u8, hash_name)); - } - - return hash_name; - } - - // This modifies the Ast in-place! It resolves import records and generates paths. - pub fn link( - linker: *ThisLinker, - file_path: Fs.Path, - result: *_transpiler.ParseResult, - origin: URL, - comptime import_path_format: Options.BundleOptions.ImportPathFormat, - comptime ignore_runtime: bool, - comptime is_bun: bool, - ) !void { - const source_dir = file_path.sourceDir(); - var externals = std.array_list.Managed(u32).init(linker.allocator); - var had_resolve_errors = false; - - const is_deferred = result.pending_imports.len > 0; - - // Step 1. Resolve imports & requires - switch (result.loader) { - .jsx, .js, .ts, .tsx => { - for (result.ast.import_records.slice(), 0..) |*import_record, record_i| { - if (import_record.flags.is_unused or - (is_bun and is_deferred and !result.isPendingImport(@intCast(record_i)))) continue; - - const record_index = record_i; - if (comptime !ignore_runtime) { - if (strings.eqlComptime(import_record.path.namespace, "runtime")) { - if (import_path_format == .absolute_url) { - import_record.path = Fs.Path.initWithNamespace(try origin.joinAlloc(linker.allocator, "", "", "bun:wrap", "", ""), "bun"); - } else { - import_record.path = try linker.generateImportPath( - source_dir, - Linker.runtime_source_path, - false, - "bun", - origin, - import_path_format, - ); - } - - result.ast.runtime_import_record_id = @intCast(record_index); - result.ast.needs_runtime = true; - continue; - } - } - - if (comptime is_bun) { - if (jsc.ModuleLoader.HardcodedModule.Alias.get(import_record.path.text, linker.options.target, .{ .rewrite_jest_for_tests = linker.options.rewrite_jest_for_tests })) |replacement| { - if (replacement.tag == .builtin and import_record.kind.isCommonJS()) - continue; - import_record.path.text = replacement.path; - import_record.tag = replacement.tag; - import_record.flags.is_external_without_side_effects = true; - continue; - } - if (strings.startsWith(import_record.path.text, "node:")) { - // if a module is not found here, it is not found at all - // so we can just disable it - had_resolve_errors = try whenModuleNotFound(linker, import_record, result, is_bun); - - if (had_resolve_errors) return error.ResolveMessage; - continue; - } - - if (strings.hasPrefixComptime(import_record.path.text, "bun:")) { - import_record.path = Fs.Path.init(import_record.path.text["bun:".len..]); - import_record.path.namespace = "bun"; - - // don't link bun - continue; - } - - // Resolve dynamic imports lazily for perf - if (import_record.kind == .dynamic) { - continue; - } - } - - if (linker.plugin_runner) |runner| { - if (PluginRunner.couldBePlugin(import_record.path.text)) { - if (try runner.onResolve( - import_record.path.text, - file_path.text, - linker.log, - import_record.range.loc, - if (is_bun) - .bun - else if (linker.options.target == .browser) - .browser - else - .node, - )) |path| { - import_record.path = try linker.generateImportPath( - source_dir, - path.text, - false, - path.namespace, - origin, - import_path_format, - ); - import_record.flags.print_namespace_in_path = true; - continue; - } - } - } - } - }, - - else => {}, - } - if (had_resolve_errors) return error.ResolveMessage; - externals.clearAndFree(); - } - - fn whenModuleNotFound( - linker: *ThisLinker, - import_record: *ImportRecord, - result: *_transpiler.ParseResult, - comptime is_bun: bool, - ) !bool { - if (import_record.flags.handles_import_errors) { - import_record.path.is_disabled = true; - return false; - } - - if (comptime is_bun) { - // make these happen at runtime - if (import_record.kind == .require or import_record.kind == .require_resolve or import_record.kind == .dynamic) { - return false; - } - } - - if (import_record.path.text.len > 0 and Resolver.isPackagePath(import_record.path.text)) { - if (linker.options.target == .browser and Options.ExternalModules.isNodeBuiltin(import_record.path.text)) { - try linker.log.addResolveError( - &result.source, - import_record.range, - linker.allocator, - "Could not resolve: \"{s}\". Try setting --target=\"node\"", - .{import_record.path.text}, - import_record.kind, - error.ModuleNotFound, - ); - } else { - try linker.log.addResolveError( - &result.source, - import_record.range, - linker.allocator, - "Could not resolve: \"{s}\". Maybe you need to \"bun install\"?", - .{import_record.path.text}, - import_record.kind, - error.ModuleNotFound, - ); - } - } else { - try linker.log.addResolveError( - &result.source, - import_record.range, - linker.allocator, - "Could not resolve: \"{s}\"", - .{ - import_record.path.text, - }, - import_record.kind, - error.ModuleNotFound, - ); - } - return true; - } - - const ImportPathsList = allocators.BSSStringList(512, 128); - pub var relative_paths_list: *ImportPathsList = undefined; - - pub fn generateImportPath( - linker: *ThisLinker, - source_dir: string, - source_path: string, - use_hashed_name: bool, - namespace: string, - origin: URL, - comptime import_path_format: Options.BundleOptions.ImportPathFormat, - ) !Fs.Path { - switch (import_path_format) { - .absolute_path => { - if (strings.eqlComptime(namespace, "node")) { - return Fs.Path.initWithNamespace(source_path, "node"); - } - - if (strings.eqlComptime(namespace, "bun") or strings.eqlComptime(namespace, "file") or namespace.len == 0) { - const relative_name = linker.fs.relative(source_dir, source_path); - return Fs.Path.initWithPretty(source_path, relative_name); - } else { - return Fs.Path.initWithNamespace(source_path, namespace); - } - }, - .relative => { - var relative_name = linker.fs.relative(source_dir, source_path); - - var pretty: string = undefined; - if (use_hashed_name) { - var basepath = Fs.Path.init(source_path); - const basename = try linker.getHashedFilename(basepath, null); - const dir = basepath.name.dirWithTrailingSlash(); - var _pretty = try linker.allocator.alloc(u8, dir.len + basename.len + basepath.name.ext.len); - bun.copy(u8, _pretty, dir); - var remaining_pretty = _pretty[dir.len..]; - bun.copy(u8, remaining_pretty, basename); - remaining_pretty = remaining_pretty[basename.len..]; - bun.copy(u8, remaining_pretty, basepath.name.ext); - pretty = _pretty; - relative_name = try linker.allocator.dupe(u8, relative_name); - } else { - if (relative_name.len > 1 and !(relative_name[0] == std.fs.path.sep or relative_name[0] == '.')) { - pretty = try strings.concat(linker.allocator, &.{ "./", relative_name }); - } else { - pretty = try linker.allocator.dupe(u8, relative_name); - } - - relative_name = pretty; - } - - return Fs.Path.initWithPretty(pretty, relative_name); - }, - - .absolute_url => { - if (strings.eqlComptime(namespace, "node")) { - if (comptime Environment.isDebug) bun.assert(strings.eqlComptime(source_path[0..5], "node:")); - - return Fs.Path.init(try std.fmt.allocPrint( - linker.allocator, - // assumption: already starts with "node:" - "{s}/{s}", - .{ - strings.withoutTrailingSlash(origin.href), - strings.withoutLeadingSlash(source_path), - }, - )); - } else { - var absolute_pathname = Fs.PathName.init(source_path); - - if (!linker.options.preserve_extensions) { - if (linker.options.out_extensions.get(absolute_pathname.ext)) |ext| { - absolute_pathname.ext = ext; - } - } - - var base = linker.fs.relativeTo(source_path); - if (strings.lastIndexOfChar(base, '.')) |dot| { - base = base[0..dot]; - } - - const dirname = std.fs.path.dirname(base) orelse ""; - - var basename = std.fs.path.basename(base); - - if (use_hashed_name) { - const basepath = Fs.Path.init(source_path); - - basename = try linker.getHashedFilename(basepath, null); - } - - return Fs.Path.init(try origin.joinAlloc( - linker.allocator, - "", - dirname, - basename, - absolute_pathname.ext, - source_path, - )); - } - }, - - else => unreachable, - } - } - - pub fn resolveResultHashKey(linker: *ThisLinker, resolve_result: *const Resolver.Result) u64 { - const path = resolve_result.pathConst() orelse unreachable; - var hash_key = path.text; - - // Shorter hash key is faster to hash - if (strings.startsWith(path.text, linker.fs.top_level_dir)) { - hash_key = path.text[linker.fs.top_level_dir.len..]; - } - - return bun.hash(hash_key); - } - - pub fn enqueueResolveResult(linker: *ThisLinker, resolve_result: *const Resolver.Result) !bool { - const hash_key = linker.resolveResultHashKey(resolve_result); - - const get_or_put_entry = try linker.resolve_results.getOrPut(hash_key); - - if (!get_or_put_entry.found_existing) { - try linker.resolve_queue.writeItem(resolve_result.*); - } - - return !get_or_put_entry.found_existing; - } -}; - -const string = []const u8; - -const Fs = @import("../resolver/fs.zig"); -const Options = @import("./options.zig"); -const std = @import("std"); -const URL = @import("../url/url.zig").URL; - -const _import_record = @import("../options_types/import_record.zig"); -const ImportRecord = _import_record.ImportRecord; - -const Resolver = @import("../resolver/resolver.zig"); -const ResolverType = Resolver.Resolver; - -const bun = @import("bun"); -const Environment = bun.Environment; -const FileDescriptorType = bun.FD; -const allocators = bun.allocators; -const jsc = bun.jsc; -const logger = bun.logger; -const strings = bun.strings; - -const _transpiler = bun.transpiler; -const PluginRunner = bun.transpiler.PluginRunner; -const ResolveQueue = _transpiler.ResolveQueue; -const Transpiler = _transpiler.Transpiler; diff --git a/src/bundler/linker_context/MetafileBuilder.zig b/src/bundler/linker_context/MetafileBuilder.zig deleted file mode 100644 index 36ad57dc4571..000000000000 --- a/src/bundler/linker_context/MetafileBuilder.zig +++ /dev/null @@ -1,1085 +0,0 @@ -//! MetafileBuilder generates metafile JSON output compatible with esbuild's format. -//! -//! The metafile format is: -//! ```json -//! { -//! "inputs": { -//! "path/to/file.js": { -//! "bytes": 1234, -//! "imports": [ -//! { "path": "dependency.js", "kind": "import-statement" }, -//! { "path": "external", "kind": "require-call", "external": true } -//! ], -//! "format": "esm" -//! } -//! }, -//! "outputs": { -//! "path/to/output.js": { -//! "bytes": 5678, -//! "inputs": { -//! "path/to/file.js": { "bytesInOutput": 1200 } -//! }, -//! "imports": [ -//! { "path": "chunk.js", "kind": "import-statement" } -//! ], -//! "exports": ["default", "foo"], -//! "entryPoint": "path/to/file.js" -//! } -//! } -//! } -//! ``` -const MetafileBuilder = @This(); - -/// Generates the JSON fragment for a single output chunk. -/// Called during parallel chunk generation in postProcessJSChunk/postProcessCSSChunk. -/// The result is stored in chunk.metafile_chunk_json and assembled later. -pub fn generateChunkJson( - allocator: std.mem.Allocator, - c: *const LinkerContext, - chunk: *const Chunk, - chunks: []const Chunk, -) ![]const u8 { - var json = std.array_list.Managed(u8).init(allocator); - errdefer json.deinit(); - - const writer = json.writer(); - const sources = c.parse_graph.input_files.items(.source); - - // Start chunk entry: "path/to/output.js": { - try writeJSONString(writer, chunk.final_rel_path); - try writer.writeAll(": {"); - - // Write bytes - const chunk_bytes = chunk.intermediate_output.getSize(); - try writer.print("\n \"bytes\": {d}", .{chunk_bytes}); - - // Write inputs for this output (bytesInOutput is pre-computed during chunk generation) - try writer.writeAll(",\n \"inputs\": {"); - var first_chunk_input = true; - var chunk_iter = chunk.files_with_parts_in_chunk.iterator(); - while (chunk_iter.next()) |entry| { - const file_source_index = entry.key_ptr.*; - const bytes_in_output = entry.value_ptr.*; - if (file_source_index >= sources.len) continue; - if (file_source_index == Index.runtime.get()) continue; - - const file_source = &sources[file_source_index]; - if (file_source.path.text.len == 0) continue; - const file_path = file_source.path.pretty; - if (file_path.len == 0) continue; - - if (!first_chunk_input) { - try writer.writeAll(","); - } - first_chunk_input = false; - - try writer.writeAll("\n "); - try writeJSONString(writer, file_path); - try writer.print(": {{\n \"bytesInOutput\": {d}\n }}", .{bytes_in_output}); - } - try writer.writeAll("\n }"); - - // Write cross-chunk imports - try writer.writeAll(",\n \"imports\": ["); - var first_chunk_import = true; - for (chunk.cross_chunk_imports.slice()) |cross_import| { - // Bounds check to prevent OOB access from corrupted data - if (cross_import.chunk_index >= chunks.len) continue; - - if (!first_chunk_import) { - try writer.writeAll(","); - } - first_chunk_import = false; - - const imported_chunk = &chunks[cross_import.chunk_index]; - try writer.writeAll("\n {\n \"path\": "); - try writeJSONString(writer, imported_chunk.final_rel_path); - try writer.writeAll(",\n \"kind\": "); - try writeJSONString(writer, cross_import.import_kind.label()); - try writer.writeAll("\n }"); - } - try writer.writeAll("\n ]"); - - // Write exports and entry point if applicable - // Use sorted_and_filtered_export_aliases for deterministic output and to exclude internal exports - try writer.writeAll(",\n \"exports\": ["); - if (chunk.entry_point.is_entry_point) { - const entry_source_index = chunk.entry_point.source_index; - // Use sources.len as the authoritative bounds check - if (entry_source_index < sources.len) { - const sorted_exports = c.graph.meta.items(.sorted_and_filtered_export_aliases)[entry_source_index]; - var first_export = true; - for (sorted_exports) |alias| { - if (!first_export) { - try writer.writeAll(","); - } - first_export = false; - try writer.writeAll("\n "); - try writeJSONString(writer, alias); - } - if (!first_export) { - try writer.writeAll("\n "); - } - } - } - try writer.writeAll("]"); - - // Write entry point path - if (chunk.entry_point.is_entry_point) { - const entry_source_index = chunk.entry_point.source_index; - if (entry_source_index < sources.len) { - const entry_source = &sources[entry_source_index]; - if (entry_source.path.text.len > 0 and entry_source.path.pretty.len > 0) { - try writer.writeAll(",\n \"entryPoint\": "); - try writeJSONString(writer, entry_source.path.pretty); - } - } - } - - // Write cssBundle if this JS chunk has associated CSS - if (chunk.content == .javascript) { - const css_chunks = chunk.content.javascript.css_chunks; - if (css_chunks.len > 0) { - // Get the first CSS chunk path - const css_chunk_index = css_chunks[0]; - if (css_chunk_index < chunks.len) { - const css_chunk = &chunks[css_chunk_index]; - if (css_chunk.final_rel_path.len > 0) { - try writer.writeAll(",\n \"cssBundle\": "); - try writeJSONString(writer, css_chunk.final_rel_path); - } - } - } - } - - try writer.writeAll("\n }"); - - return json.toOwnedSlice(); -} - -/// Assembles the final metafile JSON from pre-built chunk fragments. -/// Called after all chunks have been generated in parallel. -/// Chunk references (unique_keys) are resolved to their final output paths. -/// The caller is responsible for freeing the returned slice. -pub fn generate( - allocator: std.mem.Allocator, - c: *LinkerContext, - chunks: []Chunk, -) ![]const u8 { - // Use StringJoiner so we can use breakOutputIntoPieces to resolve chunk references - var j = StringJoiner{ - .allocator = allocator, - }; - errdefer j.deinit(); - - j.pushStatic("{\n \"inputs\": {"); - - // Collect all input files that are reachable - var first_input = true; - const sources = c.parse_graph.input_files.items(.source); - const loaders = c.parse_graph.input_files.items(.loader); - const import_records_list = c.parse_graph.ast.items(.import_records); - - // Iterate through all files in chunks to collect unique source indices - var seen_sources = try std.DynamicBitSet.initEmpty(allocator, sources.len); - defer seen_sources.deinit(); - - // Mark all files that appear in chunks - for (chunks) |*chunk| { - var iter = chunk.files_with_parts_in_chunk.iterator(); - while (iter.next()) |entry| { - const source_index = entry.key_ptr.*; - if (source_index < sources.len) { - seen_sources.set(source_index); - } - } - } - - // Write inputs - var source_index: u32 = 0; - while (source_index < sources.len) : (source_index += 1) { - if (!seen_sources.isSet(source_index)) continue; - - // Skip runtime and other special files - if (source_index == Index.runtime.get()) continue; - - const source = &sources[source_index]; - if (source.path.text.len == 0) continue; - - const path = source.path.pretty; - if (path.len == 0) continue; - - if (!first_input) { - j.pushStatic(","); - } - first_input = false; - - j.pushStatic("\n "); - j.push(try std.fmt.allocPrint(allocator, "{f}", .{bun.fmt.formatJSONStringUTF8(path, .{})}), allocator); - j.push(try std.fmt.allocPrint(allocator, ": {{\n \"bytes\": {d}", .{source.contents.len}), allocator); - - // Write imports - j.pushStatic(",\n \"imports\": ["); - if (source_index < import_records_list.len) { - const import_records = import_records_list[source_index]; - var first_import = true; - for (import_records.slice()) |record| { - if (record.kind == .internal) continue; - - if (!first_import) { - j.pushStatic(","); - } - first_import = false; - - j.pushStatic("\n {\n \"path\": "); - // Write path with JSON escaping - chunk references (unique_keys) will be resolved - // by breakOutputIntoPieces and code() below - j.push(try std.fmt.allocPrint(allocator, "{f}", .{bun.fmt.formatJSONStringUTF8(record.path.text, .{})}), allocator); - j.pushStatic(",\n \"kind\": \""); - j.pushStatic(record.kind.label()); - j.pushStatic("\""); - - // Add "original" field if different from path - if (record.original_path.len > 0 and !std.mem.eql(u8, record.original_path, record.path.text)) { - j.pushStatic(",\n \"original\": "); - j.push(try std.fmt.allocPrint(allocator, "{f}", .{bun.fmt.formatJSONStringUTF8(record.original_path, .{})}), allocator); - } - - // Add "external": true for external imports - if (record.flags.is_external_without_side_effects or !record.source_index.isValid()) { - j.pushStatic(",\n \"external\": true"); - } - - // Add "with" for import attributes (json, toml, text loaders) - if (record.source_index.isValid() and record.source_index.get() < loaders.len) { - const loader = loaders[record.source_index.get()]; - const with_type: ?[]const u8 = switch (loader) { - .json => "json", - .toml => "toml", - .text => "text", - else => null, - }; - if (with_type) |wt| { - j.pushStatic(",\n \"with\": { \"type\": \""); - j.pushStatic(wt); - j.pushStatic("\" }"); - } - } - - j.pushStatic("\n }"); - } - } - j.pushStatic("\n ]"); - - // Write format based on exports_kind (esm vs cjs detection) - const loader = loaders[source_index]; - const format: ?[]const u8 = switch (loader) { - .js, .jsx, .ts, .tsx => blk: { - const exports_kind = c.graph.ast.items(.exports_kind); - if (source_index < exports_kind.len) { - break :blk switch (exports_kind[source_index]) { - .cjs, .esm_with_dynamic_fallback_from_cjs => "cjs", - .esm, .esm_with_dynamic_fallback => "esm", - .none => null, // Unknown format, don't emit - }; - } - break :blk null; - }, - .json => "json", - .css => "css", - else => null, - }; - if (format) |fmt| { - j.pushStatic(",\n \"format\": \""); - j.pushStatic(fmt); - j.pushStatic("\""); - } - - j.pushStatic("\n }"); - } - - j.pushStatic("\n },\n \"outputs\": {"); - - // Write outputs by joining pre-built chunk JSON fragments - var first_output = true; - for (chunks) |*chunk| { - if (chunk.final_rel_path.len == 0) continue; - - if (!first_output) { - j.pushStatic(","); - } - first_output = false; - - j.pushStatic("\n "); - j.pushStatic(chunk.metafile_chunk_json); - } - - j.pushStatic("\n }\n}\n"); - - // If no chunks, there are no chunk references to resolve, so just return the joined string - if (chunks.len == 0) { - return j.done(allocator); - } - - // Break output into pieces and resolve chunk references to final paths - var intermediate = try c.breakOutputIntoPieces(allocator, &j, @intCast(chunks.len)); - - // Get final output with all chunk references resolved - const code_result = try intermediate.code( - allocator, - c.parse_graph, - &c.graph, - "", // no import prefix for metafile - &chunks[0], // dummy chunk, not used for metafile - chunks, - null, // no display size - false, // not force absolute path - false, // no source map shifts - ); - - return code_result.buffer; -} - -fn writeJSONString(writer: anytype, str: []const u8) !void { - try writer.print("{f}", .{bun.fmt.formatJSONStringUTF8(str, .{})}); -} - -/// Generates a markdown visualization of the module graph from metafile JSON. -/// This is a post-processing step that parses the JSON and produces LLM-friendly output. -/// Designed to help diagnose bundle bloat, dependency chains, and entry point analysis. -/// The caller is responsible for freeing the returned slice. -pub fn generateMarkdown(allocator: std.mem.Allocator, metafile_json: []const u8) ![]const u8 { - const parsed = std.json.parseFromSlice(std.json.Value, allocator, metafile_json, .{}) catch { - return error.InvalidJSON; - }; - defer parsed.deinit(); - - const root = parsed.value; - if (root != .object) return error.InvalidJSON; - - var md = std.array_list.Managed(u8).init(allocator); - errdefer md.deinit(); - const writer = md.writer(); - - // Get inputs and outputs - const inputs = root.object.get("inputs") orelse return error.InvalidJSON; - const outputs = root.object.get("outputs") orelse return error.InvalidJSON; - - if (inputs != .object or outputs != .object) return error.InvalidJSON; - - // Header - try writer.writeAll("# Bundle Analysis Report\n\n"); - try writer.writeAll("This report helps identify bundle size issues, dependency bloat, and optimization opportunities.\n\n"); - - // Table of Contents for easy navigation - try writer.writeAll("## Table of Contents\n\n"); - try writer.writeAll("- [Quick Summary](#quick-summary)\n"); - try writer.writeAll("- [Largest Modules by Output Contribution](#largest-modules-by-output-contribution)\n"); - try writer.writeAll("- [Entry Point Analysis](#entry-point-analysis)\n"); - try writer.writeAll("- [Dependency Chains](#dependency-chains)\n"); - try writer.writeAll("- [Full Module Graph](#full-module-graph)\n"); - try writer.writeAll("- [Raw Data for Searching](#raw-data-for-searching)\n\n"); - try writer.writeAll("---\n\n"); - - // ==================== SUMMARY ==================== - try writer.writeAll("## Quick Summary\n\n"); - - var total_output_bytes: u64 = 0; - var esm_count: u32 = 0; - var cjs_count: u32 = 0; - var json_count: u32 = 0; - var external_count: u32 = 0; - var node_modules_count: u32 = 0; - var node_modules_bytes: u64 = 0; - - // Build a map of module path -> bytesInOutput (bytes contributed to output) - // This aggregates from all outputs since a module may appear in multiple chunks - var bytes_in_output = bun.StringHashMap(u64).init(allocator); - defer bytes_in_output.deinit(); - - // First pass through outputs to collect bytesInOutput for each module - var output_iter_first = outputs.object.iterator(); - while (output_iter_first.next()) |out_entry| { - const output = out_entry.value_ptr.*; - if (output != .object) continue; - - if (output.object.get("inputs")) |output_inputs| { - if (output_inputs == .object) { - var oi_iter = output_inputs.object.iterator(); - while (oi_iter.next()) |oi_entry| { - const module_path = oi_entry.key_ptr.*; - const module_info = oi_entry.value_ptr.*; - if (module_info == .object) { - if (module_info.object.get("bytesInOutput")) |bio| { - if (bio == .integer) { - const bytes_val: u64 = @intCast(bio.integer); - const gop = try bytes_in_output.getOrPut(module_path); - if (gop.found_existing) { - gop.value_ptr.* += bytes_val; - } else { - gop.value_ptr.* = bytes_val; - } - } - } - } - } - } - } - } - - // Build reverse dependency map: who imports each file? - // Also collect input file data for sorting - const InputFileInfo = struct { - path: []const u8, - bytes_in_output: u64, - import_count: u32, - is_node_modules: bool, - format: []const u8, - }; - - var input_files: std.ArrayListUnmanaged(InputFileInfo) = .{}; - defer input_files.deinit(allocator); - - var imported_by = bun.StringHashMap(std.ArrayListUnmanaged([]const u8)).init(allocator); - defer { - var it = imported_by.valueIterator(); - while (it.next()) |list| { - list.deinit(allocator); - } - imported_by.deinit(); - } - - // Second pass: collect all input file info and build reverse dependency map - var input_iter = inputs.object.iterator(); - while (input_iter.next()) |entry| { - const path = entry.key_ptr.*; - const input = entry.value_ptr.*; - if (input != .object) continue; - - const is_node_modules = std.mem.indexOf(u8, path, "node_modules") != null; - const module_bytes = bytes_in_output.get(path) orelse 0; - - var info = InputFileInfo{ - .path = path, - .bytes_in_output = module_bytes, - .import_count = 0, - .is_node_modules = is_node_modules, - .format = "", - }; - - if (is_node_modules) { - node_modules_bytes += module_bytes; - node_modules_count += 1; - } - - if (input.object.get("format")) |format| { - if (format == .string) { - info.format = format.string; - if (std.mem.eql(u8, format.string, "esm")) { - esm_count += 1; - } else if (std.mem.eql(u8, format.string, "cjs")) { - cjs_count += 1; - } else if (std.mem.eql(u8, format.string, "json")) { - json_count += 1; - } - } - } - - // Build reverse dependency map - if (input.object.get("imports")) |imps| { - if (imps == .array) { - info.import_count = @intCast(imps.array.items.len); - for (imps.array.items) |imp| { - if (imp == .object) { - if (imp.object.get("external")) |ext| { - if (ext == .bool and ext.bool) { - external_count += 1; - continue; - } - } - if (imp.object.get("path")) |imp_path| { - if (imp_path == .string) { - // Try to find the matching input key for this import - // The import path may be absolute while input keys are relative - // Or it may be a relative path like "../utils/logger.js" - const target = imp_path.string; - - // First, try exact match - var matched_key: ?[]const u8 = null; - if (inputs.object.contains(target)) { - matched_key = target; - } else { - // Try matching by basename or suffix - var key_iter = inputs.object.iterator(); - while (key_iter.next()) |key_entry| { - const input_key = key_entry.key_ptr.*; - // Check if target ends with the input key - if (std.mem.endsWith(u8, target, input_key)) { - // Make sure it's a path boundary (preceded by / or \ or start) - if (target.len == input_key.len or - (target.len > input_key.len and (target[target.len - input_key.len - 1] == '/' or target[target.len - input_key.len - 1] == '\\'))) - { - matched_key = input_key; - break; - } - } - // Also check if input_key ends with target (for relative paths) - // e.g., target="../utils/logger.js" might match "src/utils/logger.js" - if (std.mem.indexOf(u8, target, "..") != null) { - // This is a relative path, try matching just the filename parts - const target_base = std.fs.path.basename(target); - const key_base = std.fs.path.basename(input_key); - if (std.mem.eql(u8, target_base, key_base)) { - // Check if paths share common suffix - const target_without_dots = stripParentRefs(target); - if (std.mem.endsWith(u8, input_key, target_without_dots)) { - matched_key = input_key; - break; - } - } - } - } - } - - if (matched_key) |key| { - const gop = try imported_by.getOrPut(key); - if (!gop.found_existing) { - gop.value_ptr.* = .{}; - } - try gop.value_ptr.append(allocator, path); - } - } - } - } - } - } - } - - try input_files.append(allocator, info); - } - - // Count outputs and entry points - var entry_point_count: u32 = 0; - var chunk_count: u32 = 0; - var output_iter = outputs.object.iterator(); - while (output_iter.next()) |entry| { - if (entry.value_ptr.* == .object) { - if (entry.value_ptr.object.get("bytes")) |bytes| { - if (bytes == .integer) { - total_output_bytes += @intCast(bytes.integer); - } - } - if (entry.value_ptr.object.get("entryPoint")) |_| { - entry_point_count += 1; - } else { - chunk_count += 1; - } - } - } - - // Summary table - try writer.writeAll("| Metric | Value |\n"); - try writer.writeAll("|--------|-------|\n"); - try writer.print("| Total output size | {f} |\n", .{bun.fmt.size(total_output_bytes, .{})}); - try writer.print("| Input modules | {d} |\n", .{inputs.object.count()}); - if (entry_point_count > 0) { - try writer.print("| Entry points | {d} |\n", .{entry_point_count}); - } - if (chunk_count > 0) { - try writer.print("| Code-split chunks | {d} |\n", .{chunk_count}); - } - if (node_modules_count > 0) { - try writer.print("| node_modules contribution | {d} files ({f}) |\n", .{ node_modules_count, bun.fmt.size(node_modules_bytes, .{}) }); - } - if (esm_count > 0) try writer.print("| ESM modules | {d} |\n", .{esm_count}); - if (cjs_count > 0) try writer.print("| CommonJS modules | {d} |\n", .{cjs_count}); - if (json_count > 0) try writer.print("| JSON files | {d} |\n", .{json_count}); - if (external_count > 0) try writer.print("| External imports | {d} |\n", .{external_count}); - - // ==================== LARGEST MODULES (BLOAT ANALYSIS) ==================== - try writer.writeAll("\n## Largest Modules by Output Contribution\n\n"); - try writer.writeAll("Modules sorted by bytes contributed to the output bundle. Large modules may indicate bloat.\n\n"); - - // Sort by bytes_in_output descending - std.mem.sort(InputFileInfo, input_files.items, {}, struct { - fn lessThan(_: void, a: InputFileInfo, b: InputFileInfo) bool { - return a.bytes_in_output > b.bytes_in_output; - } - }.lessThan); - - try writer.writeAll("| Output Bytes | % of Total | Module | Format |\n"); - try writer.writeAll("|--------------|------------|--------|--------|\n"); - - const max_to_show: usize = 20; - for (input_files.items, 0..) |info, i| { - if (i >= max_to_show) break; - if (info.bytes_in_output == 0) break; // Skip modules with no output contribution - const pct = if (total_output_bytes > 0) - @as(f64, @floatFromInt(info.bytes_in_output)) / @as(f64, @floatFromInt(total_output_bytes)) * 100.0 - else - 0.0; - try writer.print("| {f} | {d:.1}% | `{s}` | {s} |\n", .{ - bun.fmt.size(info.bytes_in_output, .{}), - pct, - info.path, - if (info.format.len > 0) info.format else "-", - }); - } - - // Count remaining modules with non-zero contribution - var remaining_count: usize = 0; - if (input_files.items.len > max_to_show) { - for (input_files.items[max_to_show..]) |info| { - if (info.bytes_in_output > 0) remaining_count += 1; - } - } - if (remaining_count > 0) { - try writer.print("\n*...and {d} more modules with output contribution*\n", .{remaining_count}); - } - - // ==================== ENTRY POINT ANALYSIS ==================== - try writer.writeAll("\n## Entry Point Analysis\n\n"); - try writer.writeAll("Each entry point and the total code it loads (including shared chunks).\n\n"); - - var out_iter2 = outputs.object.iterator(); - while (out_iter2.next()) |entry| { - const output_path = entry.key_ptr.*; - const output = entry.value_ptr.*; - if (output != .object) continue; - - const entry_point = output.object.get("entryPoint") orelse continue; - if (entry_point != .string) continue; - - try writer.print("### Entry: `{s}`\n\n", .{entry_point.string}); - - // Output file info - try writer.print("**Output file**: `{s}`\n", .{output_path}); - - if (output.object.get("bytes")) |bytes| { - if (bytes == .integer) { - try writer.print("**Bundle size**: {f}\n", .{bun.fmt.size(@as(u64, @intCast(bytes.integer)), .{})}); - } - } - - // CSS bundle - if (output.object.get("cssBundle")) |css_bundle| { - if (css_bundle == .string) { - try writer.print("**CSS bundle**: `{s}`\n", .{css_bundle.string}); - } - } - - // Exports - if (output.object.get("exports")) |exports| { - if (exports == .array and exports.array.items.len > 0) { - try writer.writeAll("**Exports**: "); - var first = true; - const max_exports: usize = 10; - for (exports.array.items, 0..) |exp, i| { - if (i >= max_exports) { - try writer.print(" ...+{d} more", .{exports.array.items.len - max_exports}); - break; - } - if (exp == .string) { - if (!first) try writer.writeAll(", "); - first = false; - try writer.print("`{s}`", .{exp.string}); - } - } - try writer.writeAll("\n"); - } - } - - // Chunk dependencies - if (output.object.get("imports")) |chunk_imports| { - if (chunk_imports == .array and chunk_imports.array.items.len > 0) { - try writer.writeAll("\n**Loads these chunks** (code-splitting):\n"); - for (chunk_imports.array.items) |imp| { - if (imp == .object) { - const path = imp.object.get("path") orelse continue; - const kind = imp.object.get("kind") orelse continue; - if (path == .string and kind == .string) { - // Try to get chunk size - if (outputs.object.get(path.string)) |chunk| { - if (chunk == .object) { - if (chunk.object.get("bytes")) |bytes| { - if (bytes == .integer) { - try writer.print("- `{s}` ({f}, {s})\n", .{ - path.string, - bun.fmt.size(@as(u64, @intCast(bytes.integer)), .{}), - kind.string, - }); - continue; - } - } - } - } - try writer.print("- `{s}` ({s})\n", .{ path.string, kind.string }); - } - } - } - } - } - - // Modules bundled into this entry - if (output.object.get("inputs")) |output_inputs| { - if (output_inputs == .object and output_inputs.object.count() > 0) { - try writer.writeAll("\n**Bundled modules** (sorted by contribution):\n\n"); - try writer.writeAll("| Bytes | Module |\n"); - try writer.writeAll("|-------|--------|\n"); - - // Collect and sort by size - const ModuleSize = struct { path: []const u8, bytes: u64 }; - var module_sizes: std.ArrayListUnmanaged(ModuleSize) = .{}; - defer module_sizes.deinit(allocator); - - var oi_iter = output_inputs.object.iterator(); - while (oi_iter.next()) |oi_entry| { - const module_path = oi_entry.key_ptr.*; - const module_info = oi_entry.value_ptr.*; - if (module_info == .object) { - if (module_info.object.get("bytesInOutput")) |bio| { - if (bio == .integer) { - try module_sizes.append(allocator, .{ .path = module_path, .bytes = @intCast(bio.integer) }); - } - } - } - } - - std.mem.sort(ModuleSize, module_sizes.items, {}, struct { - fn lessThan(_: void, a: ModuleSize, b: ModuleSize) bool { - return a.bytes > b.bytes; - } - }.lessThan); - - const max_modules: usize = 15; - for (module_sizes.items, 0..) |ms, i| { - if (i >= max_modules) break; - try writer.print("| {f} | `{s}` |\n", .{ bun.fmt.size(ms.bytes, .{}), ms.path }); - } - if (module_sizes.items.len > max_modules) { - try writer.print("\n*...and {d} more modules*\n", .{module_sizes.items.len - max_modules}); - } - } - } - - try writer.writeAll("\n"); - } - - // ==================== DEPENDENCY CHAINS (WHY IS THIS INCLUDED?) ==================== - try writer.writeAll("## Dependency Chains\n\n"); - try writer.writeAll("For each module, shows what files import it. Use this to understand why a module is included.\n\n"); - - // Show modules that are imported by many files (potential optimization targets) - const ImportedByInfo = struct { path: []const u8, count: usize }; - var highly_imported: std.ArrayListUnmanaged(ImportedByInfo) = .{}; - defer highly_imported.deinit(allocator); - - var ib_iter = imported_by.iterator(); - while (ib_iter.next()) |entry| { - try highly_imported.append(allocator, .{ .path = entry.key_ptr.*, .count = entry.value_ptr.items.len }); - } - - std.mem.sort(ImportedByInfo, highly_imported.items, {}, struct { - fn lessThan(_: void, a: ImportedByInfo, b: ImportedByInfo) bool { - return a.count > b.count; - } - }.lessThan); - - // Show most commonly imported modules - if (highly_imported.items.len > 0) { - try writer.writeAll("### Most Commonly Imported Modules\n\n"); - try writer.writeAll("Modules imported by many files. Extracting these to shared chunks may help.\n\n"); - try writer.writeAll("| Import Count | Module | Imported By |\n"); - try writer.writeAll("|--------------|--------|-------------|\n"); - - const max_common: usize = 15; - for (highly_imported.items, 0..) |hi, i| { - if (i >= max_common) break; - if (hi.count < 2) break; // Only show if imported by 2+ files - - try writer.print("| {d} | `{s}` | ", .{ hi.count, hi.path }); - - // Show first few importers - if (imported_by.get(hi.path)) |importers| { - const max_importers: usize = 3; - for (importers.items, 0..) |importer, j| { - if (j >= max_importers) { - try writer.print("+{d} more", .{importers.items.len - max_importers}); - break; - } - if (j > 0) try writer.writeAll(", "); - try writer.print("`{s}`", .{importer}); - } - } - try writer.writeAll(" |\n"); - } - } - - // ==================== FULL MODULE GRAPH ==================== - try writer.writeAll("\n## Full Module Graph\n\n"); - try writer.writeAll("Complete dependency information for each module.\n\n"); - - // Sort inputs alphabetically for easier navigation - const PathOnly = struct { path: []const u8 }; - var sorted_paths: std.ArrayListUnmanaged(PathOnly) = .{}; - defer sorted_paths.deinit(allocator); - - var path_iter = inputs.object.iterator(); - while (path_iter.next()) |entry| { - try sorted_paths.append(allocator, .{ .path = entry.key_ptr.* }); - } - - std.mem.sort(PathOnly, sorted_paths.items, {}, struct { - fn lessThan(_: void, a: PathOnly, b: PathOnly) bool { - return std.mem.lessThan(u8, a.path, b.path); - } - }.lessThan); - - for (sorted_paths.items) |sp| { - const input_path = sp.path; - const input = inputs.object.get(input_path) orelse continue; - if (input != .object) continue; - - try writer.print("### `{s}`\n\n", .{input_path}); - - // Show bytes contributed to output - if (bytes_in_output.get(input_path)) |contrib| { - if (contrib > 0) { - try writer.print("- **Output contribution**: {f}\n", .{bun.fmt.size(contrib, .{})}); - } - } - - if (input.object.get("format")) |format| { - if (format == .string) { - try writer.print("- **Format**: {s}\n", .{format.string}); - } - } - - // Who imports this file? - if (imported_by.get(input_path)) |importers| { - try writer.print("- **Imported by** ({d} files):", .{importers.items.len}); - if (importers.items.len <= 5) { - for (importers.items) |importer| { - try writer.print(" `{s}`", .{importer}); - } - } else { - for (importers.items[0..5]) |importer| { - try writer.print(" `{s}`", .{importer}); - } - try writer.print(" +{d} more", .{importers.items.len - 5}); - } - try writer.writeAll("\n"); - } else { - // This is likely an entry point - try writer.writeAll("- **Imported by**: (entry point or orphan)\n"); - } - - // What does this file import? - if (input.object.get("imports")) |imps| { - if (imps == .array and imps.array.items.len > 0) { - try writer.writeAll("- **Imports**:\n"); - for (imps.array.items) |imp| { - if (imp == .object) { - const path = imp.object.get("path") orelse continue; - const kind = imp.object.get("kind") orelse continue; - if (path != .string or kind != .string) continue; - - const is_external = blk: { - if (imp.object.get("external")) |ext| { - if (ext == .bool) break :blk ext.bool; - } - break :blk false; - }; - - const original = blk: { - if (imp.object.get("original")) |orig| { - if (orig == .string) break :blk orig.string; - } - break :blk null; - }; - - // Get output contribution of imported file if available - const imported_contrib: ?u64 = if (!is_external) bytes_in_output.get(path.string) else null; - - if (is_external) { - if (original) |orig| { - try writer.print(" - `{s}` ({s}, **external**, specifier: `{s}`)\n", .{ path.string, kind.string, orig }); - } else { - try writer.print(" - `{s}` ({s}, **external**)\n", .{ path.string, kind.string }); - } - } else if (imported_contrib) |contrib| { - if (contrib > 0) { - if (original) |orig| { - try writer.print(" - `{s}` ({s}, contributes {f}, specifier: `{s}`)\n", .{ path.string, kind.string, bun.fmt.size(contrib, .{}), orig }); - } else { - try writer.print(" - `{s}` ({s}, contributes {f})\n", .{ path.string, kind.string, bun.fmt.size(contrib, .{}) }); - } - } else { - if (original) |orig| { - try writer.print(" - `{s}` ({s}, specifier: `{s}`)\n", .{ path.string, kind.string, orig }); - } else { - try writer.print(" - `{s}` ({s})\n", .{ path.string, kind.string }); - } - } - } else { - if (original) |orig| { - try writer.print(" - `{s}` ({s}, specifier: `{s}`)\n", .{ path.string, kind.string, orig }); - } else { - try writer.print(" - `{s}` ({s})\n", .{ path.string, kind.string }); - } - } - - // Show import attributes if present - if (imp.object.get("with")) |with| { - if (with == .object) { - if (with.object.get("type")) |type_val| { - if (type_val == .string) { - try writer.print(" - with type: `{s}`\n", .{type_val.string}); - } - } - } - } - } - } - } - } - - try writer.writeAll("\n"); - } - - // ==================== RAW DATA FOR SEARCHING ==================== - try writer.writeAll("## Raw Data for Searching\n\n"); - try writer.writeAll("This section contains raw, grep-friendly data. Use these patterns:\n"); - try writer.writeAll("- `[MODULE:` - Find all modules\n"); - try writer.writeAll("- `[OUTPUT_BYTES:` - Find output contribution for each module\n"); - try writer.writeAll("- `[IMPORT:` - Find all import relationships\n"); - try writer.writeAll("- `[IMPORTED_BY:` - Find reverse dependencies\n"); - try writer.writeAll("- `[ENTRY:` - Find entry points\n"); - try writer.writeAll("- `[EXTERNAL:` - Find external imports\n"); - try writer.writeAll("- `[NODE_MODULES:` - Find node_modules files\n\n"); - - // All modules with output contribution - try writer.writeAll("### All Modules\n\n"); - try writer.writeAll("```\n"); - for (input_files.items) |info| { - try writer.print("[MODULE: {s}]\n", .{info.path}); - if (info.bytes_in_output > 0) { - try writer.print("[OUTPUT_BYTES: {s} = {d} bytes]\n", .{ info.path, info.bytes_in_output }); - } - if (info.format.len > 0) { - try writer.print("[FORMAT: {s} = {s}]\n", .{ info.path, info.format }); - } - if (info.is_node_modules) { - try writer.print("[NODE_MODULES: {s}]\n", .{info.path}); - } - } - try writer.writeAll("```\n\n"); - - // All import relationships - try writer.writeAll("### All Imports\n\n"); - try writer.writeAll("```\n"); - var import_iter2 = inputs.object.iterator(); - while (import_iter2.next()) |entry| { - const source_path = entry.key_ptr.*; - const input2 = entry.value_ptr.*; - if (input2 != .object) continue; - - if (input2.object.get("imports")) |imps| { - if (imps == .array) { - for (imps.array.items) |imp| { - if (imp == .object) { - const is_ext = blk: { - if (imp.object.get("external")) |ext| { - if (ext == .bool) break :blk ext.bool; - } - break :blk false; - }; - - if (imp.object.get("path")) |imp_path| { - if (imp_path == .string) { - if (is_ext) { - try writer.print("[EXTERNAL: {s} imports {s}]\n", .{ source_path, imp_path.string }); - } else { - try writer.print("[IMPORT: {s} -> {s}]\n", .{ source_path, imp_path.string }); - } - } - } - } - } - } - } - } - try writer.writeAll("```\n\n"); - - // All reverse dependencies (imported by) - try writer.writeAll("### Reverse Dependencies (Imported By)\n\n"); - try writer.writeAll("```\n"); - var ib_iter2 = imported_by.iterator(); - while (ib_iter2.next()) |entry| { - const target = entry.key_ptr.*; - for (entry.value_ptr.items) |importer| { - try writer.print("[IMPORTED_BY: {s} <- {s}]\n", .{ target, importer }); - } - } - try writer.writeAll("```\n\n"); - - // Entry points - try writer.writeAll("### Entry Points\n\n"); - try writer.writeAll("```\n"); - var out_iter3 = outputs.object.iterator(); - while (out_iter3.next()) |entry| { - const output_path2 = entry.key_ptr.*; - const output2 = entry.value_ptr.*; - if (output2 != .object) continue; - - if (output2.object.get("entryPoint")) |ep| { - if (ep == .string) { - var size: u64 = 0; - if (output2.object.get("bytes")) |bytes| { - if (bytes == .integer) { - size = @intCast(bytes.integer); - } - } - try writer.print("[ENTRY: {s} -> {s} ({d} bytes)]\n", .{ ep.string, output_path2, size }); - } - } - } - try writer.writeAll("```\n\n"); - - // node_modules summary - if (node_modules_count > 0) { - try writer.writeAll("### node_modules Summary\n\n"); - try writer.writeAll("```\n"); - for (input_files.items) |info| { - if (info.is_node_modules and info.bytes_in_output > 0) { - try writer.print("[NODE_MODULES: {s} (contributes {d} bytes)]\n", .{ info.path, info.bytes_in_output }); - } - } - try writer.writeAll("```\n"); - } - - return md.toOwnedSlice(); -} - -/// Strips leading "../" sequences from a relative path. -/// e.g., "../utils/logger.js" -> "utils/logger.js" -fn stripParentRefs(path: []const u8) []const u8 { - var result = path; - while (result.len >= 3 and std.mem.startsWith(u8, result, "../")) { - result = result[3..]; - } - // Also handle ./ prefix - while (result.len >= 2 and std.mem.startsWith(u8, result, "./")) { - result = result[2..]; - } - return result; -} - -const std = @import("std"); - -const bun = @import("bun"); -const StringJoiner = bun.StringJoiner; - -const Chunk = bun.bundle_v2.Chunk; -const Index = bun.bundle_v2.Index; -const LinkerContext = bun.bundle_v2.LinkerContext; diff --git a/src/bundler/linker_context/OutputFileListBuilder.zig b/src/bundler/linker_context/OutputFileListBuilder.zig deleted file mode 100644 index 83f7cd3fa998..000000000000 --- a/src/bundler/linker_context/OutputFileListBuilder.zig +++ /dev/null @@ -1,150 +0,0 @@ -//! Q: What does this struct do? -//! A: This struct segments the `OutputFile` list into 3 separate spaces so -//! chunk indexing remains the same: -//! -//! 1. chunks -//! 2. sourcemaps, bytecode, and module_info -//! 3. additional output files -//! -//! We can calculate the space ahead of time and avoid having to do something -//! more complicated or which requires extra work. -//! -//! Q: Why does it need to do that? -//! A: We would like it so if we have a chunk index, we can also index its -//! corresponding output file in the output file list. -//! -//! The DevServer uses the `referenced_css_chunks` (a list of chunk indices) -//! field on `OutputFile` to know which CSS files to hand to the rendering -//! function. For React this just adds tags that point to each output CSS -//! file. -//! -//! However, we previously were pushing sourcemaps and bytecode output files -//! to the output file list directly after their corresponding chunk, meaning -//! the index of the chunk in the chunk list and its corresponding -//! `OutputFile` in the output file list got scrambled. -//! -//! If we maintain the property that `outputIndexForChunk(chunk[i]) == i` -//! then we don't need to do any allocations or extra work to get the output -//! file for a chunk. -pub const OutputFileList = @This(); - -output_files: std.array_list.Managed(options.OutputFile), -index_for_chunk: u32, -index_for_sourcemaps_and_bytecode: ?u32, -additional_output_files_start: u32, - -total_insertions: u32, - -pub fn init( - allocator: std.mem.Allocator, - c: *const bun.bundle_v2.LinkerContext, - chunks: []const bun.bundle_v2.Chunk, - _: usize, -) !@This() { - const length, const supplementary_file_count = OutputFileList.calculateOutputFileListCapacity(c, chunks); - var output_files = try std.array_list.Managed(options.OutputFile).initCapacity( - allocator, - length, - ); - output_files.appendNTimesAssumeCapacity(OutputFile.zero_value, length); - - return .{ - .output_files = output_files, - .index_for_chunk = 0, - .index_for_sourcemaps_and_bytecode = if (supplementary_file_count == 0) null else @as(u32, @truncate(chunks.len)), - .additional_output_files_start = @as(u32, @intCast(chunks.len)) + supplementary_file_count, - .total_insertions = 0, - }; -} - -pub fn take(this: *@This()) std.array_list.Managed(options.OutputFile) { - // TODO: should this return an error - bun.assertf(this.total_insertions == this.output_files.items.len, "total_insertions ({d}) != output_files.items.len ({d})", .{ this.total_insertions, this.output_files.items.len }); - // Set the length just in case so the list doesn't have undefined memory - this.output_files.items.len = this.total_insertions; - const list = this.output_files; - this.output_files = std.array_list.Managed(options.OutputFile).init(bun.default_allocator); - return list; -} - -pub fn calculateOutputFileListCapacity(c: *const bun.bundle_v2.LinkerContext, chunks: []const bun.bundle_v2.Chunk) struct { u32, u32 } { - const source_map_count = if (c.options.source_maps.hasExternalFiles()) brk: { - var count: usize = 0; - for (chunks) |*chunk| { - if (chunk.content.sourcemap(c.options.source_maps).hasExternalFiles()) { - count += 1; - } - } - break :brk count; - } else 0; - const bytecode_count = if (c.options.generate_bytecode_cache) bytecode_count: { - var bytecode_count: usize = 0; - for (chunks) |*chunk| { - const loader: bun.options.Loader = if (chunk.entry_point.is_entry_point) - c.parse_graph.input_files.items(.loader)[ - chunk.entry_point.source_index - ] - else - .js; - - if (chunk.content == .javascript and loader.isJavaScriptLike()) { - bytecode_count += 1; - } - } - break :bytecode_count bytecode_count; - } else 0; - - // module_info is generated for ESM bytecode in --compile builds - const module_info_count = if (c.options.generate_bytecode_cache and c.options.output_format == .esm and c.options.compile) bytecode_count else 0; - - const additional_output_files_count = if (c.options.compile_to_standalone_html) 0 else c.parse_graph.additional_output_files.items.len; - return .{ @intCast(chunks.len + source_map_count + bytecode_count + module_info_count + additional_output_files_count), @intCast(source_map_count + bytecode_count + module_info_count) }; -} - -pub fn insertForChunk(this: *OutputFileList, output_file: options.OutputFile) u32 { - const index = this.indexForChunk(); - bun.assertf(index < this.index_for_sourcemaps_and_bytecode orelse std.math.maxInt(u32), "index ({d}) \\< index_for_sourcemaps_and_bytecode ({d})", .{ index, this.index_for_sourcemaps_and_bytecode orelse std.math.maxInt(u32) }); - this.output_files.items[index] = output_file; - this.total_insertions += 1; - return index; -} - -pub fn insertForSourcemapOrBytecode(this: *OutputFileList, output_file: options.OutputFile) !u32 { - const index = this.indexForSourcemapOrBytecode() orelse return error.NoSourceMapsOrBytecode; - bun.assertf(index < this.additional_output_files_start, "index ({d}) \\< additional_output_files_start ({d})", .{ index, this.additional_output_files_start }); - this.output_files.items[index] = output_file; - this.total_insertions += 1; - return index; -} - -pub fn insertAdditionalOutputFiles(this: *OutputFileList, additional_output_files: []const options.OutputFile) void { - bun.assertf(this.index_for_sourcemaps_and_bytecode orelse 0 <= this.additional_output_files_start, "index_for_sourcemaps_and_bytecode ({d}) \\< additional_output_files_start ({d})", .{ this.index_for_sourcemaps_and_bytecode orelse 0, this.additional_output_files_start }); - bun.copy( - options.OutputFile, - this.getMutableAdditionalOutputFiles(), - additional_output_files, - ); - this.total_insertions += @as(u32, @intCast(additional_output_files.len)); -} - -pub fn getMutableAdditionalOutputFiles(this: *OutputFileList) []options.OutputFile { - return this.output_files.items[this.additional_output_files_start..]; -} - -fn indexForChunk(this: *@This()) u32 { - const result = this.index_for_chunk; - this.index_for_chunk += 1; - return result; -} - -fn indexForSourcemapOrBytecode(this: *@This()) ?u32 { - const result = this.index_for_sourcemaps_and_bytecode orelse return null; - this.index_for_sourcemaps_and_bytecode.? += 1; - return result; -} - -const bun = @import("bun"); -const std = @import("std"); - -const options = bun.options; -const OutputFile = options.OutputFile; diff --git a/src/bundler/linker_context/README.md b/src/bundler/linker_context/README.md index 61ef4b000879..da861fb27860 100644 --- a/src/bundler/linker_context/README.md +++ b/src/bundler/linker_context/README.md @@ -12,7 +12,7 @@ The LinkerContext operates in several main phases: ## Main Functions -### 1. `load()` - LinkerContext.zig:187 +### 1. `load()` - LinkerContext.rs:187 **Purpose**: Initializes the LinkerContext with bundle data and prepares the graph for linking. @@ -32,7 +32,7 @@ The LinkerContext operates in several main phases: - Entry point processing - Memory management setup -### 2. `link()` - LinkerContext.zig:294 +### 2. `link()` - LinkerContext.rs:294 **Purpose**: The main linking orchestrator that coordinates all bundling phases. @@ -53,7 +53,7 @@ The LinkerContext operates in several main phases: - Memory corruption checks (in debug builds) - Returns the final chunk array -### 3. `generateChunksInParallel()` - generateChunksInParallel.zig:1 +### 3. `generateChunksInParallel()` - generateChunksInParallel.rs:1 **Purpose**: Generates the final output files from chunks using parallel processing. @@ -80,7 +80,7 @@ The LinkerContext operates in several main phases: ### Core Analysis Phase -#### `scanImportsAndExports.zig` +#### `scanImportsAndExports.rs` **Purpose**: Analyzes all import/export relationships across the module graph, determining module compatibility, resolving dependencies, and setting up the foundation for code generation. This is the critical first phase of linking that establishes how modules will interact in the final bundle. @@ -448,7 +448,7 @@ if (targetModule.needsWrapper) { This function is the foundation of Bun's module compatibility system, ensuring that mixed ES6/CommonJS codebases work correctly while enabling optimal bundling strategies. -#### `doStep5.zig` +#### `doStep5.rs` **Purpose**: Creates namespace exports for every file. @@ -461,7 +461,7 @@ This function is the foundation of Bun's module compatibility system, ensuring t ### Optimization Phase -#### `renameSymbolsInChunk.zig` +#### `renameSymbolsInChunk.rs` **Purpose**: Performs symbol renaming within individual chunks to eliminate naming conflicts, enable minification, and ensure proper scoping isolation. This function is critical for generating final output code where variables can be safely renamed without breaking references. @@ -485,17 +485,20 @@ This function is the foundation of Bun's module compatibility system, ensuring t **Why the Ref System Exists**: Bun's `Ref` struct solves the parallel parsing problem that occurs when processing thousands of files simultaneously: -```zig -pub const Ref = packed struct(u64) { - inner_index: u31, // Symbol index within the source file - tag: enum(u2) { // Type of reference (symbol, invalid, etc.) - invalid, - allocated_name, - source_contents_slice, - symbol, - }, - source_index: u31, // Index of the source file containing the symbol +```rust +// Single packed u64: inner_index | tag | source_index +#[repr(C, packed(4))] +pub struct Ref(u64); + +pub enum RefTag { + Invalid = 0, + AllocatedName = 1, + SourceContentsSlice = 2, + Symbol = 3, } +// ref.inner_index() -> symbol index within the source file +// ref.tag() -> RefTag +// ref.source_index() -> index of the source file containing the symbol ``` **Core Algorithm**: The function operates by analyzing all symbols within a chunk, computing reserved names that cannot be used, and then applying either minification-based renaming (for optimized builds) or number-based renaming (for readable builds). @@ -533,11 +536,11 @@ _What happens_: _StableRef structure_: -```zig +```rust // Enables deterministic cross-chunk symbol ordering -StableRef { - stable_source_index: u32, // Consistent index across builds - ref: Ref, // Original symbol reference +pub struct StableRef { + pub stable_source_index: IndexInt, // Consistent index across builds + pub r#ref: Ref, // Original symbol reference } ``` @@ -675,20 +678,20 @@ if (development) { _Essential Ref methods used throughout_: -- `ref.isValid()` - returns `this.tag != .invalid` -- `ref.sourceIndex()` - returns which file the symbol originated from -- `ref.innerIndex()` - returns the symbol's index within that file -- `ref.getSymbol(symbol_table)` - retrieves the actual symbol data +- `ref.is_valid()` - returns `self.tag() != RefTag::Invalid` +- `ref.source_index()` - returns which file the symbol originated from +- `ref.inner_index()` - returns the symbol's index within that file +- `ref.get_symbol(symbol_table)` - retrieves the actual symbol data _Symbol table organization_: -```zig +```rust // Two-dimensional array structure enables fast parallel merging symbol_table[source_index][inner_index] = Symbol { original_name: "myVariable", link: renamed_symbol_ref, // Points to final renamed version // ... other symbol data -} +}; ``` **Error Handling and Edge Cases**: @@ -717,7 +720,7 @@ The renamed symbols are then used during final code generation to produce output ### Chunk Computation Phase -#### `computeChunks.zig` +#### `computeChunks.rs` **Purpose**: Determines the final chunk structure based on entry points and code splitting. @@ -729,7 +732,7 @@ The renamed symbols are then used during final code generation to produce output - Manages HTML chunk creation - Assigns unique keys and templates to chunks -#### `computeCrossChunkDependencies.zig` +#### `computeCrossChunkDependencies.rs` **Purpose**: Resolves dependencies between different chunks. @@ -740,7 +743,7 @@ The renamed symbols are then used during final code generation to produce output - Handles dynamic imports across chunks - Manages chunk metadata for dependency resolution -#### `findAllImportedPartsInJSOrder.zig` +#### `findAllImportedPartsInJSOrder.rs` **Purpose**: Determines the order of parts within JavaScript chunks. @@ -751,7 +754,7 @@ The renamed symbols are then used during final code generation to produce output - Manages import precedence - Ensures proper evaluation order -#### `findImportedCSSFilesInJSOrder.zig` +#### `findImportedCSSFilesInJSOrder.rs` **Purpose**: Determines CSS file ordering for JavaScript chunks that import CSS. @@ -761,7 +764,7 @@ The renamed symbols are then used during final code generation to produce output - Handles CSS dependency resolution - Manages CSS-in-JS import patterns -#### `findImportedFilesInCSSOrder.zig` +#### `findImportedFilesInCSSOrder.rs` **Purpose**: Determines the import order for CSS files. @@ -773,7 +776,7 @@ The renamed symbols are then used during final code generation to produce output ### Code Generation Phase -#### `generateCodeForFileInChunkJS.zig` +#### `generateCodeForFileInChunkJS.rs` **Purpose**: Generates JavaScript code for a specific file within a chunk. @@ -784,7 +787,7 @@ The renamed symbols are then used during final code generation to produce output - Manages HMR (Hot Module Replacement) code generation - Processes wrapper functions and runtime calls -#### `generateCompileResultForJSChunk.zig` +#### `generateCompileResultForJSChunk.rs` **Purpose**: Worker function that generates compile results for JavaScript chunks in parallel. @@ -795,7 +798,7 @@ The renamed symbols are then used during final code generation to produce output - Error handling in parallel context - Integration with thread pool -#### `generateCompileResultForCssChunk.zig` +#### `generateCompileResultForCssChunk.rs` **Purpose**: Worker function that generates compile results for CSS chunks in parallel. @@ -806,7 +809,7 @@ The renamed symbols are then used during final code generation to produce output - CSS import processing - Thread-safe CSS compilation -#### `generateCompileResultForHtmlChunk.zig` +#### `generateCompileResultForHtmlChunk.rs` **Purpose**: Worker function that generates compile results for HTML chunks. @@ -817,7 +820,7 @@ The renamed symbols are then used during final code generation to produce output - HTML minification - Script/stylesheet injection -#### `generateCodeForLazyExport.zig` +#### `generateCodeForLazyExport.rs` **Purpose**: Generates code for expression-style loaders that defer code generation until linking. @@ -865,7 +868,7 @@ The function resolves `composes` relationships by visiting the referenced classe ### Statement Processing -#### `convertStmtsForChunk.zig` +#### `convertStmtsForChunk.rs` **Purpose**: Converts and transforms AST statements for final inclusion in output chunks, handling the critical process of adapting module-level statements for different output formats and wrapper contexts. @@ -998,7 +1001,7 @@ var init_demo = __esm(() => { This function is essential for maintaining JavaScript module semantics across different output formats while enabling optimal bundling strategies. -#### `convertStmtsForChunkForDevServer.zig` +#### `convertStmtsForChunkForDevServer.rs` **Purpose**: Special statement conversion for development server (HMR). @@ -1010,7 +1013,7 @@ This function is essential for maintaining JavaScript module semantics across di ### Post-Processing Phase -#### `prepareCssAstsForChunk.zig` +#### `prepareCssAstsForChunk.rs` **Purpose**: Prepares CSS ASTs before final processing. @@ -1020,7 +1023,7 @@ This function is essential for maintaining JavaScript module semantics across di - CSS optimization passes - Asset reference resolution -#### `postProcessJSChunk.zig` +#### `postProcessJSChunk.rs` **Purpose**: Final processing of JavaScript chunks after code generation. @@ -1031,7 +1034,7 @@ This function is essential for maintaining JavaScript module semantics across di - Source map integration - Output formatting -#### `postProcessCSSChunk.zig` +#### `postProcessCSSChunk.rs` **Purpose**: Final processing of CSS chunks. @@ -1042,7 +1045,7 @@ This function is essential for maintaining JavaScript module semantics across di - CSS minification - Source map generation -#### `postProcessHTMLChunk.zig` +#### `postProcessHTMLChunk.rs` **Purpose**: Final processing of HTML chunks. @@ -1055,7 +1058,7 @@ This function is essential for maintaining JavaScript module semantics across di ### Output Phase -#### `writeOutputFilesToDisk.zig` +#### `writeOutputFilesToDisk.rs` **Purpose**: Writes all generated chunks and assets to the filesystem. diff --git a/src/bundler/linker_context/StaticRouteVisitor.zig b/src/bundler/linker_context/StaticRouteVisitor.zig deleted file mode 100644 index ba06fb00efc8..000000000000 --- a/src/bundler/linker_context/StaticRouteVisitor.zig +++ /dev/null @@ -1,93 +0,0 @@ -//! The `isFullyStatic(source_index)` function returns whether or not -//! `source_index` imports a file with `"use client"`. -//! -//! TODO: Could we move this into the ReachableFileVisitor inside `bundle_v2.zig`? - -const StaticRouteVisitor = @This(); - -c: *LinkerContext, -cache: std.AutoArrayHashMapUnmanaged(Index.Int, bool) = .{}, -visited: bun.bit_set.AutoBitSet, - -pub fn deinit(this: *StaticRouteVisitor) void { - this.cache.deinit(bun.default_allocator); - this.visited.deinit(bun.default_allocator); -} - -/// This the quickest, simplest, dumbest way I can think of doing this. -/// Investigate performance. It can have false negatives (it doesn't properly -/// handle cycles), but that's okay as it's just used an optimization -pub fn hasTransitiveUseClient(this: *StaticRouteVisitor, entry_point_source_index: u32) bool { - if (bun.Environment.isDebug and bun.env_var.BUN_SSG_DISABLE_STATIC_ROUTE_VISITOR.get()) { - return false; - } - - const all_import_records: []const ImportRecord.List = this.c.parse_graph.ast.items(.import_records); - const referenced_source_indices: []const u32 = this.c.parse_graph.server_component_boundaries.list.items(.reference_source_index); - const use_directives: []const UseDirective = this.c.parse_graph.server_component_boundaries.list.items(.use_directive); - - return this.hasTransitiveUseClientImpl( - all_import_records, - referenced_source_indices, - use_directives, - Index.init(entry_point_source_index), - ); -} - -/// 1. Get AST for `source_index` -/// 2. Recursively traverse its imports in import records -/// 3. If any of the imports match any item in -/// `referenced_source_indices` which has `use_directive == -/// .client`, then we know `source_index` is NOT fully -/// static. -fn hasTransitiveUseClientImpl( - this: *StaticRouteVisitor, - all_import_records: []const ImportRecord.List, - referenced_source_indices: []const u32, - use_directives: []const UseDirective, - source_index: Index, -) bool { - if (this.cache.get(source_index.get())) |result| { - return result; - } - if (this.visited.isSet(source_index.get())) { - return false; - } - this.visited.set(source_index.get()); - - const import_records = all_import_records[source_index.get()]; - - const result = result: { - for (import_records.sliceConst()) |*import_record| { - if (!import_record.source_index.isValid()) continue; - - // check if this import is a client boundary - for (referenced_source_indices, use_directives) |referenced_source_index, use_directive| { - if (use_directive != .client) continue; - // it's a client boundary - if (referenced_source_index == import_record.source_index.get()) break :result true; - } - - // otherwise check its children - if (this.hasTransitiveUseClientImpl( - all_import_records, - referenced_source_indices, - use_directives, - import_record.source_index, - )) break :result true; - } - break :result false; - }; - - this.cache.put(bun.default_allocator, source_index.get(), result) catch unreachable; - - return result; -} - -const bun = @import("bun"); -const std = @import("std"); - -const ImportRecord = bun.bundle_v2.ImportRecord; -const Index = bun.bundle_v2.Index; -const LinkerContext = bun.bundle_v2.LinkerContext; -const UseDirective = bun.bundle_v2.UseDirective; diff --git a/src/bundler/linker_context/computeChunks.zig b/src/bundler/linker_context/computeChunks.zig deleted file mode 100644 index 0dbb9ab7d88a..000000000000 --- a/src/bundler/linker_context/computeChunks.zig +++ /dev/null @@ -1,503 +0,0 @@ -pub noinline fn computeChunks( - this: *LinkerContext, - unique_key: u64, -) ![]Chunk { - const trace = bun.perf.trace("Bundler.computeChunks"); - defer trace.end(); - - bun.assert(this.dev_server == null); // use - - var stack_fallback = std.heap.stackFallback(4096, this.allocator()); - const stack_all = stack_fallback.get(); - var arena = bun.ArenaAllocator.init(stack_all); - defer arena.deinit(); - - var temp_allocator = arena.allocator(); - var js_chunks = bun.StringArrayHashMap(Chunk).init(temp_allocator); - try js_chunks.ensureUnusedCapacity(this.graph.entry_points.len); - - // Key is the hash of the CSS order. This deduplicates identical CSS files. - var css_chunks = std.AutoArrayHashMap(u64, Chunk).init(temp_allocator); - var js_chunks_with_css: usize = 0; - - // Maps entry point IDs to their index in js_chunks.values(). - // CSS-only entry points that skip JS chunk creation get maxInt as sentinel. - const entry_point_to_js_chunk_idx = try temp_allocator.alloc(u32, this.graph.entry_points.len); - @memset(entry_point_to_js_chunk_idx, std.math.maxInt(u32)); - - const entry_source_indices = this.graph.entry_points.items(.source_index); - const css_asts = this.graph.ast.items(.css); - var html_chunks = bun.StringArrayHashMap(Chunk).init(temp_allocator); - const loaders = this.parse_graph.input_files.items(.loader); - const ast_targets = this.graph.ast.items(.target); - - const code_splitting = this.graph.code_splitting; - const could_be_browser_target_from_server_build = this.options.target.isServerSide() and this.parse_graph.html_imports.html_source_indices.len > 0; - const has_server_html_imports = this.parse_graph.html_imports.server_source_indices.len > 0; - - // Create chunks for entry points - for (entry_source_indices, 0..) |source_index, entry_id_| { - const entry_bit = @as(Chunk.EntryPoint.ID, @truncate(entry_id_)); - - var entry_bits = &this.graph.files.items(.entry_bits)[source_index]; - entry_bits.set(entry_bit); - - const has_html_chunk = loaders[source_index] == .html; - - // For code splitting, entry point chunks should be keyed by ONLY the entry point's - // own bit, not the full entry_bits. This ensures that if an entry point file is - // reachable from other entry points (e.g., via re-exports), its content goes into - // a shared chunk rather than staying in the entry point's chunk. - // https://github.com/evanw/esbuild/blob/cd832972927f1f67b6d2cc895c06a8759c1cf309/internal/linker/linker.go#L3882 - var entry_point_chunk_bits = try AutoBitSet.initEmpty(this.allocator(), this.graph.entry_points.len); - entry_point_chunk_bits.set(entry_bit); - - const js_chunk_key = brk: { - if (code_splitting) { - break :brk try temp_allocator.dupe(u8, entry_point_chunk_bits.bytes(this.graph.entry_points.len)); - } else { - // Force HTML chunks to always be generated, even if there's an identical JS file. - break :brk try std.fmt.allocPrint(temp_allocator, "{f}", .{JSChunkKeyFormatter{ - .has_html = has_html_chunk, - .entry_bits = entry_bits.bytes(this.graph.entry_points.len), - }}); - } - }; - - // Put this early on in this loop so that CSS-only entry points work. - if (has_html_chunk) { - const html_chunk_entry = try html_chunks.getOrPut(js_chunk_key); - if (!html_chunk_entry.found_existing) { - html_chunk_entry.value_ptr.* = .{ - .entry_point = .{ - .entry_point_id = entry_bit, - .source_index = source_index, - .is_entry_point = true, - }, - .entry_bits = entry_point_chunk_bits, - .content = .html, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - .flags = .{ .is_browser_chunk_from_server_build = could_be_browser_target_from_server_build and ast_targets[source_index] == .browser }, - }; - } - } - - if (css_asts[source_index] != null) { - const order = this.findImportedFilesInCSSOrder(temp_allocator, &.{Index.init(source_index)}); - // Create a chunk for the entry point here to ensure that the chunk is - // always generated even if the resulting file is empty - const hash_to_use = if (!this.options.css_chunking) - bun.hash(try temp_allocator.dupe(u8, entry_bits.bytes(this.graph.entry_points.len))) - else brk: { - var hasher = std.hash.Wyhash.init(5); - bun.writeAnyToHasher(&hasher, order.len); - for (order.slice()) |x| x.hash(&hasher); - break :brk hasher.final(); - }; - const css_chunk_entry = try css_chunks.getOrPut(hash_to_use); - if (!css_chunk_entry.found_existing) { - // const css_chunk_entry = try js_chunks.getOrPut(); - css_chunk_entry.value_ptr.* = .{ - .entry_point = .{ - .entry_point_id = entry_bit, - .source_index = source_index, - .is_entry_point = true, - }, - .entry_bits = entry_point_chunk_bits, - .content = .{ - .css = .{ - .imports_in_chunk_in_order = order, - .asts = bun.handleOom(this.allocator().alloc(bun.css.BundlerStyleSheet, order.len)), - }, - }, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - .flags = .{ - .has_html_chunk = has_html_chunk, - .is_browser_chunk_from_server_build = could_be_browser_target_from_server_build and ast_targets[source_index] == .browser, - }, - }; - } - - continue; - } - - // Create a chunk for the entry point here to ensure that the chunk is - // always generated even if the resulting file is empty - const js_chunk_entry = try js_chunks.getOrPut(js_chunk_key); - entry_point_to_js_chunk_idx[entry_id_] = @intCast(js_chunk_entry.index); - js_chunk_entry.value_ptr.* = .{ - .entry_point = .{ - .entry_point_id = entry_bit, - .source_index = source_index, - .is_entry_point = true, - }, - .entry_bits = entry_point_chunk_bits, - .content = .{ - .javascript = .{}, - }, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - .flags = .{ - .has_html_chunk = has_html_chunk, - .is_browser_chunk_from_server_build = could_be_browser_target_from_server_build and ast_targets[source_index] == .browser, - }, - }; - - { - // If this JS entry point has an associated CSS entry point, generate it - // now. This is essentially done by generating a virtual CSS file that - // only contains "@import" statements in the order that the files were - // discovered in JS source order, where JS source order is arbitrary but - // consistent for dynamic imports. Then we run the CSS import order - // algorithm to determine the final CSS file order for the chunk. - const css_source_indices = this.findImportedCSSFilesInJSOrder(temp_allocator, Index.init(source_index)); - if (css_source_indices.len > 0) { - const order = this.findImportedFilesInCSSOrder(temp_allocator, css_source_indices.slice()); - - // Always use content-based hashing for CSS chunk deduplication. - // This ensures that when multiple JS entry points import the - // same CSS files, they share a single CSS output chunk rather - // than producing duplicates that collide on hash-based naming. - const hash_to_use = brk: { - var hasher = std.hash.Wyhash.init(5); - bun.writeAnyToHasher(&hasher, order.len); - for (order.slice()) |x| x.hash(&hasher); - break :brk hasher.final(); - }; - - const css_chunk_entry = try css_chunks.getOrPut(hash_to_use); - - js_chunk_entry.value_ptr.content.javascript.css_chunks = try this.allocator().dupe(u32, &.{ - @intCast(css_chunk_entry.index), - }); - js_chunks_with_css += 1; - - if (!css_chunk_entry.found_existing) { - var css_files_with_parts_in_chunk = std.AutoArrayHashMapUnmanaged(Index.Int, usize){}; - for (order.slice()) |entry| { - if (entry.kind == .source_index) { - bun.handleOom(css_files_with_parts_in_chunk.put(this.allocator(), entry.kind.source_index.get(), 0)); - } - } - css_chunk_entry.value_ptr.* = .{ - .entry_point = .{ - .entry_point_id = entry_bit, - .source_index = source_index, - .is_entry_point = true, - }, - .entry_bits = entry_bits.*, - .content = .{ - .css = .{ - .imports_in_chunk_in_order = order, - .asts = bun.handleOom(this.allocator().alloc(bun.css.BundlerStyleSheet, order.len)), - }, - }, - .files_with_parts_in_chunk = css_files_with_parts_in_chunk, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - .flags = .{ - .has_html_chunk = has_html_chunk, - .is_browser_chunk_from_server_build = could_be_browser_target_from_server_build and ast_targets[source_index] == .browser, - }, - }; - } - } - } - } - var file_entry_bits: []AutoBitSet = this.graph.files.items(.entry_bits); - - const Handler = struct { - chunks: []Chunk, - allocator: std.mem.Allocator, - source_id: u32, - entry_point_to_js_chunk_idx: []const u32, - - pub fn next(c: *@This(), entry_point_id: usize) void { - // Map the entry point ID to the actual JS chunk index. - // CSS-only entry points don't have JS chunks (sentinel value). - const chunk_idx = c.entry_point_to_js_chunk_idx[entry_point_id]; - if (chunk_idx == std.math.maxInt(u32)) return; - - const entry = c.chunks[chunk_idx].files_with_parts_in_chunk.getOrPut(c.allocator, @as(u32, @truncate(c.source_id))) catch unreachable; - if (!entry.found_existing) { - entry.value_ptr.* = 0; // Initialize byte count to 0 - } - } - }; - - const css_reprs = this.graph.ast.items(.css); - - // Figure out which JS files are in which chunk - if (js_chunks.count() > 0) { - for (this.graph.reachable_files) |source_index| { - if (this.graph.files_live.isSet(source_index.get())) { - if (this.graph.ast.items(.css)[source_index.get()] == null) { - const entry_bits: *const AutoBitSet = &file_entry_bits[source_index.get()]; - if (css_reprs[source_index.get()] != null) continue; - - if (this.graph.code_splitting) { - const js_chunk_key = try temp_allocator.dupe(u8, entry_bits.bytes(this.graph.entry_points.len)); - var js_chunk_entry = try js_chunks.getOrPut(js_chunk_key); - - if (!js_chunk_entry.found_existing) { - const is_browser_chunk_from_server_build = could_be_browser_target_from_server_build and ast_targets[source_index.get()] == .browser; - js_chunk_entry.value_ptr.* = .{ - .entry_bits = entry_bits.*, - .entry_point = .{ - .source_index = source_index.get(), - }, - .content = .{ - .javascript = .{}, - }, - .output_source_map = SourceMap.SourceMapPieces.init(this.allocator()), - .flags = .{ .is_browser_chunk_from_server_build = is_browser_chunk_from_server_build }, - }; - } else if (could_be_browser_target_from_server_build and - !js_chunk_entry.value_ptr.entry_point.is_entry_point and - !js_chunk_entry.value_ptr.flags.is_browser_chunk_from_server_build and - ast_targets[source_index.get()] == .browser) - { - // If any file in the chunk has browser target, mark the whole chunk as browser. - // This handles the case where a lazy-loaded chunk (code splitting chunk, not entry point) - // contains browser-targeted files but was first created by a non-browser file. - // We only apply this to non-entry-point chunks to preserve the correct side for server entry points. - js_chunk_entry.value_ptr.flags.is_browser_chunk_from_server_build = true; - } - - const entry = js_chunk_entry.value_ptr.files_with_parts_in_chunk.getOrPut(this.allocator(), @as(u32, @truncate(source_index.get()))) catch unreachable; - if (!entry.found_existing) { - entry.value_ptr.* = 0; // Initialize byte count to 0 - } - } else { - var handler = Handler{ - .chunks = js_chunks.values(), - .allocator = this.allocator(), - .source_id = source_index.get(), - .entry_point_to_js_chunk_idx = entry_point_to_js_chunk_idx, - }; - entry_bits.forEach(Handler, &handler, Handler.next); - } - } - } - } - } - - // Sort the chunks for determinism. This matters because we use chunk indices - // as sorting keys in a few places. - const chunks: []Chunk = sort_chunks: { - var sorted_chunks = try BabyList(Chunk).initCapacity(this.allocator(), js_chunks.count() + css_chunks.count() + html_chunks.count()); - - var sorted_keys = try BabyList(string).initCapacity(temp_allocator, js_chunks.count()); - - sorted_keys.appendSliceAssumeCapacity(js_chunks.keys()); - - // sort by entry_point_id to ensure the main entry point (id=0) comes first, - // then by key for determinism among the rest. - const ChunkSortContext = struct { - chunks: *const bun.StringArrayHashMap(Chunk), - - pub fn lessThan(ctx: @This(), a_key: string, b_key: string) bool { - const a_chunk = ctx.chunks.get(a_key) orelse return true; - const b_chunk = ctx.chunks.get(b_key) orelse return false; - const a_id = a_chunk.entry_point.entry_point_id; - const b_id = b_chunk.entry_point.entry_point_id; - - // Main entry point (id=0) always comes first - if (a_id == 0 and b_id != 0) return true; - if (b_id == 0 and a_id != 0) return false; - - // Otherwise sort alphabetically by key for determinism - return bun.strings.order(a_key, b_key) == .lt; - } - }; - - sorted_keys.sort(ChunkSortContext, .{ .chunks = &js_chunks }); - var js_chunk_indices_with_css = try BabyList(u32).initCapacity(temp_allocator, js_chunks_with_css); - for (sorted_keys.slice()) |key| { - const chunk = js_chunks.get(key) orelse unreachable; - - if (chunk.content.javascript.css_chunks.len > 0) - js_chunk_indices_with_css.appendAssumeCapacity(sorted_chunks.len); - - sorted_chunks.appendAssumeCapacity(chunk); - - // Attempt to order the JS HTML chunk immediately after the non-html one. - if (chunk.flags.has_html_chunk) { - if (html_chunks.fetchSwapRemove(key)) |html_chunk| { - sorted_chunks.appendAssumeCapacity(html_chunk.value); - } - } - } - - if (css_chunks.count() > 0) { - const sorted_css_keys = try temp_allocator.dupe(u64, css_chunks.keys()); - std.sort.pdq(u64, sorted_css_keys, {}, std.sort.asc(u64)); - - // A map from the index in `css_chunks` to it's final index in `sorted_chunks` - const remapped_css_indexes = try temp_allocator.alloc(u32, css_chunks.count()); - - const css_chunk_values = css_chunks.values(); - // Use sorted_chunks.len as the starting index because HTML chunks - // may be interleaved with JS chunks, so js_chunks.count() would be - // incorrect when HTML entry points are present. - for (sorted_css_keys, sorted_chunks.len..) |key, sorted_index| { - const index = css_chunks.getIndex(key) orelse unreachable; - sorted_chunks.appendAssumeCapacity(css_chunk_values[index]); - remapped_css_indexes[index] = @intCast(sorted_index); - } - - // Update all affected JS chunks to point at the correct CSS chunk index. - for (js_chunk_indices_with_css.slice()) |js_index| { - for (sorted_chunks.slice()[js_index].content.javascript.css_chunks) |*idx| { - idx.* = remapped_css_indexes[idx.*]; - } - } - } - - // We don't care about the order of the HTML chunks that have no JS chunks. - try sorted_chunks.appendSlice(this.allocator(), html_chunks.values()); - - break :sort_chunks sorted_chunks.slice(); - }; - - const entry_point_chunk_indices: []u32 = this.graph.files.items(.entry_point_chunk_index); - // Map from the entry point file to this chunk. We will need this later if - // a file contains a dynamic import to this entry point, since we'll need - // to look up the path for this chunk to use with the import. - for (chunks, 0..) |*chunk, chunk_id| { - if (chunk.entry_point.is_entry_point) { - // JS entry points that import CSS files generate two chunks, a JS chunk - // and a CSS chunk. Don't link the CSS chunk to the JS file since the CSS - // chunk is secondary (the JS chunk is primary). - if (chunk.content == .css and css_asts[chunk.entry_point.source_index] == null) { - continue; - } - entry_point_chunk_indices[chunk.entry_point.source_index] = @intCast(chunk_id); - } - } - - // Determine the order of JS files (and parts) within the chunk ahead of time - try this.findAllImportedPartsInJSOrder(temp_allocator, chunks); - - // Handle empty chunks case - if (chunks.len == 0) { - this.unique_key_buf = ""; - return chunks; - } - - const unique_key_item_len = std.fmt.count("{f}C{d:0>8}", .{ bun.fmt.hexIntLower(unique_key), chunks.len }); - var unique_key_builder = try bun.StringBuilder.initCapacity(this.allocator(), unique_key_item_len * chunks.len); - this.unique_key_buf = unique_key_builder.allocatedSlice(); - - errdefer { - unique_key_builder.deinit(this.allocator()); - this.unique_key_buf = ""; - } - - const kinds = this.graph.files.items(.entry_point_kind); - const output_paths = this.graph.entry_points.items(.output_path); - const bv2: *bundler.BundleV2 = @fieldParentPtr("linker", this); - for (chunks, 0..) |*chunk, chunk_id| { - // Assign a unique key to each chunk. This key encodes the index directly so - // we can easily recover it later without needing to look it up in a map. The - // last 8 numbers of the key are the chunk index. - chunk.unique_key = unique_key_builder.fmt("{f}C{d:0>8}", .{ bun.fmt.hexIntLower(unique_key), chunk_id }); - if (this.unique_key_prefix.len == 0) - this.unique_key_prefix = chunk.unique_key[0..std.fmt.count("{f}", .{bun.fmt.hexIntLower(unique_key)})]; - - if (chunk.entry_point.is_entry_point and - (chunk.content == .html or (kinds[chunk.entry_point.source_index] == .user_specified and !chunk.flags.has_html_chunk))) - { - // Use fileWithTarget template if there are HTML imports and user hasn't manually set naming - if (has_server_html_imports and bv2.transpiler.options.entry_naming.len == 0) { - chunk.template = PathTemplate.fileWithTarget; - } else { - chunk.template = PathTemplate.file; - if (chunk.flags.is_browser_chunk_from_server_build) { - chunk.template.data = bv2.transpilerForTarget(.browser).options.entry_naming; - } else { - chunk.template.data = bv2.transpiler.options.entry_naming; - } - } - } else { - if (has_server_html_imports and bv2.transpiler.options.chunk_naming.len == 0) { - chunk.template = PathTemplate.chunkWithTarget; - } else { - chunk.template = PathTemplate.chunk; - if (chunk.flags.is_browser_chunk_from_server_build) { - chunk.template.data = bv2.transpilerForTarget(.browser).options.chunk_naming; - } else { - chunk.template.data = bv2.transpiler.options.chunk_naming; - } - } - } - - const pathname = Fs.PathName.init(output_paths[chunk.entry_point.entry_point_id].slice()); - chunk.template.placeholder.name = pathname.base; - chunk.template.placeholder.ext = chunk.content.ext(); - - if (chunk.template.needs(.target)) { - // Determine the target from the AST of the entry point source - const chunk_target = ast_targets[chunk.entry_point.source_index]; - chunk.template.placeholder.target = switch (chunk_target) { - .browser => "browser", - .bun => "bun", - .node => "node", - .bun_macro => "macro", - .bake_server_components_ssr => "ssr", - }; - } - - if (chunk.template.needs(.dir)) { - // this if check is a specific fix for `bun build hi.ts --external '*'`, without leading `./` - const dir_path = if (pathname.dir.len > 0) pathname.dir else "."; - var real_path_buf: bun.PathBuffer = undefined; - const dir = dir: { - var dir = bun.sys.openatA(.cwd(), dir_path, bun.O.PATH | bun.O.DIRECTORY, 0).unwrap() catch { - break :dir bun.path.normalizeBuf(dir_path, &real_path_buf, .auto); - }; - defer dir.close(); - - break :dir dir.getFdPath(&real_path_buf) catch |err| { - try this.log.addErrorFmt(null, .Empty, this.allocator(), "{s}: Failed to get full path for directory '{s}'", .{ @errorName(err), dir_path }); - return error.BuildFailed; - }; - }; - - chunk.template.placeholder.dir = try resolve_path.relativeAlloc(this.allocator(), this.resolver.opts.root_dir, dir); - } - } - - return chunks; -} - -const JSChunkKeyFormatter = struct { - has_html: bool, - entry_bits: []const u8, - - pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - try writer.writeAll(&[_]u8{@intFromBool(!this.has_html)}); - try writer.writeAll(this.entry_bits); - } -}; - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const SourceMap = bun.SourceMap; -const options = bun.options; -const AutoBitSet = bun.bit_set.AutoBitSet; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const EntryPoint = bundler.EntryPoint; -const Fs = bun.bundle_v2.Fs; -const Index = bun.bundle_v2.Index; -const LinkerContext = bun.bundle_v2.LinkerContext; -const PathTemplate = bundler.PathTemplate; -const resolve_path = bun.bundle_v2.resolve_path; diff --git a/src/bundler/linker_context/computeCrossChunkDependencies.zig b/src/bundler/linker_context/computeCrossChunkDependencies.zig deleted file mode 100644 index a21a22132a91..000000000000 --- a/src/bundler/linker_context/computeCrossChunkDependencies.zig +++ /dev/null @@ -1,459 +0,0 @@ -pub fn computeCrossChunkDependencies(c: *LinkerContext, chunks: []Chunk) bun.OOM!void { - if (!c.graph.code_splitting) { - // No need to compute cross-chunk dependencies if there can't be any - return; - } - - const chunk_metas = try c.allocator().alloc(ChunkMeta, chunks.len); - for (chunk_metas) |*meta| { - // these must be global allocator - meta.* = .{ - .imports = ChunkMeta.Map.init(bun.default_allocator), - .exports = ChunkMeta.Map.init(bun.default_allocator), - .dynamic_imports = std.AutoArrayHashMap(Index.Int, void).init(bun.default_allocator), - }; - } - defer { - for (chunk_metas) |*meta| { - meta.imports.deinit(); - meta.exports.deinit(); - meta.dynamic_imports.deinit(); - } - c.allocator().free(chunk_metas); - } - - { - const cross_chunk_dependencies = c.allocator().create(CrossChunkDependencies) catch unreachable; - defer c.allocator().destroy(cross_chunk_dependencies); - - cross_chunk_dependencies.* = .{ - .chunks = chunks, - .chunk_meta = chunk_metas, - .parts = c.graph.ast.items(.parts), - .import_records = c.graph.ast.items(.import_records), - .flags = c.graph.meta.items(.flags), - .entry_point_chunk_indices = c.graph.files.items(.entry_point_chunk_index), - .imports_to_bind = c.graph.meta.items(.imports_to_bind), - .wrapper_refs = c.graph.ast.items(.wrapper_ref), - .exports_refs = c.graph.ast.items(.exports_ref), - .sorted_and_filtered_export_aliases = c.graph.meta.items(.sorted_and_filtered_export_aliases), - .resolved_exports = c.graph.meta.items(.resolved_exports), - .ctx = c, - .symbols = &c.graph.symbols, - }; - - c.parse_graph.pool.worker_pool.eachPtr( - c.allocator(), - cross_chunk_dependencies, - CrossChunkDependencies.walk, - chunks, - ) catch unreachable; - } - - try computeCrossChunkDependenciesWithChunkMetas(c, chunks, chunk_metas); -} - -const CrossChunkDependencies = struct { - chunk_meta: []ChunkMeta, - chunks: []Chunk, - parts: []BabyList(Part), - import_records: []BabyList(bun.ImportRecord), - flags: []const JSMeta.Flags, - entry_point_chunk_indices: []Index.Int, - imports_to_bind: []RefImportData, - wrapper_refs: []const Ref, - exports_refs: []const Ref, - sorted_and_filtered_export_aliases: []const []const string, - resolved_exports: []const ResolvedExports, - ctx: *LinkerContext, - symbols: *Symbol.Map, - - pub fn walk(deps: *@This(), chunk: *Chunk, chunk_index: usize) void { - var chunk_meta = &deps.chunk_meta[chunk_index]; - var imports = &deps.chunk_meta[chunk_index].imports; - - const entry_point_chunk_indices = deps.entry_point_chunk_indices; - - // Go over each file in this chunk - for (chunk.files_with_parts_in_chunk.keys()) |source_index| { - // TODO: make this switch - if (chunk.content == .css) { - continue; - } - if (chunk.content != .javascript) continue; - - // Go over each part in this file that's marked for inclusion in this chunk - const parts = deps.parts[source_index].slice(); - var import_records = deps.import_records[source_index].slice(); - const imports_to_bind = deps.imports_to_bind[source_index]; - const wrap = deps.flags[source_index].wrap; - const wrapper_ref = deps.wrapper_refs[source_index]; - const _chunks = deps.chunks; - - for (parts) |*part| { - if (!part.is_live) - continue; - - // Rewrite external dynamic imports to point to the chunk for that entry point - for (part.import_record_indices.slice()) |import_record_id| { - var import_record = &import_records[import_record_id]; - if (import_record.source_index.isValid() and deps.ctx.isExternalDynamicImport(import_record, source_index)) { - const other_chunk_index = entry_point_chunk_indices[import_record.source_index.get()]; - import_record.path.text = _chunks[other_chunk_index].unique_key; - import_record.source_index = Index.invalid; - - // Track this cross-chunk dynamic import so we make sure to - // include its hash when we're calculating the hashes of all - // dependencies of this chunk. - if (other_chunk_index != chunk_index) - chunk_meta.dynamic_imports.put(other_chunk_index, {}) catch unreachable; - } - } - - // Remember what chunk each top-level symbol is declared in. Symbols - // with multiple declarations such as repeated "var" statements with - // the same name should already be marked as all being in a single - // chunk. In that case this will overwrite the same value below which - // is fine. - deps.symbols.assignChunkIndex(part.declared_symbols, @as(u32, @truncate(chunk_index))); - - const used_refs = part.symbol_uses.keys(); - - // Record each symbol used in this part. This will later be matched up - // with our map of which chunk a given symbol is declared in to - // determine if the symbol needs to be imported from another chunk. - for (used_refs) |ref| { - const ref_to_use = brk: { - var ref_to_use = ref; - var symbol = deps.symbols.getConst(ref_to_use).?; - - // Ignore unbound symbols - if (symbol.kind == .unbound) - continue; - - // Ignore symbols that are going to be replaced by undefined - if (symbol.import_item_status == .missing) - continue; - - // If this is imported from another file, follow the import - // reference and reference the symbol in that file instead - if (imports_to_bind.get(ref_to_use)) |import_data| { - ref_to_use = import_data.data.import_ref; - symbol = deps.symbols.getConst(ref_to_use).?; - } else if (wrap == .cjs and ref_to_use.eql(wrapper_ref)) { - // The only internal symbol that wrapped CommonJS files export - // is the wrapper itself. - continue; - } - - // If this is an ES6 import from a CommonJS file, it will become a - // property access off the namespace symbol instead of a bare - // identifier. In that case we want to pull in the namespace symbol - // instead. The namespace symbol stores the result of "require()". - if (symbol.namespace_alias) |*namespace_alias| { - ref_to_use = namespace_alias.namespace_ref; - } - break :brk ref_to_use; - }; - - if (comptime Environment.allow_assert) - debug("Cross-chunk import: {s} {f}", .{ deps.symbols.get(ref_to_use).?.original_name, ref_to_use }); - - // We must record this relationship even for symbols that are not - // imports. Due to code splitting, the definition of a symbol may - // be moved to a separate chunk than the use of a symbol even if - // the definition and use of that symbol are originally from the - // same source file. - imports.put(ref_to_use, {}) catch unreachable; - } - } - } - - // Include the exports if this is an entry point chunk - if (chunk.content == .javascript) { - if (chunk.entry_point.is_entry_point) { - const flags = deps.flags[chunk.entry_point.source_index]; - if (flags.wrap != .cjs) { - const resolved_exports = deps.resolved_exports[chunk.entry_point.source_index]; - const sorted_and_filtered_export_aliases = deps.sorted_and_filtered_export_aliases[chunk.entry_point.source_index]; - for (sorted_and_filtered_export_aliases) |alias| { - const export_ = resolved_exports.get(alias).?; - var target_ref = export_.data.import_ref; - - // If this is an import, then target what the import points to - if (deps.imports_to_bind[export_.data.source_index.get()].get(target_ref)) |import_data| { - target_ref = import_data.data.import_ref; - } - - // If this is an ES6 import from a CommonJS file, it will become a - // property access off the namespace symbol instead of a bare - // identifier. In that case we want to pull in the namespace symbol - // instead. The namespace symbol stores the result of "require()". - if (deps.symbols.getConst(target_ref).?.namespace_alias) |namespace_alias| { - target_ref = namespace_alias.namespace_ref; - } - - if (comptime Environment.allow_assert) - debug("Cross-chunk export: {s}", .{deps.symbols.get(target_ref).?.original_name}); - - imports.put(target_ref, {}) catch unreachable; - } - } - - // Ensure "exports" is included if the current output format needs it - // https://github.com/evanw/esbuild/blob/v0.27.2/internal/linker/linker.go#L1049-L1051 - if (flags.force_include_exports_for_entry_point) { - imports.put(deps.exports_refs[chunk.entry_point.source_index], {}) catch unreachable; - } - - // Include the wrapper if present - // https://github.com/evanw/esbuild/blob/v0.27.2/internal/linker/linker.go#L1053-L1056 - if (flags.wrap != .none) { - imports.put(deps.wrapper_refs[chunk.entry_point.source_index], {}) catch unreachable; - } - } - } - } -}; - -fn computeCrossChunkDependenciesWithChunkMetas(c: *LinkerContext, chunks: []Chunk, chunk_metas: []ChunkMeta) !void { - - // Mark imported symbols as exported in the chunk from which they are declared - for (chunks, chunk_metas, 0..) |*chunk, *chunk_meta, chunk_index| { - if (chunk.content != .javascript) { - continue; - } - var js = &chunk.content.javascript; - - // Find all uses in this chunk of symbols from other chunks - for (chunk_meta.imports.keys()) |import_ref| { - const symbol = c.graph.symbols.getConst(import_ref).?; - - // Ignore uses that aren't top-level symbols - if (symbol.chunkIndex()) |other_chunk_index| { - if (@as(usize, other_chunk_index) != chunk_index) { - if (comptime Environment.allow_assert) - debug("Import name: {s} (in {s})", .{ - symbol.original_name, - c.parse_graph.input_files.get(import_ref.sourceIndex()).source.path.text, - }); - - { - var entry = try js - .imports_from_other_chunks - .getOrPutValue(c.allocator(), other_chunk_index, .{}); - try entry.value_ptr.append(c.allocator(), .{ - .ref = import_ref, - }); - } - _ = chunk_metas[other_chunk_index].exports.getOrPut(import_ref) catch unreachable; - } else { - debug("{s} imports from itself (chunk {d})", .{ symbol.original_name, chunk_index }); - } - } - } - - // If this is an entry point, make sure we import all chunks belonging to - // this entry point, even if there are no imports. We need to make sure - // these chunks are evaluated for their side effects too. - if (chunk.entry_point.is_entry_point) { - for (chunks, 0..) |*other_chunk, other_chunk_index| { - if (other_chunk_index == chunk_index or other_chunk.content != .javascript) continue; - - if (other_chunk.entry_bits.isSet(chunk.entry_point.entry_point_id)) { - _ = js.imports_from_other_chunks.getOrPutValue( - c.allocator(), - @as(u32, @truncate(other_chunk_index)), - CrossChunkImport.Item.List{}, - ) catch unreachable; - } - } - } - - // Make sure we also track dynamic cross-chunk imports. These need to be - // tracked so we count them as dependencies of this chunk for the purpose - // of hash calculation. - if (chunk_meta.dynamic_imports.count() > 0) { - const dynamic_chunk_indices = chunk_meta.dynamic_imports.keys(); - std.sort.pdq(Index.Int, dynamic_chunk_indices, {}, std.sort.asc(Index.Int)); - - const new_imports = bun.handleOom( - chunk.cross_chunk_imports.writableSlice(c.allocator(), dynamic_chunk_indices.len), - ); - for (dynamic_chunk_indices, new_imports) |dynamic_chunk_index, *item| { - item.* = .{ - .import_kind = .dynamic, - .chunk_index = dynamic_chunk_index, - }; - } - } - } - - // Generate cross-chunk exports. These must be computed before cross-chunk - // imports because of export alias renaming, which must consider all export - // aliases simultaneously to avoid collisions. - { - bun.assert(chunk_metas.len == chunks.len); - var r = renamer.ExportRenamer.init(c.allocator()); - defer r.deinit(); - debug("Generating cross-chunk exports", .{}); - - var stable_ref_list = std.array_list.Managed(StableRef).init(c.allocator()); - defer stable_ref_list.deinit(); - - for (chunks, chunk_metas) |*chunk, *chunk_meta| { - if (chunk.content != .javascript) continue; - - var repr = &chunk.content.javascript; - - switch (c.options.output_format) { - .esm => { - c.sortedCrossChunkExportItems( - chunk_meta.exports, - &stable_ref_list, - ); - var clause_items = BabyList(js_ast.ClauseItem).initCapacity(c.allocator(), stable_ref_list.items.len) catch unreachable; - clause_items.len = @as(u32, @truncate(stable_ref_list.items.len)); - repr.exports_to_other_chunks.ensureUnusedCapacity(c.allocator(), stable_ref_list.items.len) catch unreachable; - r.clearRetainingCapacity(); - - for (stable_ref_list.items, clause_items.slice()) |stable_ref, *clause_item| { - const ref = stable_ref.ref; - const alias = if (c.options.minify_identifiers) try r.nextMinifiedName(c.allocator()) else r.nextRenamedName(c.graph.symbols.get(ref).?.original_name); - - clause_item.* = .{ - .name = .{ - .ref = ref, - .loc = Logger.Loc.Empty, - }, - .alias = alias, - .alias_loc = Logger.Loc.Empty, - .original_name = "", - }; - - repr.exports_to_other_chunks.putAssumeCapacity( - ref, - alias, - ); - } - - if (clause_items.len > 0) { - var stmts = BabyList(js_ast.Stmt).initCapacity(c.allocator(), 1) catch unreachable; - const export_clause = c.allocator().create(js_ast.S.ExportClause) catch unreachable; - export_clause.* = .{ - .items = clause_items.slice(), - .is_single_line = true, - }; - stmts.appendAssumeCapacity(.{ - .data = .{ - .s_export_clause = export_clause, - }, - .loc = Logger.Loc.Empty, - }); - repr.cross_chunk_suffix_stmts = stmts; - } - }, - else => {}, - } - } - } - - // Generate cross-chunk imports. These must be computed after cross-chunk - // exports because the export aliases must already be finalized so they can - // be embedded in the generated import statements. - { - debug("Generating cross-chunk imports", .{}); - var list = CrossChunkImport.List.init(c.allocator()); - defer list.deinit(); - for (chunks) |*chunk| { - if (chunk.content != .javascript) continue; - var repr = &chunk.content.javascript; - var cross_chunk_prefix_stmts = BabyList(js_ast.Stmt){}; - - CrossChunkImport.sortedCrossChunkImports(&list, chunks, &repr.imports_from_other_chunks) catch unreachable; - const cross_chunk_imports_input: []CrossChunkImport = list.items; - var cross_chunk_imports = chunk.cross_chunk_imports; - for (cross_chunk_imports_input) |cross_chunk_import| { - switch (c.options.output_format) { - .esm => { - const import_record_index = @as(u32, @intCast(cross_chunk_imports.len)); - - var clauses = std.array_list.Managed(js_ast.ClauseItem).initCapacity(c.allocator(), cross_chunk_import.sorted_import_items.len) catch unreachable; - for (cross_chunk_import.sorted_import_items.slice()) |item| { - clauses.appendAssumeCapacity(.{ - .name = .{ - .ref = item.ref, - .loc = Logger.Loc.Empty, - }, - .alias = item.export_alias, - .alias_loc = Logger.Loc.Empty, - }); - } - - cross_chunk_imports.append(c.allocator(), .{ - .import_kind = .stmt, - .chunk_index = cross_chunk_import.chunk_index, - }) catch unreachable; - const import = c.allocator().create(js_ast.S.Import) catch unreachable; - import.* = .{ - .items = clauses.items, - .import_record_index = import_record_index, - .namespace_ref = Ref.None, - }; - cross_chunk_prefix_stmts.append( - c.allocator(), - .{ - .data = .{ - .s_import = import, - }, - .loc = Logger.Loc.Empty, - }, - ) catch unreachable; - }, - else => {}, - } - } - - repr.cross_chunk_prefix_stmts = cross_chunk_prefix_stmts; - chunk.cross_chunk_imports = cross_chunk_imports; - } - } -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const Environment = bun.Environment; -const ImportRecord = bun.ImportRecord; -const default_allocator = bun.default_allocator; -const renamer = bun.renamer; - -const js_ast = bun.ast; -const Part = js_ast.Part; -const S = js_ast.S; -const Stmt = js_ast.Stmt; -const Symbol = js_ast.Symbol; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const CrossChunkImport = bundler.CrossChunkImport; -const Index = bun.bundle_v2.Index; -const JSMeta = bundler.JSMeta; -const Ref = bun.bundle_v2.Ref; -const RefImportData = bundler.RefImportData; -const ResolvedExports = bundler.ResolvedExports; -const StableRef = bundler.StableRef; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const ChunkMeta = LinkerContext.ChunkMeta; -const debug = LinkerContext.debug; - -const Logger = bun.logger; -const Loc = Logger.Loc; diff --git a/src/bundler/linker_context/convertStmtsForChunk.zig b/src/bundler/linker_context/convertStmtsForChunk.zig deleted file mode 100644 index 712e519d7dd1..000000000000 --- a/src/bundler/linker_context/convertStmtsForChunk.zig +++ /dev/null @@ -1,558 +0,0 @@ -/// Code we ultimately include in the bundle is potentially wrapped -/// -/// In that case, we do a final pass over the statements list to figure out -/// where it needs to go in the wrapper, following the syntax of the output -/// format ESM import and export statements to always be top-level, so they -/// can never be inside the wrapper. -/// -/// prefix - outer -/// ... -/// var init_foo = __esm(() => { -/// prefix - inner -/// ... -/// suffix - inenr -/// }); -/// ... -/// suffix - outer -/// -/// Keep in mind that we may need to wrap ES modules in some cases too -/// Consider: -/// import * as foo from 'bar'; -/// foo[computedProperty] -/// -/// In that case, when bundling, we still need to preserve that module -/// namespace object (foo) because we cannot know what they are going to -/// attempt to access statically -pub fn convertStmtsForChunk( - c: *LinkerContext, - source_index: u32, - stmts: *StmtList, - part_stmts: []const js_ast.Stmt, - chunk: *Chunk, - allocator: std.mem.Allocator, - wrap: WrapKind, - ast: *const JSAst, -) !void { - const shouldExtractESMStmtsForWrap = wrap != .none; - const shouldStripExports = c.options.mode != .passthrough or c.graph.files.items(.entry_point_kind)[source_index] != .none; - - const flags = c.graph.meta.items(.flags); - const output_format = c.options.output_format; - - // If this file is a CommonJS entry point, double-write re-exports to the - // external CommonJS "module.exports" object in addition to our internal ESM - // export namespace object. The difference between these two objects is that - // our internal one must not have the "__esModule" marker while the external - // one must have the "__esModule" marker. This is done because an ES module - // importing itself should not see the "__esModule" marker but a CommonJS module - // importing us should see the "__esModule" marker. - var module_exports_for_export: ?Expr = null; - if (output_format == .cjs and chunk.isEntryPoint()) { - module_exports_for_export = Expr.allocate( - allocator, - E.Dot, - E.Dot{ - .target = Expr.allocate( - allocator, - E.Identifier, - E.Identifier{ - .ref = c.unbound_module_ref, - }, - Logger.Loc.Empty, - ), - .name = "exports", - .name_loc = Logger.Loc.Empty, - }, - Logger.Loc.Empty, - ); - } - - for (part_stmts) |stmt_| { - var stmt = stmt_; - process_stmt: { - switch (stmt.data) { - .s_import => |s| { - // "import * as ns from 'path'" - // "import {foo} from 'path'" - if (try c.shouldRemoveImportExportStmt( - stmts, - stmt.loc, - s.namespace_ref, - s.import_record_index, - allocator, - ast, - )) { - continue; - } - - // Make sure these don't end up in the wrapper closure - if (shouldExtractESMStmtsForWrap) { - try stmts.append(.outside_wrapper_prefix, stmt); - continue; - } - }, - .s_export_star => |s| { - // "export * as ns from 'path'" - if (s.alias) |alias| { - if (try c.shouldRemoveImportExportStmt( - stmts, - stmt.loc, - s.namespace_ref, - s.import_record_index, - allocator, - ast, - )) { - continue; - } - - if (shouldStripExports) { - // Turn this statement into "import * as ns from 'path'" - stmt = Stmt.alloc( - S.Import, - S.Import{ - .namespace_ref = s.namespace_ref, - .import_record_index = s.import_record_index, - .star_name_loc = alias.loc, - }, - stmt.loc, - ); - } - - // Make sure these don't end up in the wrapper closure - if (shouldExtractESMStmtsForWrap) { - try stmts.append(.outside_wrapper_prefix, stmt); - continue; - } - - break :process_stmt; - } - - // "export * from 'path'" - const record = ast.import_records.at(s.import_record_index); - - // Barrel optimization: deferred export * records should be dropped - if (record.flags.is_unused) { - continue; - } - - if (!shouldStripExports) { - break :process_stmt; - } - - // Is this export star evaluated at run time? - if (!record.source_index.isValid() and c.options.output_format.keepES6ImportExportSyntax()) { - if (record.flags.calls_runtime_re_export_fn) { - // Turn this statement into "import * as ns from 'path'" - stmt = Stmt.alloc( - S.Import, - S.Import{ - .namespace_ref = s.namespace_ref, - .import_record_index = s.import_record_index, - .star_name_loc = stmt.loc, - }, - stmt.loc, - ); - - // Prefix this module with "__reExport(exports, ns, module.exports)" - const export_star_ref = c.runtimeFunction("__reExport"); - var args = try allocator.alloc(Expr, 2 + @as(usize, @intFromBool(module_exports_for_export != null))); - args[0..2].* = .{ - Expr.init( - E.Identifier, - E.Identifier{ - .ref = ast.exports_ref, - }, - stmt.loc, - ), - Expr.init( - E.Identifier, - E.Identifier{ - .ref = s.namespace_ref, - }, - stmt.loc, - ), - }; - - if (module_exports_for_export) |mod| { - args[3] = mod; - } - - try stmts.inside_wrapper_prefix.appendNonDependency( - Stmt.alloc( - S.SExpr, - S.SExpr{ - .value = Expr.allocate( - allocator, - E.Call, - E.Call{ - .target = Expr.allocate( - allocator, - E.Identifier, - E.Identifier{ - .ref = export_star_ref, - }, - stmt.loc, - ), - .args = bun.BabyList(Expr).fromOwnedSlice(args), - }, - stmt.loc, - ), - }, - stmt.loc, - ), - ); - - // Make sure these don't end up in the wrapper closure - if (shouldExtractESMStmtsForWrap) { - try stmts.append(.outside_wrapper_prefix, stmt); - continue; - } - } - } else { - if (record.source_index.isValid()) { - const flag = flags[record.source_index.get()]; - const wrapper_ref = c.graph.ast.items(.wrapper_ref)[record.source_index.get()]; - if (flag.wrap == .esm and wrapper_ref.isValid()) { - try stmts.inside_wrapper_prefix.appendNonDependency( - Stmt.alloc(S.SExpr, .{ - .value = Expr.init(E.Call, .{ - .target = Expr.init( - E.Identifier, - E.Identifier{ - .ref = wrapper_ref, - }, - stmt.loc, - ), - }, stmt.loc), - }, stmt.loc), - ); - } - } - - if (record.flags.calls_runtime_re_export_fn) { - const target: Expr = brk: { - if (record.source_index.isValid() and c.graph.ast.items(.exports_kind)[record.source_index.get()].isESMWithDynamicFallback()) { - // Prefix this module with "__reExport(exports, otherExports, module.exports)" - break :brk Expr.initIdentifier(c.graph.ast.items(.exports_ref)[record.source_index.get()], stmt.loc); - } - - break :brk Expr.init( - E.RequireString, - E.RequireString{ - .import_record_index = s.import_record_index, - }, - stmt.loc, - ); - }; - - // Prefix this module with "__reExport(exports, require(path), module.exports)" - const export_star_ref = c.runtimeFunction("__reExport"); - var args = try allocator.alloc(Expr, 2 + @as(usize, @intFromBool(module_exports_for_export != null))); - args[0..2].* = .{ - Expr.init( - E.Identifier, - E.Identifier{ - .ref = ast.exports_ref, - }, - stmt.loc, - ), - target, - }; - - if (module_exports_for_export) |mod| { - args[2] = mod; - } - - try stmts.inside_wrapper_prefix.appendNonDependency( - Stmt.alloc( - S.SExpr, - S.SExpr{ - .value = Expr.init( - E.Call, - E.Call{ - .target = Expr.init( - E.Identifier, - E.Identifier{ - .ref = export_star_ref, - }, - stmt.loc, - ), - .args = js_ast.ExprNodeList.fromOwnedSlice(args), - }, - stmt.loc, - ), - }, - stmt.loc, - ), - ); - } - - // Remove the export star statement - continue; - } - }, - - .s_export_from => |s| { - // "export {foo} from 'path'" - if (try c.shouldRemoveImportExportStmt( - stmts, - stmt.loc, - s.namespace_ref, - s.import_record_index, - allocator, - ast, - )) { - continue; - } - - if (shouldStripExports) { - // Turn this statement into "import {foo} from 'path'" - // TODO: is this allocation necessary? - const items = allocator.alloc(js_ast.ClauseItem, s.items.len) catch unreachable; - for (s.items, items) |src, *dest| { - dest.* = .{ - .alias = src.original_name, - .alias_loc = src.alias_loc, - .name = src.name, - }; - } - - stmt = Stmt.alloc( - S.Import, - S.Import{ - .items = items, - .import_record_index = s.import_record_index, - .namespace_ref = s.namespace_ref, - .is_single_line = s.is_single_line, - }, - stmt.loc, - ); - } - - // Make sure these don't end up in the wrapper closure - if (shouldExtractESMStmtsForWrap) { - try stmts.append(.outside_wrapper_prefix, stmt); - continue; - } - }, - - .s_export_clause => { - // "export {foo}" - - if (shouldStripExports) { - // Remove export statements entirely - continue; - } - - // Make sure these don't end up in the wrapper closure - if (shouldExtractESMStmtsForWrap) { - try stmts.append(.outside_wrapper_prefix, stmt); - continue; - } - }, - - .s_function => |s| { - // Strip the "export" keyword while bundling - if (shouldStripExports and s.func.flags.contains(.is_export)) { - // Be c areful to not modify the original statement - stmt = Stmt.alloc( - S.Function, - S.Function{ - .func = s.func, - }, - stmt.loc, - ); - stmt.data.s_function.func.flags.remove(.is_export); - } - }, - - .s_class => |s| { - // Strip the "export" keyword while bundling - if (shouldStripExports and s.is_export) { - // Be careful to not modify the original statement - stmt = Stmt.alloc( - S.Class, - S.Class{ - .class = s.class, - .is_export = false, - }, - stmt.loc, - ); - } - }, - - .s_local => |s| { - // Strip the "export" keyword while bundling - if (shouldStripExports and s.is_export) { - // Be careful to not modify the original statement - stmt = Stmt.alloc( - S.Local, - s.*, - stmt.loc, - ); - stmt.data.s_local.is_export = false; - } else if (FeatureFlags.unwrap_commonjs_to_esm and s.was_commonjs_export and wrap == .cjs) { - bun.assert(stmt.data.s_local.decls.len == 1); - const decl = stmt.data.s_local.decls.ptr[0]; - if (decl.value) |decl_value| { - stmt = Stmt.alloc( - S.SExpr, - S.SExpr{ - .value = Expr.init( - E.Binary, - E.Binary{ - .op = .bin_assign, - .left = Expr.init( - E.CommonJSExportIdentifier, - E.CommonJSExportIdentifier{ - .ref = decl.binding.data.b_identifier.ref, - }, - decl.binding.loc, - ), - .right = decl_value, - }, - stmt.loc, - ), - }, - stmt.loc, - ); - } else { - continue; - } - } - }, - - .s_export_default => |s| { - // "export default foo" - - if (shouldStripExports) { - switch (s.value) { - .stmt => |stmt2| { - switch (stmt2.data) { - .s_expr => |s2| { - // "export default foo;" => "var default = foo;" - stmt = Stmt.alloc( - S.Local, - S.Local{ - .decls = try G.Decl.List.fromSlice( - allocator, - &.{ - .{ - .binding = Binding.alloc( - allocator, - B.Identifier{ - .ref = s.default_name.ref.?, - }, - s2.value.loc, - ), - .value = s2.value, - }, - }, - ), - }, - stmt.loc, - ); - }, - .s_function => |s2| { - // "export default function() {}" => "function default() {}" - // "export default function foo() {}" => "function foo() {}" - - // Be careful to not modify the original statement - stmt = Stmt.alloc( - S.Function, - S.Function{ - .func = s2.func, - }, - stmt.loc, - ); - stmt.data.s_function.func.name = s.default_name; - }, - - .s_class => |s2| { - // "export default class {}" => "class default {}" - // "export default class foo {}" => "class foo {}" - - // Be careful to not modify the original statement - stmt = Stmt.alloc( - S.Class, - S.Class{ - .class = s2.class, - .is_export = false, - }, - stmt.loc, - ); - stmt.data.s_class.class.class_name = s.default_name; - }, - - else => bun.unreachablePanic( - "Unexpected type in source file {s}", - .{ - c.parse_graph.input_files.get(c.graph.files.get(source_index).input_file.get()).source.path.text, - }, - ), - } - }, - .expr => |e| { - stmt = Stmt.alloc( - S.Local, - S.Local{ - .decls = try G.Decl.List.fromSlice( - allocator, - &.{ - .{ - .binding = Binding.alloc( - allocator, - B.Identifier{ - .ref = s.default_name.ref.?, - }, - e.loc, - ), - .value = e, - }, - }, - ), - }, - stmt.loc, - ); - }, - } - } - }, - - else => {}, - } - } - - try stmts.append(.inside_wrapper_suffix, stmt); - } -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const FeatureFlags = bun.FeatureFlags; - -const js_ast = bun.ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const JSAst = js_ast.BundledAst; -const S = js_ast.S; -const Stmt = js_ast.Stmt; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const WrapKind = bundler.WrapKind; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const StmtList = LinkerContext.StmtList; - -const Logger = bun.logger; -const Loc = Logger.Loc; diff --git a/src/bundler/linker_context/convertStmtsForChunkForDevServer.zig b/src/bundler/linker_context/convertStmtsForChunkForDevServer.zig deleted file mode 100644 index 33c17a5c9bf0..000000000000 --- a/src/bundler/linker_context/convertStmtsForChunkForDevServer.zig +++ /dev/null @@ -1,192 +0,0 @@ -/// For CommonJS, all statements are copied `inside_wrapper_suffix` and this returns. -/// The conversion logic is completely different for format .internal_bake_dev -/// -/// For ESM, this function populates all three lists: -/// 1. outside_wrapper_prefix: all import statements, unmodified. -/// 2. inside_wrapper_prefix: a var decl line and a call to `module.retrieve` -/// 3. inside_wrapper_suffix: all non-import statements -/// -/// The imports are rewritten at print time to fit the packed array format -/// that the HMR runtime can decode. This encoding is low on JS objects and -/// indentation. -/// -/// 1 ┃ "module/esm": [ [ -/// ┃ 'module_1', 1, "add", -/// ┃ 'module_2', 2, "mul", "div", -/// ┃ 'module_3', 0, // bare or import star -/// ], [ "default" ], [], (hmr) => { -/// 2 ┃ var [module_1, module_2, module_3] = hmr.imports; -/// ┃ hmr.onUpdate = [ -/// ┃ (module) => (module_1 = module), -/// ┃ (module) => (module_2 = module), -/// ┃ (module) => (module_3 = module), -/// ┃ ]; -/// -/// 3 ┃ console.log("my module", module_1.add(1, module_2.mul(2, 3)); -/// ┃ module.exports = { -/// ┃ default: module_3.something(module_2.div), -/// ┃ }; -/// }, false ], -/// ----- "is the module async?" -pub fn convertStmtsForChunkForDevServer( - c: *LinkerContext, - stmts: *StmtList, - part_stmts: []const js_ast.Stmt, - allocator: std.mem.Allocator, - ast: *JSAst, -) !void { - const hmr_api_ref = ast.wrapper_ref; - const hmr_api_id = Expr.initIdentifier(hmr_api_ref, Logger.Loc.Empty); - var esm_decls: std.ArrayListUnmanaged(B.Array.Item) = .empty; - var esm_callbacks: std.ArrayListUnmanaged(Expr) = .empty; - - for (ast.import_records.slice()) |*record| { - if (record.path.is_disabled) continue; - if (record.source_index.isValid() and c.parse_graph.input_files.items(.loader)[record.source_index.get()] == .css) { - record.path.is_disabled = true; - continue; - } - // Make sure the printer gets the resolved path - if (record.source_index.isValid()) { - record.path = c.parse_graph.input_files.items(.source)[record.source_index.get()].path; - } - } - - // Modules which do not have side effects - for (part_stmts) |stmt| switch (stmt.data) { - else => try stmts.append(.inside_wrapper_suffix, stmt), - - .s_import => |st| { - const record = ast.import_records.mut(st.import_record_index); - if (record.path.is_disabled) continue; - - if (record.flags.is_unused) { - // Barrel optimization: this import was deferred (unused submodule). - // Don't add to dep array, but declare the namespace ref as an - // empty object so body code referencing it doesn't throw. - if (st.star_name_loc != null or st.items.len > 0 or st.default_name != null) { - try stmts.inside_wrapper_prefix.appendNonDependency(Stmt.alloc(S.Local, .{ - .kind = .k_var, - .decls = try G.Decl.List.fromSlice(allocator, &.{.{ - .binding = Binding.alloc(allocator, B.Identifier{ .ref = st.namespace_ref }, stmt.loc), - .value = Expr.init(E.Object, .{}, stmt.loc), - }}), - }, stmt.loc)); - } - continue; - } - - const is_builtin = record.tag == .builtin or record.tag == .bun or record.tag == .runtime; - const is_bare_import = st.star_name_loc == null and st.items.len == 0 and st.default_name == null; - - if (is_builtin) { - if (!is_bare_import) { - // hmr.importBuiltin('...') or hmr.require('bun:wrap') - const call = Expr.init(E.Call, .{ - .target = Expr.init(E.Dot, .{ - .target = hmr_api_id, - .name = if (record.tag == .runtime) "require" else "builtin", - .name_loc = stmt.loc, - }, stmt.loc), - .args = .fromOwnedSlice(try allocator.dupe(Expr, &.{Expr.init(E.String, .{ - .data = if (record.tag == .runtime) "bun:wrap" else record.path.pretty, - }, record.range.loc)})), - }, stmt.loc); - - // var namespace = ...; - try stmts.inside_wrapper_prefix.appendNonDependency(Stmt.alloc(S.Local, .{ - .kind = .k_var, // remove a tdz - .decls = try G.Decl.List.fromSlice(allocator, &.{.{ - .binding = Binding.alloc( - allocator, - B.Identifier{ .ref = st.namespace_ref }, - st.star_name_loc orelse stmt.loc, - ), - .value = call, - }}), - }, stmt.loc)); - } - } else { - const loc = st.star_name_loc orelse stmt.loc; - if (is_bare_import) { - try esm_decls.append(allocator, .{ .binding = .{ .data = .b_missing, .loc = .Empty } }); - try esm_callbacks.append(allocator, Expr.init(E.Arrow, .noop_return_undefined, .Empty)); - } else { - const binding = Binding.alloc(allocator, B.Identifier{ .ref = st.namespace_ref }, loc); - try esm_decls.append(allocator, .{ .binding = binding }); - try esm_callbacks.append(allocator, Expr.init(E.Arrow, .{ - .args = try allocator.dupe(G.Arg, &.{.{ - .binding = Binding.alloc(allocator, B.Identifier{ - .ref = ast.module_ref, - }, .Empty), - }}), - .prefer_expr = true, - .body = try .initReturnExpr(allocator, Expr.init(E.Binary, .{ - .op = .bin_assign, - .left = Expr.initIdentifier(st.namespace_ref, .Empty), - .right = Expr.initIdentifier(ast.module_ref, .Empty), - }, .Empty)), - }, .Empty)); - } - - try stmts.append(.outside_wrapper_prefix, stmt); - } - }, - }; - - if (esm_decls.items.len > 0) { - // var ...; - try stmts.inside_wrapper_prefix.appendNonDependency(Stmt.alloc(S.Local, .{ - .kind = .k_var, // remove a tdz - .decls = try .fromSlice(allocator, &.{.{ - .binding = Binding.alloc(allocator, B.Array{ - .items = esm_decls.items, - .is_single_line = true, - }, .Empty), - .value = Expr.init(E.Dot, .{ - .target = hmr_api_id, - .name = "imports", - .name_loc = .Empty, - }, .Empty), - }}), - }, .Empty)); - // hmr.onUpdate = [ ... ]; - try stmts.inside_wrapper_prefix.appendNonDependency(Stmt.alloc(S.SExpr, .{ - .value = Expr.init(E.Binary, .{ - .op = .bin_assign, - .left = Expr.init(E.Dot, .{ - .target = hmr_api_id, - .name = "updateImport", - .name_loc = .Empty, - }, .Empty), - .right = Expr.init(E.Array, .{ - .items = .moveFromList(&esm_callbacks), - .is_single_line = esm_callbacks.items.len <= 2, - }, .Empty), - }, .Empty), - }, .Empty)); - } -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const bun = @import("bun"); -const std = @import("std"); - -const js_ast = bun.ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const JSAst = js_ast.BundledAst; -const S = js_ast.S; -const Stmt = js_ast.Stmt; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const StmtList = LinkerContext.StmtList; - -const Logger = bun.logger; -const Loc = Logger.Loc; diff --git a/src/bundler/linker_context/doStep5.zig b/src/bundler/linker_context/doStep5.zig deleted file mode 100644 index a2c55e745ec0..000000000000 --- a/src/bundler/linker_context/doStep5.zig +++ /dev/null @@ -1,509 +0,0 @@ -/// Step 5: Create namespace exports for every file. This is always necessary -/// for CommonJS files, and is also necessary for other files if they are -/// imported using an import star statement. -pub fn doStep5(c: *LinkerContext, source_index_: Index, _: usize) void { - const source_index = source_index_.get(); - const trace = bun.perf.trace("Bundler.CreateNamespaceExports"); - defer trace.end(); - - const id = source_index; - if (id >= c.graph.meta.len) return; - - const worker: *ThreadPool.Worker = ThreadPool.Worker.get(@fieldParentPtr("linker", c)); - defer worker.unget(); - - // we must use this allocator here - const allocator = worker.allocator; - - const resolved_exports: *ResolvedExports = &c.graph.meta.items(.resolved_exports)[id]; - - // Now that all exports have been resolved, sort and filter them to create - // something we can iterate over later. - var aliases = std.array_list.Managed(string).initCapacity(allocator, resolved_exports.count()) catch unreachable; - var alias_iter = resolved_exports.iterator(); - const imports_to_bind = c.graph.meta.items(.imports_to_bind); - const probably_typescript_type = c.graph.meta.items(.probably_typescript_type); - - // counting in here saves us an extra pass through the array - var re_exports_count: usize = 0; - - next_alias: while (alias_iter.next()) |entry| { - var export_ = entry.value_ptr.*; - const alias = entry.key_ptr.*; - const this_id = export_.data.source_index.get(); - var inner_count: usize = 0; - // Re-exporting multiple symbols with the same name causes an ambiguous - // export. These names cannot be used and should not end up in generated code. - if (export_.potentially_ambiguous_export_star_refs.len > 0) { - const main = imports_to_bind[this_id].get(export_.data.import_ref) orelse ImportData{ .data = export_.data }; - for (export_.potentially_ambiguous_export_star_refs.slice()) |ambig| { - const _id = ambig.data.source_index.get(); - const ambig_ref = if (imports_to_bind[_id].get(ambig.data.import_ref)) |bound| - bound.data.import_ref - else - ambig.data.import_ref; - if (!main.data.import_ref.eql(ambig_ref)) { - continue :next_alias; - } - inner_count += @as(usize, ambig.re_exports.len); - } - } - - // Ignore re-exported imports in TypeScript files that failed to be - // resolved. These are probably just type-only imports so the best thing to - // do is to silently omit them from the export list. - if (probably_typescript_type[this_id].contains(export_.data.import_ref)) { - continue; - } - re_exports_count += inner_count; - - aliases.appendAssumeCapacity(alias); - } - // TODO: can this be u32 instead of a string? - // if yes, we could just move all the hidden exports to the end of the array - // and only store a count instead of an array - strings.sortDesc(aliases.items); - const export_aliases = aliases.toOwnedSlice() catch unreachable; - c.graph.meta.items(.sorted_and_filtered_export_aliases)[id] = export_aliases; - - // Export creation uses "sortedAndFilteredExportAliases" so this must - // come second after we fill in that array - c.createExportsForFile( - allocator, - id, - resolved_exports, - imports_to_bind, - export_aliases, - re_exports_count, - ); - - // Each part tracks the other parts it depends on within this file - var local_dependencies = std.AutoHashMap(u32, u32).init(allocator); - defer local_dependencies.deinit(); - - const parts_slice: []Part = c.graph.ast.items(.parts)[id].slice(); - const named_imports: *js_ast.Ast.NamedImports = &c.graph.ast.items(.named_imports)[id]; - - const our_imports_to_bind = imports_to_bind[id]; - outer: for (parts_slice, 0..) |*part, part_index| { - // Previously owned by `c.allocator()`, which is a `MimallocArena` (from - // `BundleV2.graph.heap`). - part.dependencies.transferOwnership(&worker.heap); - - // Now that all files have been parsed, determine which property - // accesses off of imported symbols are inlined enum values and - // which ones aren't - for ( - part.import_symbol_property_uses.keys(), - part.import_symbol_property_uses.values(), - ) |ref, properties| { - const use = part.symbol_uses.getPtr(ref).?; - - // Rare path: this import is a TypeScript enum - if (our_imports_to_bind.get(ref)) |import_data| { - const import_ref = import_data.data.import_ref; - if (c.graph.symbols.get(import_ref)) |symbol| { - if (symbol.kind == .ts_enum) { - if (c.graph.ts_enums.get(import_ref)) |enum_data| { - var found_non_inlined_enum = false; - - var it = properties.iterator(); - while (it.next()) |next| { - const name = next.key_ptr.*; - const prop_use = next.value_ptr; - - if (enum_data.get(name) == null) { - found_non_inlined_enum = true; - use.count_estimate += prop_use.count_estimate; - } - } - - if (!found_non_inlined_enum) { - if (use.count_estimate == 0) { - _ = part.symbol_uses.swapRemove(ref); - } - continue; - } - } - } - } - } - - // Common path: this import isn't a TypeScript enum - var it = properties.valueIterator(); - while (it.next()) |prop_use| { - use.count_estimate += prop_use.count_estimate; - } - } - - // TODO: inline function calls here - - // TODO: Inline cross-module constants - // if (c.graph.const_values.count() > 0) { - // // First, find any symbol usage that points to a constant value. - // // This will be pretty rare. - // const first_constant_i: ?usize = brk: { - // for (part.symbol_uses.keys(), 0..) |ref, j| { - // if (c.graph.const_values.contains(ref)) { - // break :brk j; - // } - // } - - // break :brk null; - // }; - // if (first_constant_i) |j| { - // var end_i: usize = 0; - // // symbol_uses is an array - // var keys = part.symbol_uses.keys()[j..]; - // var values = part.symbol_uses.values()[j..]; - // for (keys, values) |ref, val| { - // if (c.graph.const_values.contains(ref)) { - // continue; - // } - - // keys[end_i] = ref; - // values[end_i] = val; - // end_i += 1; - // } - // part.symbol_uses.entries.len = end_i + j; - - // if (part.symbol_uses.entries.len == 0 and part.can_be_removed_if_unused) { - // part.tag = .dead_due_to_inlining; - // part.dependencies.len = 0; - // continue :outer; - // } - - // part.symbol_uses.reIndex(allocator) catch unreachable; - // } - // } - if (false) break :outer; // this `if` is here to preserve the unused - // block label from the above commented code. - - // Now that we know this, we can determine cross-part dependencies - for (part.symbol_uses.keys(), 0..) |ref, j| { - if (comptime Environment.allow_assert) { - bun.assert(part.symbol_uses.values()[j].count_estimate > 0); - } - - const other_parts = c.topLevelSymbolsToParts(id, ref); - - for (other_parts) |other_part_index| { - const local = local_dependencies.getOrPut(other_part_index) catch unreachable; - if (!local.found_existing or local.value_ptr.* != part_index) { - local.value_ptr.* = @as(u32, @intCast(part_index)); - // note: if we crash on append, it is due to threadlocal heaps in mimalloc - part.dependencies.append( - allocator, - .{ - .source_index = Index.source(source_index), - .part_index = other_part_index, - }, - ) catch unreachable; - } - } - - // Also map from imports to parts that use them - if (named_imports.getPtr(ref)) |existing| { - bun.handleOom(existing.local_parts_with_uses.append(allocator, @intCast(part_index))); - } - } - } -} - -pub fn createExportsForFile( - c: *LinkerContext, - allocator: std.mem.Allocator, - id: u32, - resolved_exports: *ResolvedExports, - imports_to_bind: []RefImportData, - export_aliases: []const string, - re_exports_count: usize, -) void { - //////////////////////////////////////////////////////////////////////////////// - // WARNING: This method is run in parallel over all files. Do not mutate data - // for other files within this method or you will create a data race. - //////////////////////////////////////////////////////////////////////////////// - - Stmt.Disabler.disable(); - defer Stmt.Disabler.enable(); - Expr.Disabler.disable(); - defer Expr.Disabler.enable(); - - // 1 property per export - var properties = bun.handleOom(std.array_list.Managed(js_ast.G.Property) - .initCapacity(allocator, export_aliases.len)); - - var ns_export_symbol_uses = Part.SymbolUseMap{}; - bun.handleOom(ns_export_symbol_uses.ensureTotalCapacity(allocator, export_aliases.len)); - - const initial_flags = c.graph.meta.items(.flags)[id]; - const needs_exports_variable = initial_flags.needs_exports_variable; - const force_include_exports_for_entry_point = c.options.output_format == .cjs and initial_flags.force_include_exports_for_entry_point; - - const stmts_count = - // 1 statement for every export - export_aliases.len + - // + 1 if there are non-zero exports - @as(usize, @intFromBool(export_aliases.len > 0)) + - // + 1 if we need to inject the exports variable - @as(usize, @intFromBool(needs_exports_variable)) + - // + 1 if we need to do module.exports = __toCommonJS(exports) - @as(usize, @intFromBool(force_include_exports_for_entry_point)); - - var stmts = bun.handleOom(js_ast.Stmt.Batcher.init(allocator, stmts_count)); - defer stmts.done(); - const loc = Logger.Loc.Empty; - // todo: investigate if preallocating this array is faster - var ns_export_dependencies = bun.handleOom(std.array_list.Managed(js_ast.Dependency).initCapacity(allocator, re_exports_count)); - for (export_aliases) |alias| { - var exp = resolved_exports.getPtr(alias).?.*; - - // If this is an export of an import, reference the symbol that the import - // was eventually resolved to. We need to do this because imports have - // already been resolved by this point, so we can't generate a new import - // and have that be resolved later. - if (imports_to_bind[exp.data.source_index.get()].get(exp.data.import_ref)) |import_data| { - exp.data.import_ref = import_data.data.import_ref; - exp.data.source_index = import_data.data.source_index; - bun.handleOom(ns_export_dependencies.appendSlice(import_data.re_exports.slice())); - } - - // Exports of imports need EImportIdentifier in case they need to be re- - // written to a property access later on - // note: this is stack allocated - const value: js_ast.Expr = brk: { - if (c.graph.symbols.getConst(exp.data.import_ref)) |symbol| { - if (symbol.namespace_alias != null) { - break :brk js_ast.Expr.init( - js_ast.E.ImportIdentifier, - js_ast.E.ImportIdentifier{ - .ref = exp.data.import_ref, - }, - loc, - ); - } - } - - break :brk js_ast.Expr.init( - js_ast.E.Identifier, - js_ast.E.Identifier{ - .ref = exp.data.import_ref, - }, - loc, - ); - }; - - const fn_body = js_ast.G.FnBody{ - .stmts = stmts.eat1( - js_ast.Stmt.allocate( - allocator, - js_ast.S.Return, - .{ .value = value }, - loc, - ), - ), - .loc = loc, - }; - properties.appendAssumeCapacity(.{ - .key = js_ast.Expr.allocate( - allocator, - js_ast.E.String, - .{ - // TODO: test emoji work as expected - // relevant for WASM exports - .data = alias, - }, - loc, - ), - .value = js_ast.Expr.allocate( - allocator, - js_ast.E.Arrow, - .{ .prefer_expr = true, .body = fn_body }, - loc, - ), - }); - ns_export_symbol_uses.putAssumeCapacity(exp.data.import_ref, .{ .count_estimate = 1 }); - - // Make sure the part that declares the export is included - const parts = c.topLevelSymbolsToParts(exp.data.source_index.get(), exp.data.import_ref); - ns_export_dependencies.ensureUnusedCapacity(parts.len) catch unreachable; - for (parts, ns_export_dependencies.unusedCapacitySlice()[0..parts.len]) |part_id, *dest| { - // Use a non-local dependency since this is likely from a different - // file if it came in through an export star - dest.* = .{ - .source_index = exp.data.source_index, - .part_index = part_id, - }; - } - ns_export_dependencies.items.len += parts.len; - } - - var declared_symbols = js_ast.DeclaredSymbol.List{}; - const exports_ref = c.graph.ast.items(.exports_ref)[id]; - const all_export_stmts: []js_ast.Stmt = stmts.head[0 .. @as(usize, @intFromBool(needs_exports_variable)) + - @as(usize, @intFromBool(properties.items.len > 0) + - @as(usize, @intFromBool(force_include_exports_for_entry_point)))]; - stmts.head = stmts.head[all_export_stmts.len..]; - var remaining_stmts = all_export_stmts; - defer bun.assert(remaining_stmts.len == 0); // all must be used - - // Prefix this part with "var exports = {}" if this isn't a CommonJS entry point - if (needs_exports_variable) { - var decls = allocator.alloc(js_ast.G.Decl, 1) catch unreachable; - decls[0] = .{ - .binding = js_ast.Binding.alloc( - allocator, - js_ast.B.Identifier{ - .ref = exports_ref, - }, - loc, - ), - .value = js_ast.Expr.allocate(allocator, js_ast.E.Object, .{}, loc), - }; - remaining_stmts[0] = js_ast.Stmt.allocate( - allocator, - js_ast.S.Local, - .{ - .decls = G.Decl.List.fromOwnedSlice(decls), - }, - loc, - ); - remaining_stmts = remaining_stmts[1..]; - declared_symbols.append(allocator, .{ .ref = exports_ref, .is_top_level = true }) catch unreachable; - } - - // "__export(exports, { foo: () => foo })" - var export_ref = Ref.None; - if (properties.items.len > 0) { - export_ref = c.runtimeFunction("__export"); - var args = allocator.alloc(js_ast.Expr, 2) catch unreachable; - args[0..2].* = [_]js_ast.Expr{ - js_ast.Expr.initIdentifier(exports_ref, loc), - js_ast.Expr.allocate( - allocator, - js_ast.E.Object, - .{ .properties = .moveFromList(&properties) }, - loc, - ), - }; - remaining_stmts[0] = js_ast.Stmt.allocate( - allocator, - js_ast.S.SExpr, - .{ - .value = js_ast.Expr.allocate( - allocator, - js_ast.E.Call, - .{ - .target = js_ast.Expr.initIdentifier(export_ref, loc), - .args = js_ast.ExprNodeList.fromOwnedSlice(args), - }, - loc, - ), - }, - loc, - ); - remaining_stmts = remaining_stmts[1..]; - // Make sure this file depends on the "__export" symbol - const parts = c.topLevelSymbolsToPartsForRuntime(export_ref); - ns_export_dependencies.ensureUnusedCapacity(parts.len) catch unreachable; - for (parts) |part_index| { - ns_export_dependencies.appendAssumeCapacity( - .{ .source_index = Index.runtime, .part_index = part_index }, - ); - } - - // Make sure the CommonJS closure, if there is one, includes "exports" - c.graph.ast.items(.flags)[id].uses_exports_ref = true; - } - - // Decorate "module.exports" with the "__esModule" flag to indicate that - // we used to be an ES module. This is done by wrapping the exports object - // instead of by mutating the exports object because other modules in the - // bundle (including the entry point module) may do "import * as" to get - // access to the exports object and should NOT see the "__esModule" flag. - if (force_include_exports_for_entry_point) { - const toCommonJSRef = c.runtimeFunction("__toCommonJS"); - - var call_args = allocator.alloc(js_ast.Expr, 1) catch unreachable; - call_args[0] = Expr.initIdentifier(exports_ref, Loc.Empty); - remaining_stmts[0] = js_ast.Stmt.assign( - Expr.allocate( - allocator, - E.Dot, - E.Dot{ - .name = "exports", - .name_loc = Loc.Empty, - .target = Expr.initIdentifier(c.unbound_module_ref, Loc.Empty), - }, - Loc.Empty, - ), - Expr.allocate( - allocator, - E.Call, - E.Call{ - .target = Expr.initIdentifier(toCommonJSRef, Loc.Empty), - .args = js_ast.ExprNodeList.fromOwnedSlice(call_args), - }, - Loc.Empty, - ), - ); - remaining_stmts = remaining_stmts[1..]; - } - - // No need to generate a part if it'll be empty - if (all_export_stmts.len > 0) { - // - we must already have preallocated the parts array - // - if the parts list is completely empty, we shouldn't have gotten here in the first place - - // Initialize the part that was allocated for us earlier. The information - // here will be used after this during tree shaking. - c.graph.ast.items(.parts)[id].slice()[js_ast.namespace_export_part_index] = .{ - .stmts = if (c.options.output_format != .internal_bake_dev) all_export_stmts else &.{}, - .symbol_uses = ns_export_symbol_uses, - .dependencies = js_ast.Dependency.List.moveFromList(&ns_export_dependencies), - .declared_symbols = declared_symbols, - - // This can be removed if nothing uses it - .can_be_removed_if_unused = true, - - // Make sure this is trimmed if unused even if tree shaking is disabled - .force_tree_shaking = true, - }; - - // Pull in the "__export" symbol if it was used - if (export_ref.isValid()) { - c.graph.meta.items(.flags)[id].needs_export_symbol_from_runtime = true; - } - } -} - -pub const ThreadPool = bun.bundle_v2.ThreadPool; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const options = bun.options; -const strings = bun.strings; - -const ImportData = bun.bundle_v2.ImportData; -const Index = bun.bundle_v2.Index; -const LinkerContext = bun.bundle_v2.LinkerContext; -const Part = bun.bundle_v2.Part; -const RefImportData = bun.bundle_v2.RefImportData; -const ResolvedExports = bun.bundle_v2.ResolvedExports; - -const js_ast = bun.bundle_v2.js_ast; -const B = js_ast.B; -const Dependency = js_ast.Dependency; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const Ref = bun.bundle_v2.js_ast.Ref; -const S = js_ast.S; -const Stmt = js_ast.Stmt; - -const Logger = bun.logger; -const Loc = Logger.Loc; diff --git a/src/bundler/linker_context/findAllImportedPartsInJSOrder.zig b/src/bundler/linker_context/findAllImportedPartsInJSOrder.zig deleted file mode 100644 index 9727512ca6a9..000000000000 --- a/src/bundler/linker_context/findAllImportedPartsInJSOrder.zig +++ /dev/null @@ -1,221 +0,0 @@ -pub fn findAllImportedPartsInJSOrder(this: *LinkerContext, temp_allocator: std.mem.Allocator, chunks: []Chunk) !void { - const trace = bun.perf.trace("Bundler.findAllImportedPartsInJSOrder"); - defer trace.end(); - - var part_ranges_shared = std.array_list.Managed(PartRange).init(temp_allocator); - var parts_prefix_shared = std.array_list.Managed(PartRange).init(temp_allocator); - defer part_ranges_shared.deinit(); - defer parts_prefix_shared.deinit(); - for (chunks, 0..) |*chunk, index| { - switch (chunk.content) { - .javascript => { - try this.findImportedPartsInJSOrder( - chunk, - &part_ranges_shared, - &parts_prefix_shared, - @intCast(index), - ); - }, - .css => {}, // handled in `findImportedCSSFilesInJSOrder` - .html => {}, - } - } -} - -pub fn findImportedPartsInJSOrder( - this: *LinkerContext, - chunk: *Chunk, - part_ranges_shared: *std.array_list.Managed(PartRange), - parts_prefix_shared: *std.array_list.Managed(PartRange), - chunk_index: u32, -) !void { - var chunk_order_array = try std.array_list.Managed(Chunk.Order).initCapacity(this.allocator(), chunk.files_with_parts_in_chunk.count()); - defer chunk_order_array.deinit(); - const distances = this.graph.files.items(.distance_from_entry_point); - for (chunk.files_with_parts_in_chunk.keys()) |source_index| { - chunk_order_array.appendAssumeCapacity( - .{ - .source_index = source_index, - .distance = distances[source_index], - .tie_breaker = this.graph.stable_source_indices[source_index], - }, - ); - } - - Chunk.Order.sort(chunk_order_array.items); - - const FindImportedPartsVisitor = struct { - entry_bits: *const AutoBitSet, - flags: []const JSMeta.Flags, - parts: []BabyList(Part), - import_records: []BabyList(ImportRecord), - files: std.array_list.Managed(Index.Int), - part_ranges: std.array_list.Managed(PartRange), - visited: std.AutoHashMap(Index.Int, void), - parts_prefix: std.array_list.Managed(PartRange), - c: *LinkerContext, - entry_point: Chunk.EntryPoint, - chunk_index: u32, - - fn appendOrExtendRange( - ranges: *std.array_list.Managed(PartRange), - source_index: Index.Int, - part_index: Index.Int, - ) void { - if (ranges.items.len > 0) { - var last_range = &ranges.items[ranges.items.len - 1]; - if (last_range.source_index.get() == source_index and last_range.part_index_end == part_index) { - last_range.part_index_end += 1; - return; - } - } - - ranges.append(.{ - .source_index = Index.init(source_index), - .part_index_begin = part_index, - .part_index_end = part_index + 1, - }) catch unreachable; - } - - // Traverse the graph using this stable order and linearize the files with - // dependencies before dependents - pub fn visit( - v: *@This(), - source_index: Index.Int, - comptime with_code_splitting: bool, - comptime with_scb: bool, - ) void { - if (source_index == Index.invalid.value) return; - const visited_entry = v.visited.getOrPut(source_index) catch unreachable; - if (visited_entry.found_existing) return; - - var is_file_in_chunk = if (with_code_splitting and v.c.graph.ast.items(.css)[source_index] == null) - // when code splitting, include the file in the chunk if ALL of the entry points overlap - v.entry_bits.eql(&v.c.graph.files.items(.entry_bits)[source_index]) - else - // when NOT code splitting, include the file in the chunk if ANY of the entry points overlap - v.entry_bits.hasIntersection(&v.c.graph.files.items(.entry_bits)[source_index]); - - // Wrapped files can't be split because they are all inside the wrapper - const can_be_split = v.flags[source_index].wrap == .none; - - const parts = v.parts[source_index].slice(); - if (can_be_split and is_file_in_chunk and parts[js_ast.namespace_export_part_index].is_live) { - appendOrExtendRange(&v.part_ranges, source_index, js_ast.namespace_export_part_index); - } - - const records = v.import_records[source_index].slice(); - - for (parts, 0..) |part, part_index_| { - const part_index = @as(u32, @truncate(part_index_)); - const is_part_in_this_chunk = is_file_in_chunk and part.is_live; - for (part.import_record_indices.slice()) |record_id| { - const record: *const ImportRecord = &records[record_id]; - if (record.source_index.isValid() and (record.kind == .stmt or is_part_in_this_chunk)) { - if (v.c.isExternalDynamicImport(record, source_index)) { - // Don't follow import() dependencies - continue; - } - - v.visit(record.source_index.get(), with_code_splitting, with_scb); - } - } - - // Then include this part after the files it imports - if (is_part_in_this_chunk) { - is_file_in_chunk = true; - - if (can_be_split and - part_index != js_ast.namespace_export_part_index and - v.c.shouldIncludePart(source_index, part)) - { - const js_parts = if (source_index == Index.runtime.value) - &v.parts_prefix - else - &v.part_ranges; - - appendOrExtendRange(js_parts, source_index, part_index); - } - } - } - - if (is_file_in_chunk) { - if (with_scb and v.c.graph.is_scb_bitset.isSet(source_index)) { - v.c.graph.files.items(.entry_point_chunk_index)[source_index] = v.chunk_index; - } - - bun.handleOom(v.files.append(source_index)); - - // CommonJS files are all-or-nothing so all parts must be contiguous - if (!can_be_split) { - v.parts_prefix.append( - .{ - .source_index = Index.init(source_index), - .part_index_begin = 0, - .part_index_end = @as(u32, @truncate(parts.len)), - }, - ) catch |err| bun.handleOom(err); - } - } - } - }; - - part_ranges_shared.clearRetainingCapacity(); - parts_prefix_shared.clearRetainingCapacity(); - - var visitor = FindImportedPartsVisitor{ - .files = std.array_list.Managed(Index.Int).init(this.allocator()), - .part_ranges = part_ranges_shared.*, - .parts_prefix = parts_prefix_shared.*, - .visited = std.AutoHashMap(Index.Int, void).init(this.allocator()), - .flags = this.graph.meta.items(.flags), - .parts = this.graph.ast.items(.parts), - .import_records = this.graph.ast.items(.import_records), - .entry_bits = chunk.entryBits(), - .c = this, - .entry_point = chunk.entry_point, - .chunk_index = chunk_index, - }; - defer { - part_ranges_shared.* = visitor.part_ranges; - parts_prefix_shared.* = visitor.parts_prefix; - visitor.visited.deinit(); - } - - switch (this.graph.code_splitting) { - inline else => |with_code_splitting| switch (this.graph.is_scb_bitset.bit_length > 0) { - inline else => |with_scb| { - visitor.visit(Index.runtime.value, with_code_splitting, with_scb); - - for (chunk_order_array.items) |order| { - visitor.visit(order.source_index, with_code_splitting, with_scb); - } - }, - }, - } - - const parts_in_chunk_order = try this.allocator().alloc(PartRange, visitor.part_ranges.items.len + visitor.parts_prefix.items.len); - bun.concat(PartRange, parts_in_chunk_order, &.{ - visitor.parts_prefix.items, - visitor.part_ranges.items, - }); - chunk.content.javascript.files_in_chunk_order = visitor.files.items; - chunk.content.javascript.parts_in_chunk_in_order = parts_in_chunk_order; -} - -pub const BitSet = bun.bit_set.DynamicBitSetUnmanaged; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const ImportRecord = bun.ImportRecord; -const AutoBitSet = bun.bit_set.AutoBitSet; - -const Chunk = bun.bundle_v2.Chunk; -const Index = bun.bundle_v2.Index; -const JSMeta = bun.bundle_v2.JSMeta; -const LinkerContext = bun.bundle_v2.LinkerContext; -const Part = bun.bundle_v2.Part; -const PartRange = bun.bundle_v2.PartRange; -const js_ast = bun.bundle_v2.js_ast; diff --git a/src/bundler/linker_context/findImportedCSSFilesInJSOrder.zig b/src/bundler/linker_context/findImportedCSSFilesInJSOrder.zig deleted file mode 100644 index 6a6036363469..000000000000 --- a/src/bundler/linker_context/findImportedCSSFilesInJSOrder.zig +++ /dev/null @@ -1,103 +0,0 @@ -/// JavaScript modules are traversed in depth-first postorder. This is the -/// order that JavaScript modules were evaluated in before the top-level await -/// feature was introduced. -/// -/// A -/// / \ -/// B C -/// \ / -/// D -/// -/// If A imports B and then C, B imports D, and C imports D, then the JavaScript -/// traversal order is D B C A. -/// -/// This function may deviate from ESM import order for dynamic imports (both -/// "require()" and "import()"). This is because the import order is impossible -/// to determine since the imports happen at run-time instead of compile-time. -/// In this case we just pick an arbitrary but consistent order. -pub fn findImportedCSSFilesInJSOrder(this: *LinkerContext, temp_allocator: std.mem.Allocator, entry_point: Index) BabyList(Index) { - var visited = bun.handleOom(BitSet.initEmpty(temp_allocator, this.graph.files.len)); - var order: BabyList(Index) = .{}; - - const all_import_records = this.graph.ast.items(.import_records); - const all_loaders = this.parse_graph.input_files.items(.loader); - const all_parts = this.graph.ast.items(.parts); - - const visit = struct { - fn visit( - c: *LinkerContext, - import_records: []const BabyList(ImportRecord), - parts: []const Part.List, - loaders: []const Loader, - temp: std.mem.Allocator, - visits: *BitSet, - o: *BabyList(Index), - source_index: Index, - is_css: bool, - ) void { - if (visits.isSet(source_index.get())) return; - visits.set(source_index.get()); - - const records: []ImportRecord = import_records[source_index.get()].slice(); - const p = &parts[source_index.get()]; - - // Iterate over each part in the file in order - for (p.sliceConst()) |part| { - // Traverse any files imported by this part. Note that CommonJS calls - // to "require()" count as imports too, sort of as if the part has an - // ESM "import" statement in it. This may seem weird because ESM imports - // are a compile-time concept while CommonJS imports are a run-time - // concept. But we don't want to manipulate 0) - Chunk.IntermediateOutput.allocatorForSize(buf.len).free(@constCast(buf)); - } - } - bun.default_allocator.free(scc); - }; - - if (is_standalone) { - const scc = bun.handleOom(bun.default_allocator.alloc(?[]const u8, chunks.len)); - @memset(scc, null); - standalone_chunk_contents = scc; - - for (chunks, 0..) |*chunk_item, ci| { - if (chunk_item.content == .html) continue; - var ds: usize = 0; - // Pass `scc` so that `.asset` pieces (e.g. `import logo from "./logo.svg"` with - // the file loader) are resolved to data: URIs from `url_for_css` instead of - // being written as paths to sidecar files that don't exist in standalone mode. - // Sibling JS/CSS chunks may still be null at this point; `.chunk` pieces fall - // back to file paths when their entry in `scc` is null, matching the previous - // behavior for inter-chunk imports. - scc[ci] = (chunk_item.intermediate_output.codeStandalone( - null, - c.parse_graph, - &c.graph, - c.options.public_path, - chunk_item, - chunks, - &ds, - false, - false, - scc, - ) catch |err| bun.handleOom(err)).buffer; - } - } - - // Don't write to disk if compile mode is enabled - we need buffer values for compilation - const is_compile = bundler.transpiler.options.compile; - if (root_path.len > 0 and !is_compile) { - try c.writeOutputFilesToDisk(root_path, chunks, &output_files, standalone_chunk_contents); - } else { - // In-memory build (also used for standalone mode) - for (chunks, 0..) |*chunk, chunk_index_in_chunks_list| { - // In standalone mode, non-HTML chunks were already resolved in the first pass. - // Insert a placeholder output file to keep chunk indices aligned. - if (is_standalone and chunk.content != .html) { - _ = output_files.insertForChunk(options.OutputFile.init(.{ - .data = .{ .buffer = .{ .data = &.{}, .allocator = bun.default_allocator } }, - .hash = null, - .loader = chunk.content.loader(), - .input_path = "", - .display_size = 0, - .output_kind = .chunk, - .input_loader = .js, - .output_path = "", - .is_executable = false, - .source_map_index = null, - .bytecode_index = null, - .module_info_index = null, - .side = .client, - .entry_point_index = null, - .referenced_css_chunks = &.{}, - .bake_extra = .{}, - })); - continue; - } - - var display_size: usize = 0; - - const public_path = if (chunk.flags.is_browser_chunk_from_server_build) - bundler.transpilerForTarget(.browser).options.public_path - else - c.options.public_path; - - const _code_result = if (is_standalone and chunk.content == .html) - chunk.intermediate_output.codeStandalone( - null, - c.parse_graph, - &c.graph, - public_path, - chunk, - chunks, - &display_size, - false, - false, - standalone_chunk_contents.?, - ) - else - chunk.intermediate_output.code( - null, - c.parse_graph, - &c.graph, - public_path, - chunk, - chunks, - &display_size, - c.resolver.opts.compile and !chunk.flags.is_browser_chunk_from_server_build, - chunk.content.sourcemap(c.options.source_maps) != .none, - ); - var code_result = _code_result catch |err| bun.handleOom(err); - - var sourcemap_output_file: ?options.OutputFile = null; - const input_path = try bun.default_allocator.dupe( - u8, - if (chunk.entry_point.is_entry_point) - c.parse_graph.input_files.items(.source)[chunk.entry_point.source_index].path.text - else - chunk.final_rel_path, - ); - - switch (chunk.content.sourcemap(c.options.source_maps)) { - .external, .linked => |tag| { - const output_source_map = chunk.output_source_map.finalize(bun.default_allocator, code_result.shifts) catch @panic("Failed to allocate memory for external source map"); - var source_map_final_rel_path = bun.handleOom(bun.default_allocator.alloc(u8, chunk.final_rel_path.len + ".map".len)); - bun.copy(u8, source_map_final_rel_path, chunk.final_rel_path); - bun.copy(u8, source_map_final_rel_path[chunk.final_rel_path.len..], ".map"); - - if (tag == .linked) { - const a, const b = if (public_path.len > 0) - cheapPrefixNormalizer(public_path, source_map_final_rel_path) - else - .{ "", std.fs.path.basename(source_map_final_rel_path) }; - - const source_map_start = "//# sourceMappingURL="; - const total_len = code_result.buffer.len + source_map_start.len + a.len + b.len + "\n".len; - var buf = std.array_list.Managed(u8).initCapacity(Chunk.IntermediateOutput.allocatorForSize(total_len), total_len) catch @panic("Failed to allocate memory for output file with inline source map"); - buf.appendSliceAssumeCapacity(code_result.buffer); - buf.appendSliceAssumeCapacity(source_map_start); - buf.appendSliceAssumeCapacity(a); - buf.appendSliceAssumeCapacity(b); - buf.appendAssumeCapacity('\n'); - - Chunk.IntermediateOutput.allocatorForSize(code_result.buffer.len).free(code_result.buffer); - code_result.buffer = buf.items; - } - - sourcemap_output_file = options.OutputFile.init(.{ - .data = .{ - .buffer = .{ - .data = output_source_map, - .allocator = bun.default_allocator, - }, - }, - .hash = null, - .loader = .json, - .input_loader = .file, - .output_path = source_map_final_rel_path, - .output_kind = .sourcemap, - .input_path = try strings.concat(bun.default_allocator, &.{ input_path, ".map" }), - .side = null, - .entry_point_index = null, - .is_executable = false, - }); - }, - .@"inline" => { - const output_source_map = chunk.output_source_map.finalize(bun.default_allocator, code_result.shifts) catch @panic("Failed to allocate memory for external source map"); - defer bun.default_allocator.free(output_source_map); - const encode_len = base64.encodeLen(output_source_map); - - const source_map_start = "//# sourceMappingURL=data:application/json;base64,"; - const total_len = code_result.buffer.len + source_map_start.len + encode_len + 1; - var buf = std.array_list.Managed(u8).initCapacity(Chunk.IntermediateOutput.allocatorForSize(total_len), total_len) catch @panic("Failed to allocate memory for output file with inline source map"); - - buf.appendSliceAssumeCapacity(code_result.buffer); - buf.appendSliceAssumeCapacity(source_map_start); - - buf.items.len += encode_len; - _ = base64.encode(buf.items[buf.items.len - encode_len ..], output_source_map); - - buf.appendAssumeCapacity('\n'); - Chunk.IntermediateOutput.allocatorForSize(code_result.buffer.len).free(code_result.buffer); - code_result.buffer = buf.items; - }, - .none => {}, - } - - // Compute side early so it can be used for bytecode, module_info, and main chunk output files - const side: bun.bake.Side = if (chunk.content == .css or chunk.flags.is_browser_chunk_from_server_build) - .client - else switch (c.graph.ast.items(.target)[chunk.entry_point.source_index]) { - .browser => .client, - else => .server, - }; - - const bytecode_output_file: ?options.OutputFile = brk: { - if (c.options.generate_bytecode_cache) { - const loader: Loader = if (chunk.entry_point.is_entry_point) - c.parse_graph.input_files.items(.loader)[ - chunk.entry_point.source_index - ] - else - .js; - - if (chunk.content == .javascript and loader.isJavaScriptLike()) { - jsc.VirtualMachine.is_bundler_thread_for_bytecode_cache = true; - jsc.initialize(false); - var fdpath: bun.PathBuffer = undefined; - // For --compile builds, the bytecode URL must match the module name - // that will be used at runtime. The module name is: - // public_path + final_rel_path (e.g., "/$bunfs/root/app.js") - // Without this prefix, the JSC bytecode cache key won't match at runtime. - // Use the per-chunk public_path (already computed above) for browser chunks - // from server builds, and normalize with cheapPrefixNormalizer for consistency - // with module_info path fixup. - // For non-compile builds, use the normal .jsc extension. - var source_provider_url = if (c.options.compile) url_blk: { - const normalizer = bun.bundle_v2.cheapPrefixNormalizer(public_path, chunk.final_rel_path); - break :url_blk try bun.String.createFormat("{s}{s}", .{ normalizer[0], normalizer[1] }); - } else try bun.String.createFormat("{s}" ++ bun.bytecode_extension, .{chunk.final_rel_path}); - source_provider_url.ref(); - - defer source_provider_url.deref(); - - if (jsc.CachedBytecode.generate(c.options.output_format, code_result.buffer, &source_provider_url)) |result| { - const bytecode, const cached_bytecode = result; - const source_provider_url_str = source_provider_url.toSlice(bun.default_allocator); - defer source_provider_url_str.deinit(); - debug("Bytecode cache generated {s}: {f}", .{ source_provider_url_str.slice(), bun.fmt.size(bytecode.len, .{ .space_between_number_and_unit = true }) }); - @memcpy(fdpath[0..chunk.final_rel_path.len], chunk.final_rel_path); - fdpath[chunk.final_rel_path.len..][0..bun.bytecode_extension.len].* = bun.bytecode_extension.*; - - break :brk options.OutputFile.init(.{ - .output_path = bun.handleOom(bun.default_allocator.dupe(u8, source_provider_url_str.slice())), - .input_path = bun.handleOom(std.fmt.allocPrint(bun.default_allocator, "{s}" ++ bun.bytecode_extension, .{chunk.final_rel_path})), - .input_loader = .js, - .hash = if (chunk.template.placeholder.hash != null) bun.hash(bytecode) else null, - .output_kind = .bytecode, - .loader = .file, - .size = @as(u32, @truncate(bytecode.len)), - .display_size = @as(u32, @truncate(bytecode.len)), - .data = .{ - .buffer = .{ .data = bytecode, .allocator = cached_bytecode.allocator() }, - }, - .side = side, - .entry_point_index = null, - .is_executable = false, - }); - } else { - // an error - c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "Failed to generate bytecode for {s}", .{ - chunk.final_rel_path, - }) catch |err| bun.handleOom(err); - } - } - } - - break :brk null; - }; - - // Create module_info output file for ESM bytecode in --compile builds - const module_info_output_file: ?options.OutputFile = brk: { - if (c.options.generate_bytecode_cache and c.options.output_format == .esm and c.options.compile) { - const loader: Loader = if (chunk.entry_point.is_entry_point) - c.parse_graph.input_files.items(.loader)[ - chunk.entry_point.source_index - ] - else - .js; - - if (chunk.content == .javascript and loader.isJavaScriptLike()) { - if (chunk.content.javascript.module_info_bytes) |module_info_bytes| { - break :brk options.OutputFile.init(.{ - .output_path = bun.handleOom(std.fmt.allocPrint(bun.default_allocator, "{s}.module-info", .{chunk.final_rel_path})), - .input_path = bun.handleOom(std.fmt.allocPrint(bun.default_allocator, "{s}.module-info", .{chunk.final_rel_path})), - .input_loader = .js, - .hash = if (chunk.template.placeholder.hash != null) bun.hash(module_info_bytes) else null, - .output_kind = .module_info, - .loader = .file, - .size = @as(u32, @truncate(module_info_bytes.len)), - .display_size = @as(u32, @truncate(module_info_bytes.len)), - .data = .{ - .buffer = .{ .data = module_info_bytes, .allocator = bun.default_allocator }, - }, - .side = side, - .entry_point_index = null, - .is_executable = false, - }); - } - } - } - break :brk null; - }; - - const source_map_index: ?u32 = if (sourcemap_output_file != null) - try output_files.insertForSourcemapOrBytecode(sourcemap_output_file.?) - else - null; - - const bytecode_index: ?u32 = if (bytecode_output_file != null) - try output_files.insertForSourcemapOrBytecode(bytecode_output_file.?) - else - null; - - const module_info_index: ?u32 = if (module_info_output_file != null) - try output_files.insertForSourcemapOrBytecode(module_info_output_file.?) - else - null; - - const output_kind = if (chunk.content == .css) - .asset - else if (chunk.entry_point.is_entry_point) - c.graph.files.items(.entry_point_kind)[chunk.entry_point.source_index].outputKind() - else - .chunk; - - const chunk_index = output_files.insertForChunk(options.OutputFile.init(.{ - .data = .{ - .buffer = .{ - .data = code_result.buffer, - .allocator = Chunk.IntermediateOutput.allocatorForSize(code_result.buffer.len), - }, - }, - .hash = chunk.template.placeholder.hash, - .loader = chunk.content.loader(), - .input_path = input_path, - .display_size = @as(u32, @truncate(display_size)), - .output_kind = output_kind, - .input_loader = if (chunk.entry_point.is_entry_point) c.parse_graph.input_files.items(.loader)[chunk.entry_point.source_index] else .js, - .output_path = try bun.default_allocator.dupe(u8, chunk.final_rel_path), - .is_executable = chunk.flags.is_executable, - .source_map_index = source_map_index, - .bytecode_index = bytecode_index, - .module_info_index = module_info_index, - .side = side, - .entry_point_index = if (output_kind == .@"entry-point") - chunk.entry_point.source_index - @as(u32, (if (c.framework) |fw| if (fw.server_components != null) 3 else 1 else 1)) - else - null, - .referenced_css_chunks = switch (chunk.content) { - .javascript => |js| @ptrCast(try bun.default_allocator.dupe(u32, js.css_chunks)), - .css => &.{}, - .html => &.{}, - }, - .bake_extra = brk: { - if (c.framework == null or is_dev_server) break :brk .{}; - if (!c.framework.?.is_built_in_react) break :brk .{}; - - var extra: OutputFile.BakeExtra = .{}; - extra.bake_is_runtime = chunk.files_with_parts_in_chunk.contains(Index.runtime.get()); - if (output_kind == .@"entry-point" and side == .server) { - extra.is_route = true; - extra.fully_static = !static_route_visitor.hasTransitiveUseClient(chunk.entry_point.source_index); - } - - break :brk extra; - }, - })); - - // We want the chunk index to remain the same in `output_files` so the indices in `OutputFile.referenced_css_chunks` work - bun.assertf(chunk_index == chunk_index_in_chunks_list, "chunk_index ({d}) != chunk_index_in_chunks_list ({d})", .{ chunk_index, chunk_index_in_chunks_list }); - } - - if (!is_standalone) { - output_files.insertAdditionalOutputFiles(c.parse_graph.additional_output_files.items); - } - } - - if (is_standalone) { - // For standalone mode, filter to only HTML output files. - // Deinit dropped items to free their heap allocations (paths, buffers). - var result = output_files.take(); - var write_idx: usize = 0; - for (result.items) |*item| { - if (item.loader == .html) { - result.items[write_idx] = item.*; - write_idx += 1; - } else { - item.deinit(); - } - } - result.items.len = write_idx; - return result; - } - - return output_files.take(); -} - -pub const ThreadPool = bun.bundle_v2.ThreadPool; - -const debugPartRanges = Output.scoped(.PartRanges, .hidden); - -const analyze_transpiled_module = @import("../analyze_transpiled_module.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const Loader = bun.Loader; -const Output = bun.Output; -const ThreadPoolLib = bun.ThreadPool; -const base64 = bun.base64; -const jsc = bun.jsc; -const strings = bun.strings; -const AutoBitSet = bun.bit_set.AutoBitSet; - -const Chunk = bun.bundle_v2.Chunk; -const ContentHasher = bun.bundle_v2.ContentHasher; -const Index = bun.bundle_v2.Index; -const Part = bun.bundle_v2.Part; -const cheapPrefixNormalizer = bun.bundle_v2.cheapPrefixNormalizer; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const CompileResult = LinkerContext.CompileResult; -const GenerateChunkCtx = LinkerContext.GenerateChunkCtx; -const OutputFileListBuilder = bun.bundle_v2.LinkerContext.OutputFileListBuilder; -const PendingPartRange = LinkerContext.PendingPartRange; -const StaticRouteVisitor = bun.bundle_v2.LinkerContext.StaticRouteVisitor; -const debug = LinkerContext.debug; -const generateChunk = LinkerContext.generateChunk; -const generateCompileResultForCssChunk = LinkerContext.generateCompileResultForCssChunk; -const generateCompileResultForHtmlChunk = LinkerContext.generateCompileResultForHtmlChunk; -const generateCompileResultForJSChunk = LinkerContext.generateCompileResultForJSChunk; - -const Logger = bun.logger; -const Loc = Logger.Loc; - -const options = bun.options; -const OutputFile = bun.options.OutputFile; diff --git a/src/bundler/linker_context/generateCodeForFileInChunkJS.zig b/src/bundler/linker_context/generateCodeForFileInChunkJS.zig deleted file mode 100644 index c26d827b83b6..000000000000 --- a/src/bundler/linker_context/generateCodeForFileInChunkJS.zig +++ /dev/null @@ -1,802 +0,0 @@ -pub fn generateCodeForFileInChunkJS( - c: *LinkerContext, - writer: *js_printer.BufferWriter, - r: renamer.Renamer, - chunk: *Chunk, - part_range: PartRange, - toCommonJSRef: Ref, - toESMRef: Ref, - runtimeRequireRef: ?Ref, - stmts: *StmtList, - allocator: std.mem.Allocator, - temp_allocator: std.mem.Allocator, - decl_collector: ?*DeclCollector, -) js_printer.PrintResult { - const parts: []Part = c.graph.ast.items(.parts)[part_range.source_index.get()].slice()[part_range.part_index_begin..part_range.part_index_end]; - const all_flags: []const JSMeta.Flags = c.graph.meta.items(.flags); - const flags = all_flags[part_range.source_index.get()]; - const wrapper_part_index = if (flags.wrap != .none) - c.graph.meta.items(.wrapper_part_index)[part_range.source_index.get()] - else - Index.invalid; - - // referencing everything by array makes the code a lot more annoying :( - var ast: JSAst = c.graph.ast.get(part_range.source_index.get()); - - // For HMR, part generation is entirely special cased. - // - export wrapping is already done. - // - imports are split from the main code. - // - one part range per file - if (c.options.output_format == .internal_bake_dev) brk: { - if (part_range.source_index.isRuntime()) { - @branchHint(.cold); - bun.debugAssert(c.dev_server == null); - break :brk; // this is from `bun build --format=internal_bake_dev` - } - - const hmr_api_ref = ast.wrapper_ref; - - for (parts) |part| { - c.convertStmtsForChunkForDevServer(stmts, part.stmts, allocator, &ast) catch |err| - return .{ .err = err }; - } - - const main_stmts_len = stmts.inside_wrapper_prefix.stmts.items.len + stmts.inside_wrapper_suffix.items.len; - const all_stmts_len = main_stmts_len + stmts.outside_wrapper_prefix.items.len + 1; - - bun.handleOom(stmts.all_stmts.ensureUnusedCapacity(stmts.allocator, all_stmts_len)); - stmts.all_stmts.appendSliceAssumeCapacity(stmts.inside_wrapper_prefix.stmts.items); - stmts.all_stmts.appendSliceAssumeCapacity(stmts.inside_wrapper_suffix.items); - - const inner = stmts.all_stmts.items[0..main_stmts_len]; - - var clousure_args = bun.BoundedArray(G.Arg, 3).fromSlice(&.{ - .{ .binding = Binding.alloc(temp_allocator, B.Identifier{ - .ref = hmr_api_ref, - }, Logger.Loc.Empty) }, - }) catch unreachable; // is within bounds - - if (ast.flags.uses_module_ref or ast.flags.uses_exports_ref) { - clousure_args.appendSliceAssumeCapacity(&.{ - .{ - .binding = Binding.alloc(temp_allocator, B.Identifier{ - .ref = ast.module_ref, - }, Logger.Loc.Empty), - }, - .{ - .binding = Binding.alloc(temp_allocator, B.Identifier{ - .ref = ast.exports_ref, - }, Logger.Loc.Empty), - }, - }); - } - - stmts.all_stmts.appendAssumeCapacity(Stmt.allocateExpr(temp_allocator, Expr.init(E.Function, .{ .func = .{ - .args = bun.handleOom(temp_allocator.dupe(G.Arg, clousure_args.slice())), - .body = .{ - .stmts = inner, - .loc = Logger.Loc.Empty, - }, - } }, Logger.Loc.Empty))); - stmts.all_stmts.appendSliceAssumeCapacity(stmts.outside_wrapper_prefix.items); - - ast.flags.uses_module_ref = true; - - // TODO: there is a weird edge case where the pretty path is not computed - // it does not reproduce when debugging. - var source = c.getSource(part_range.source_index.get()).*; - if (source.path.text.ptr == source.path.pretty.ptr) { - source.path = genericPathWithPrettyInitialized( - source.path, - c.options.target, - c.resolver.fs.top_level_dir, - allocator, - ) catch |err| bun.handleOom(err); - } - - return c.printCodeForFileInChunkJS( - r, - allocator, - writer, - stmts.all_stmts.items[main_stmts_len..], - &ast, - flags, - .None, - .None, - null, - part_range.source_index, - &source, - ); - } - - var needs_wrapper = false; - - const namespace_export_part_index = js_ast.namespace_export_part_index; - - stmts.reset(); - - const part_index_for_lazy_default_export: u32 = brk: { - if (ast.flags.has_lazy_export) { - if (c.graph.meta.items(.resolved_exports)[part_range.source_index.get()].get("default")) |default| { - break :brk c.graph.topLevelSymbolToParts(part_range.source_index.get(), default.data.import_ref)[0]; - } - } - break :brk std.math.maxInt(u32); - }; - - const output_format = c.options.output_format; - - // The top-level directive must come first (the non-wrapped case is handled - // by the chunk generation code, although only for the entry point) - if (flags.wrap != .none and ast.flags.has_explicit_use_strict_directive and !chunk.isEntryPoint() and !output_format.isAlwaysStrictMode()) { - stmts.inside_wrapper_prefix.appendNonDependency(Stmt.alloc(S.Directive, .{ - .value = "use strict", - }, Logger.Loc.Empty)) catch unreachable; - } - - // TODO: handle directive - if (namespace_export_part_index >= part_range.part_index_begin and - namespace_export_part_index < part_range.part_index_end and - parts[namespace_export_part_index].is_live) - { - c.convertStmtsForChunk( - part_range.source_index.get(), - stmts, - parts[namespace_export_part_index].stmts, - chunk, - temp_allocator, - flags.wrap, - &ast, - ) catch |err| { - bun.handleErrorReturnTrace(err, @errorReturnTrace()); - return .{ .err = err }; - }; - - switch (flags.wrap) { - .esm => { - stmts.appendSlice(.outside_wrapper_prefix, stmts.inside_wrapper_suffix.items) catch unreachable; - }, - else => { - stmts.inside_wrapper_prefix.appendNonDependencySlice(stmts.inside_wrapper_suffix.items) catch unreachable; - }, - } - - stmts.inside_wrapper_suffix.clearRetainingCapacity(); - } - - // Add all other parts in this chunk - for (parts, 0..) |part, index_| { - const index = part_range.part_index_begin + @as(u32, @truncate(index_)); - if (!part.is_live) { - // Skip the part if it's not in this chunk - continue; - } - - if (index == namespace_export_part_index) { - // Skip the namespace export part because we already handled it above - continue; - } - - if (index == wrapper_part_index.get()) { - // Skip the wrapper part because we already handled it above - needs_wrapper = true; - continue; - } - - var single_stmts_list = [1]Stmt{undefined}; - var part_stmts = part.stmts; - - // If this could be a JSON or TOML file that exports a top-level object literal, go - // over the non-default top-level properties that ended up being imported - // and substitute references to them into the main top-level object literal. - // So this JSON file: - // - // { - // "foo": [1, 2, 3], - // "bar": [4, 5, 6], - // } - // - // is initially compiled into this: - // - // export var foo = [1, 2, 3]; - // export var bar = [4, 5, 6]; - // export default { - // foo: [1, 2, 3], - // bar: [4, 5, 6], - // }; - // - // But we turn it into this if both "foo" and "default" are imported: - // - // export var foo = [1, 2, 3]; - // export default { - // foo, - // bar: [4, 5, 6], - // }; - // - if (index == part_index_for_lazy_default_export) { - bun.assert(index != std.math.maxInt(u32)); - - const stmt = part_stmts[0]; - - if (stmt.data != .s_export_default) - @panic("expected Lazy default export to be an export default statement"); - - const default_export = stmt.data.s_export_default; - var default_expr = default_export.value.expr; - - // Be careful: the top-level value in a JSON file is not necessarily an object - if (default_expr.data == .e_object) { - var new_properties = default_expr.data.e_object.properties.clone(temp_allocator) catch unreachable; - - var resolved_exports = c.graph.meta.items(.resolved_exports)[part_range.source_index.get()]; - - // If any top-level properties ended up being imported directly, change - // the property to just reference the corresponding variable instead - for (new_properties.slice()) |*prop| { - if (prop.key == null or prop.key.?.data != .e_string or prop.value == null) continue; - const name = prop.key.?.data.e_string.slice(temp_allocator); - if (strings.eqlComptime(name, "default") or - strings.eqlComptime(name, "__esModule") or - !bun.js_lexer.isIdentifier(name)) continue; - - if (resolved_exports.get(name)) |export_data| { - const export_ref = export_data.data.import_ref; - const export_part = ast.parts.slice()[c.graph.topLevelSymbolToParts(part_range.source_index.get(), export_ref)[0]]; - if (export_part.is_live) { - prop.* = .{ - .key = prop.key, - .value = Expr.initIdentifier(export_ref, prop.value.?.loc), - }; - } - } - } - - default_expr = Expr.allocate( - temp_allocator, - E.Object, - E.Object{ - .properties = new_properties, - }, - default_expr.loc, - ); - } - - single_stmts_list[0] = Stmt.allocate( - temp_allocator, - S.ExportDefault, - .{ - .default_name = default_export.default_name, - .value = .{ .expr = default_expr }, - }, - stmt.loc, - ); - part_stmts = single_stmts_list[0..]; - } - - c.convertStmtsForChunk( - part_range.source_index.get(), - stmts, - part_stmts, - chunk, - temp_allocator, - flags.wrap, - &ast, - ) catch |err| return .{ - .err = err, - }; - } - - // Hoist all import statements before any normal statements. ES6 imports - // are different than CommonJS imports. All modules imported via ES6 import - // statements are evaluated before the module doing the importing is - // evaluated (well, except for cyclic import scenarios). We need to preserve - // these semantics even when modules imported via ES6 import statements end - // up being CommonJS modules. - stmts.all_stmts.ensureUnusedCapacity(stmts.allocator, stmts.inside_wrapper_prefix.stmts.items.len + stmts.inside_wrapper_suffix.items.len) catch unreachable; - stmts.all_stmts.appendSliceAssumeCapacity(stmts.inside_wrapper_prefix.stmts.items); - stmts.all_stmts.appendSliceAssumeCapacity(stmts.inside_wrapper_suffix.items); - stmts.inside_wrapper_prefix.reset(); - stmts.inside_wrapper_suffix.clearRetainingCapacity(); - - if (c.options.minify_syntax) { - mergeAdjacentLocalStmts(&stmts.all_stmts, temp_allocator); - } - - var out_stmts: []js_ast.Stmt = stmts.all_stmts.items; - - // Optionally wrap all statements in a closure - if (needs_wrapper) { - switch (flags.wrap) { - .cjs => { - // Only include the arguments that are actually used - var args = std.array_list.Managed(G.Arg).initCapacity( - temp_allocator, - if (ast.flags.uses_module_ref or ast.flags.uses_exports_ref) 2 else 0, - ) catch unreachable; - - if (ast.flags.uses_module_ref or ast.flags.uses_exports_ref) { - args.appendAssumeCapacity( - G.Arg{ - .binding = Binding.alloc( - temp_allocator, - B.Identifier{ - .ref = ast.exports_ref, - }, - Logger.Loc.Empty, - ), - }, - ); - - if (ast.flags.uses_module_ref) { - args.appendAssumeCapacity( - G.Arg{ - .binding = Binding.alloc( - temp_allocator, - B.Identifier{ - .ref = ast.module_ref, - }, - Logger.Loc.Empty, - ), - }, - ); - } - } - - // TODO: variants of the runtime functions - var cjs_args = temp_allocator.alloc(Expr, 1) catch unreachable; - cjs_args[0] = Expr.init( - E.Arrow, - E.Arrow{ - .args = args.items, - .body = .{ - .stmts = stmts.all_stmts.items, - .loc = Logger.Loc.Empty, - }, - }, - Logger.Loc.Empty, - ); - - const commonjs_wrapper_definition = Expr.init( - E.Call, - E.Call{ - .target = Expr.init( - E.Identifier, - E.Identifier{ - .ref = c.cjs_runtime_ref, - }, - Logger.Loc.Empty, - ), - .args = bun.BabyList(Expr).fromOwnedSlice(cjs_args), - }, - Logger.Loc.Empty, - ); - - // "var require_foo = __commonJS(...);" - { - var decls = temp_allocator.alloc(G.Decl, 1) catch unreachable; - decls[0] = G.Decl{ - .binding = Binding.alloc( - temp_allocator, - B.Identifier{ - .ref = ast.wrapper_ref, - }, - Logger.Loc.Empty, - ), - .value = commonjs_wrapper_definition, - }; - - stmts.append( - .outside_wrapper_prefix, - Stmt.alloc( - S.Local, - S.Local{ - .decls = G.Decl.List.fromOwnedSlice(decls), - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - } - }, - .esm => { - // The wrapper only needs to be "async" if there is a transitive async - // dependency. For correctness, we must not use "async" if the module - // isn't async because then calling "require()" on that module would - // swallow any exceptions thrown during module initialization. - const is_async = flags.is_async_or_has_async_dependency; - - const ExportHoist = struct { - decls: std.ArrayListUnmanaged(G.Decl), - allocator: std.mem.Allocator, - - pub fn wrapIdentifier(w: *@This(), loc: Logger.Loc, ref: Ref) Expr { - w.decls.append( - w.allocator, - .{ - .binding = Binding.alloc( - w.allocator, - B.Identifier{ - .ref = ref, - }, - loc, - ), - .value = null, - }, - ) catch |err| bun.handleOom(err); - - return Expr.initIdentifier(ref, loc); - } - }; - - var hoist = ExportHoist{ - .decls = .{}, - .allocator = temp_allocator, - }; - - var inner_stmts = stmts.all_stmts.items; - - // Hoist all top-level "var" and "function" declarations out of the closure - { - var end: usize = 0; - for (stmts.all_stmts.items) |stmt| { - const transformed = switch (stmt.data) { - .s_local => |local| stmt: { - // "using" / "await using" declarations have disposal - // side-effects tied to the scope they appear in, so - // they must stay inside the closure rather than being - // hoisted to `var` + assignment. - if (local.kind.isUsing()) { - break :stmt stmt; - } - - // Convert the declarations to assignments - var value = Expr.empty; - for (local.decls.slice()) |*decl| { - if (decl.value) |initializer| { - const can_be_moved = initializer.canBeMoved(); - if (can_be_moved) { - // if the value can be moved, move the decl directly to preserve destructuring - // ie `const { main } = class { static main() {} }` => `var {main} = class { static main() {} }` - bun.handleOom(hoist.decls.append(hoist.allocator, decl.*)); - } else { - // if the value cannot be moved, add every destructuring key separately - // ie `var { append } = { append() {} }` => `var append; __esm(() => ({ append } = { append() {} }))` - const binding = decl.binding.toExpr(&hoist); - value = value.joinWithComma( - binding.assign(initializer), - temp_allocator, - ); - } - } else { - _ = decl.binding.toExpr(&hoist); - } - } - - if (value.isEmpty()) { - continue; - } - - break :stmt Stmt.allocateExpr(temp_allocator, value); - }, - .s_function => { - bun.handleOom(stmts.append(.outside_wrapper_prefix, stmt)); - continue; - }, - .s_class => |class| stmt: { - if (class.class.canBeMoved()) { - bun.handleOom(stmts.append(.outside_wrapper_prefix, stmt)); - continue; - } - - break :stmt Stmt.allocateExpr( - temp_allocator, - Expr.assign(hoist.wrapIdentifier( - class.class.class_name.?.loc, - class.class.class_name.?.ref.?, - ), .{ - .data = .{ .e_class = &class.class }, - .loc = stmt.loc, - }), - ); - }, - else => stmt, - }; - - inner_stmts[end] = transformed; - end += 1; - } - inner_stmts.len = end; - } - - if (hoist.decls.items.len > 0) { - stmts.append( - .outside_wrapper_prefix, - Stmt.alloc( - S.Local, - S.Local{ - .decls = G.Decl.List.moveFromList(&hoist.decls), - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - hoist.decls.items.len = 0; - } - - if (inner_stmts.len > 0) { - // See the comment in needsWrapperRef for why the symbol - // is sometimes not generated. - bun.assert(!ast.wrapper_ref.isEmpty()); // js_parser's needsWrapperRef thought wrapper was not needed - - // "__esm(() => { ... })" - var esm_args = bun.handleOom(temp_allocator.alloc(Expr, 1)); - esm_args[0] = Expr.init(E.Arrow, .{ - .args = &.{}, - .is_async = is_async, - .body = .{ - .stmts = inner_stmts, - .loc = Logger.Loc.Empty, - }, - }, Logger.Loc.Empty); - - // "var init_foo = __esm(...);" - const value = Expr.init(E.Call, .{ - .target = Expr.initIdentifier(c.esm_runtime_ref, Logger.Loc.Empty), - .args = bun.BabyList(Expr).fromOwnedSlice(esm_args), - }, Logger.Loc.Empty); - - var decls = bun.handleOom(temp_allocator.alloc(G.Decl, 1)); - decls[0] = G.Decl{ - .binding = Binding.alloc( - temp_allocator, - B.Identifier{ - .ref = ast.wrapper_ref, - }, - Logger.Loc.Empty, - ), - .value = value, - }; - - stmts.append( - .outside_wrapper_prefix, - Stmt.alloc(S.Local, .{ - .decls = G.Decl.List.fromOwnedSlice(decls), - }, Logger.Loc.Empty), - ) catch |err| bun.handleOom(err); - } else { - // // If this fails, then there will be places we reference - // // `init_foo` without it actually existing. - // bun.assert(ast.wrapper_ref.isEmpty()); - - // TODO: the edge case where we are wrong is when there - // are references to other ESM modules, but those get - // fully hoisted. The look like side effects, but they - // are removed. - // - // It is too late to retroactively delete the - // wrapper_ref, since printing has already begun. The - // most we can do to salvage the situation is to print - // an empty arrow function. - // - // This is marked as a TODO, because this can be solved - // via a count of external modules, decremented during - // linking. - if (!ast.wrapper_ref.isEmpty()) { - const value = Expr.init(E.Arrow, .{ - .args = &.{}, - .is_async = is_async, - .body = .{ - .stmts = inner_stmts, - .loc = Logger.Loc.Empty, - }, - }, Logger.Loc.Empty); - - stmts.append( - .outside_wrapper_prefix, - Stmt.alloc(S.Local, .{ - .decls = G.Decl.List.fromSlice(temp_allocator, &.{.{ - .binding = Binding.alloc( - temp_allocator, - B.Identifier{ - .ref = ast.wrapper_ref, - }, - Logger.Loc.Empty, - ), - .value = value, - }}) catch |err| bun.handleOom(err), - }, Logger.Loc.Empty), - ) catch |err| bun.handleOom(err); - } - } - }, - else => {}, - } - - out_stmts = stmts.outside_wrapper_prefix.items; - } - - if (out_stmts.len == 0) { - return .{ - .result = .{ - .code = "", - .source_map = null, - }, - }; - } - - // Collect top-level declarations from the converted statements. - // This is done here (after convertStmtsForChunk) rather than in - // postProcessJSChunk, because convertStmtsForChunk transforms the AST - // (e.g. export default expr → var, export stripping) and the converted - // statements reflect what actually gets printed. - if (decl_collector) |dc| { - dc.collectFromStmts(out_stmts, r, c); - } - - return c.printCodeForFileInChunkJS( - r, - allocator, - writer, - out_stmts, - &ast, - flags, - toESMRef, - toCommonJSRef, - runtimeRequireRef, - part_range.source_index, - c.getSource(part_range.source_index.get()), - ); -} - -pub const DeclCollector = struct { - decls: std.ArrayListUnmanaged(CompileResult.DeclInfo) = .{}, - allocator: std.mem.Allocator, - - const CompileResult = bun.bundle_v2.CompileResult; - - /// Collect top-level declarations from **converted** statements (after - /// `convertStmtsForChunk`). At that point, export statements have already - /// been transformed: - /// - `s_export_default` → `s_local` / `s_function` / `s_class` - /// - `s_export_clause` → removed entirely - /// - `s_export_from` / `s_export_star` → removed or converted to `s_import` - /// - /// Remaining `s_import` statements (external, non-bundled) don't need - /// handling here; their bindings are recorded separately in - /// `postProcessJSChunk` by scanning the original AST import records. - pub fn collectFromStmts(self: *DeclCollector, stmts: []const Stmt, r: renamer.Renamer, c: *LinkerContext) void { - for (stmts) |stmt| { - switch (stmt.data) { - .s_local => |s| { - const kind: CompileResult.DeclInfo.Kind = if (s.kind == .k_var) .declared else .lexical; - for (s.decls.slice()) |decl| { - self.collectFromBinding(decl.binding, kind, r, c); - } - }, - .s_function => |s| { - if (s.func.name) |name_loc_ref| { - if (name_loc_ref.ref) |name_ref| { - self.addRef(name_ref, .lexical, r, c); - } - } - }, - .s_class => |s| { - if (s.class.class_name) |class_name| { - if (class_name.ref) |name_ref| { - self.addRef(name_ref, .lexical, r, c); - } - } - }, - else => {}, - } - } - } - - fn collectFromBinding(self: *DeclCollector, binding: Binding, kind: CompileResult.DeclInfo.Kind, r: renamer.Renamer, c: *LinkerContext) void { - switch (binding.data) { - .b_identifier => |b| { - self.addRef(b.ref, kind, r, c); - }, - .b_array => |b| { - for (b.items) |item| { - self.collectFromBinding(item.binding, kind, r, c); - } - }, - .b_object => |b| { - for (b.properties) |prop| { - self.collectFromBinding(prop.value, kind, r, c); - } - }, - .b_missing => {}, - } - } - - fn addRef(self: *DeclCollector, ref: Ref, kind: CompileResult.DeclInfo.Kind, r: renamer.Renamer, c: *LinkerContext) void { - const followed = c.graph.symbols.follow(ref); - const name = r.nameForSymbol(followed); - if (name.len == 0) return; - self.decls.append(self.allocator, .{ .name = name, .kind = kind }) catch return; - } -}; - -fn mergeAdjacentLocalStmts(stmts: *std.ArrayListUnmanaged(Stmt), allocator: std.mem.Allocator) void { - if (stmts.items.len == 0) - return; - - var did_merge_with_previous_local = false; - var end: usize = 1; - - for (stmts.items[1..]) |stmt| { - // Try to merge with the previous variable statement - if (stmt.data == .s_local) { - var after = stmt.data.s_local; - if (stmts.items[end - 1].data == .s_local) { - var before = stmts.items[end - 1].data.s_local; - // It must be the same kind of variable statement (i.e. let/var/const) - if (before.canMergeWith(after)) { - if (did_merge_with_previous_local) { - // Avoid O(n^2) behavior for repeated variable declarations - // Appending to this decls list is safe because did_merge_with_previous_local is true - before.decls.appendSlice(allocator, after.decls.slice()) catch unreachable; - } else { - // Append the declarations to the previous variable statement - did_merge_with_previous_local = true; - - var clone = bun.BabyList(G.Decl).initCapacity(allocator, before.decls.len + after.decls.len) catch unreachable; - clone.appendSliceAssumeCapacity(before.decls.slice()); - clone.appendSliceAssumeCapacity(after.decls.slice()); - // we must clone instead of overwrite in-place incase the same S.Local is used across threads - // https://github.com/oven-sh/bun/issues/2942 - stmts.items[end - 1] = Stmt.allocate( - allocator, - S.Local, - S.Local{ - .decls = clone, - .is_export = before.is_export, - .was_commonjs_export = before.was_commonjs_export, - .was_ts_import_equals = before.was_ts_import_equals, - .kind = before.kind, - }, - stmts.items[end - 1].loc, - ); - } - continue; - } - } - } - - did_merge_with_previous_local = false; - stmts.items[end] = stmt; - end += 1; - } - stmts.items.len = end; -} - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const Logger = bun.logger; -const options = bun.options; -const strings = bun.strings; - -const Chunk = bun.bundle_v2.Chunk; -const Index = bun.bundle_v2.Index; -const JSAst = bun.bundle_v2.JSAst; -const JSMeta = bun.bundle_v2.JSMeta; -const Part = bun.bundle_v2.Part; -const PartRange = bun.bundle_v2.PartRange; -const genericPathWithPrettyInitialized = bun.bundle_v2.genericPathWithPrettyInitialized; -const js_printer = bun.bundle_v2.js_printer; -const renamer = bun.bundle_v2.renamer; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const StmtList = LinkerContext.StmtList; - -const js_ast = bun.bundle_v2.js_ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const Ref = bun.bundle_v2.js_ast.Ref; -const S = js_ast.S; -const Stmt = js_ast.Stmt; diff --git a/src/bundler/linker_context/generateCodeForLazyExport.zig b/src/bundler/linker_context/generateCodeForLazyExport.zig deleted file mode 100644 index 06f255e7a10f..000000000000 --- a/src/bundler/linker_context/generateCodeForLazyExport.zig +++ /dev/null @@ -1,421 +0,0 @@ -pub fn generateCodeForLazyExport(this: *LinkerContext, source_index: Index.Int) bun.OOM!void { - const exports_kind = this.graph.ast.items(.exports_kind)[source_index]; - const all_sources = this.parse_graph.input_files.items(.source); - const all_css_asts = this.graph.ast.items(.css); - const maybe_css_ast: ?*bun.css.BundlerStyleSheet = all_css_asts[source_index]; - var parts = &this.graph.ast.items(.parts)[source_index]; - - if (parts.len < 1) { - @panic("Internal error: expected at least one part for lazy export"); - } - - var part: *Part = &parts.ptr[1]; - - if (part.stmts.len == 0) { - @panic("Internal error: expected at least one statement in the lazy export"); - } - - const module_ref = this.graph.ast.items(.module_ref)[source_index]; - - // Handle css modules - // - // --- original comment from esbuild --- - // If this JavaScript file is a stub from a CSS file, populate the exports of - // this JavaScript stub with the local names from that CSS file. This is done - // now instead of earlier because we need the whole bundle to be present. - if (maybe_css_ast) |css_ast| { - const stmt: Stmt = part.stmts[0]; - if (stmt.data != .s_lazy_export) { - @panic("Internal error: expected top-level lazy export statement"); - } - if (css_ast.local_scope.count() > 0) out: { - var exports = E.Object{}; - - const symbols: *const Symbol.List = &this.graph.ast.items(.symbols)[source_index]; - const all_import_records: []const BabyList(bun.css.ImportRecord) = this.graph.ast.items(.import_records); - - const values = css_ast.local_scope.values(); - if (values.len == 0) break :out; - const size = size: { - var size: u32 = 0; - for (values) |entry| { - size = @max(size, entry.ref.inner_index); - } - break :size size + 1; - }; - - var inner_visited = try BitSet.initEmpty(this.allocator(), size); - defer inner_visited.deinit(this.allocator()); - var composes_visited = std.AutoArrayHashMap(bun.bundle_v2.Ref, void).init(this.allocator()); - defer composes_visited.deinit(); - - const Visitor = struct { - inner_visited: *BitSet, - composes_visited: *std.AutoArrayHashMap(bun.bundle_v2.Ref, void), - parts: *std.array_list.Managed(E.TemplatePart), - all_import_records: []const BabyList(bun.css.ImportRecord), - all_css_asts: []?*bun.css.BundlerStyleSheet, - all_sources: []const Logger.Source, - all_symbols: []const Symbol.List, - source_index: Index.Int, - log: *Logger.Log, - loc: Loc, - allocator: std.mem.Allocator, - - fn clearAll(visitor: *@This()) void { - visitor.inner_visited.setAll(false); - visitor.composes_visited.clearRetainingCapacity(); - } - - fn visitName(visitor: *@This(), ast: *bun.css.BundlerStyleSheet, ref: bun.css.CssRef, idx: Index.Int) void { - bun.assert(ref.canBeComposed()); - const from_this_file = ref.sourceIndex(idx) == visitor.source_index; - if ((from_this_file and visitor.inner_visited.isSet(ref.innerIndex())) or - (!from_this_file and visitor.composes_visited.contains(ref.toRealRef(idx)))) - { - return; - } - - visitor.visitComposes(ast, ref, idx); - visitor.parts.append(E.TemplatePart{ - .value = Expr.init( - E.NameOfSymbol, - E.NameOfSymbol{ - .ref = ref.toRealRef(idx), - }, - visitor.loc, - ), - .tail = .{ - .cooked = E.String.init(" "), - }, - .tail_loc = visitor.loc, - }) catch |err| bun.handleOom(err); - - if (from_this_file) { - visitor.inner_visited.set(ref.innerIndex()); - } else { - visitor.composes_visited.put(ref.toRealRef(idx), {}) catch unreachable; - } - } - - fn warnNonSingleClassComposes(visitor: *@This(), ast: *bun.css.BundlerStyleSheet, css_ref: bun.css.CssRef, idx: Index.Int, compose_loc: Loc) void { - const ref = css_ref.toRealRef(idx); - _ = ref; - const syms: *const Symbol.List = &visitor.all_symbols[css_ref.sourceIndex(idx)]; - const name = syms.at(css_ref.innerIndex()).original_name; - const loc = ast.local_scope.get(name).?.loc; - - visitor.log.addRangeErrorFmtWithNote( - &visitor.all_sources[idx], - .{ .loc = compose_loc }, - visitor.allocator, - "The composes property cannot be used with {f}, because it is not a single class name.", - .{ - bun.fmt.quote(name), - }, - "The definition of {f} is here.", - .{ - bun.fmt.quote(name), - }, - - .{ - .loc = loc, - }, - ) catch |err| bun.handleOom(err); - } - - fn visitComposes(visitor: *@This(), ast: *bun.css.BundlerStyleSheet, css_ref: bun.css.CssRef, idx: Index.Int) void { - const ref = css_ref.toRealRef(idx); - if (ast.composes.count() > 0) { - const composes = ast.composes.getPtr(ref) orelse return; - // while parsing we check that we only allow `composes` on single class selectors - bun.assert(css_ref.tag.class); - - for (composes.composes.slice()) |*compose| { - // it is imported - if (compose.from != null) { - if (compose.from.? == .import_record_index) { - const import_record_idx = compose.from.?.import_record_index; - const import_records: *const BabyList(bun.css.ImportRecord) = &visitor.all_import_records[idx]; - const import_record = import_records.at(import_record_idx); - if (import_record.source_index.isValid()) { - const other_file = visitor.all_css_asts[import_record.source_index.get()] orelse { - visitor.log.addErrorFmt( - &visitor.all_sources[idx], - compose.loc, - visitor.allocator, - "Cannot use the \"composes\" property with the {f} file (it is not a CSS file)", - .{bun.fmt.quote(visitor.all_sources[import_record.source_index.get()].path.pretty)}, - ) catch |err| bun.handleOom(err); - continue; - }; - for (compose.names.slice()) |name| { - const other_name_entry = other_file.local_scope.get(name.v) orelse continue; - const other_name_ref = other_name_entry.ref; - if (!other_name_ref.canBeComposed()) { - visitor.warnNonSingleClassComposes(other_file, other_name_ref, import_record.source_index.get(), compose.loc); - } else { - visitor.visitName(other_file, other_name_ref, import_record.source_index.get()); - } - } - } - } else if (compose.from.? == .global) { - // E.g.: `composes: foo from global` - // - // In this example `foo` is global and won't be rewritten to a locally scoped - // name, so we can just add it as a string. - for (compose.names.slice()) |name| { - visitor.parts.append( - E.TemplatePart{ - .value = Expr.init( - E.String, - E.String.init(name.v), - visitor.loc, - ), - .tail = .{ - .cooked = E.String.init(" "), - }, - .tail_loc = visitor.loc, - }, - ) catch |err| bun.handleOom(err); - } - } - } else { - // it is from the current file - for (compose.names.slice()) |name| { - const name_entry = ast.local_scope.get(name.v) orelse { - visitor.log.addErrorFmt( - &visitor.all_sources[idx], - compose.loc, - visitor.allocator, - "The name {f} never appears in {f} as a CSS modules locally scoped class name. Note that \"composes\" only works with single class selectors.", - .{ - bun.fmt.quote(name.v), - bun.fmt.quote(visitor.all_sources[idx].path.pretty), - }, - ) catch |err| bun.handleOom(err); - continue; - }; - const name_ref = name_entry.ref; - if (!name_ref.canBeComposed()) { - visitor.warnNonSingleClassComposes(ast, name_ref, idx, compose.loc); - } else { - visitor.visitName(ast, name_ref, idx); - } - } - } - } - } - } - }; - - var visitor = Visitor{ - .inner_visited = &inner_visited, - .composes_visited = &composes_visited, - .source_index = source_index, - .parts = undefined, - .all_import_records = all_import_records, - .all_css_asts = all_css_asts, - .loc = stmt.loc, - .log = this.log, - .all_sources = all_sources, - .allocator = this.allocator(), - .all_symbols = this.graph.ast.items(.symbols), - }; - - for (values) |entry| { - const ref = entry.ref; - bun.assert(ref.inner_index < symbols.len); - - var template_parts = std.array_list.Managed(E.TemplatePart).init(this.allocator()); - var value = Expr.init(E.NameOfSymbol, E.NameOfSymbol{ .ref = ref.toRealRef(source_index) }, stmt.loc); - - visitor.parts = &template_parts; - visitor.clearAll(); - visitor.inner_visited.set(ref.innerIndex()); - if (ref.tag.class) visitor.visitComposes(css_ast, ref, source_index); - - if (template_parts.items.len > 0) { - template_parts.append(E.TemplatePart{ - .value = value, - .tail_loc = stmt.loc, - .tail = .{ .cooked = E.String.init("") }, - }) catch |err| bun.handleOom(err); - value = Expr.init( - E.Template, - E.Template{ - .parts = template_parts.items, - .head = .{ - .cooked = E.String.init(""), - }, - }, - stmt.loc, - ); - } - - const key = symbols.at(ref.innerIndex()).original_name; - try exports.put(this.allocator(), key, value); - } - - part.stmts[0].data.s_lazy_export.* = Expr.init(E.Object, exports, stmt.loc).data; - } - } - - const stmt: Stmt = part.stmts[0]; - if (stmt.data != .s_lazy_export) { - @panic("Internal error: expected top-level lazy export statement"); - } - - const expr = Expr{ - .data = stmt.data.s_lazy_export.*, - .loc = stmt.loc, - }; - - switch (exports_kind) { - .cjs => { - part.stmts[0] = Stmt.assign( - Expr.init( - E.Dot, - E.Dot{ - .target = Expr.initIdentifier(module_ref, stmt.loc), - .name = "exports", - .name_loc = stmt.loc, - }, - stmt.loc, - ), - expr, - ); - try this.graph.generateSymbolImportAndUse(source_index, 0, module_ref, 1, Index.init(source_index)); - - // If this is a .napi addon and it's not node, we need to generate a require() call to the runtime - if (expr.data == .e_call and - expr.data.e_call.target.data == .e_require_call_target and - // if it's commonjs, use require() - this.options.output_format != .cjs) - { - try this.graph.generateRuntimeSymbolImportAndUse( - source_index, - Index.part(1), - "__require", - 1, - ); - } - }, - else => { - // Otherwise, generate ES6 export statements. These are added as additional - // parts so they can be tree shaken individually. - part.stmts.len = 0; - - if (expr.data == .e_object) { - for (expr.data.e_object.properties.slice()) |property_| { - const property: G.Property = property_; - if (property.key == null or property.key.?.data != .e_string or property.value == null or - property.key.?.data.e_string.eqlComptime("default") or property.key.?.data.e_string.eqlComptime("__esModule")) - { - continue; - } - - const name = property.key.?.data.e_string.slice(this.allocator()); - - // TODO: support non-identifier names - if (!bun.js_lexer.isIdentifier(name)) - continue; - - // This initializes the generated variable with a copy of the property - // value, which is INCORRECT for values that are objects/arrays because - // they will have separate object identity. This is fixed up later in - // "generateCodeForFileInChunkJS" by changing the object literal to - // reference this generated variable instead. - // - // Changing the object literal is deferred until that point instead of - // doing it now because we only want to do this for top-level variables - // that actually end up being used, and we don't know which ones will - // end up actually being used at this point (since import binding hasn't - // happened yet). So we need to wait until after tree shaking happens. - const generated = try this.generateNamedExportInFile(source_index, module_ref, name, name); - parts.ptr[generated[1]].stmts = try this.allocator().alloc(Stmt, 1); - parts.ptr[generated[1]].stmts[0] = Stmt.alloc( - S.Local, - S.Local{ - .is_export = true, - .decls = try js_ast.G.Decl.List.fromSlice( - this.allocator(), - &.{ - .{ - .binding = Binding.alloc( - this.allocator(), - B.Identifier{ - .ref = generated[0], - }, - expr.loc, - ), - .value = property.value.?, - }, - }, - ), - }, - property.key.?.loc, - ); - } - } - - { - const generated = try this.generateNamedExportInFile( - source_index, - module_ref, - try std.fmt.allocPrint( - this.allocator(), - "{f}_default", - .{this.parse_graph.input_files.items(.source)[source_index].fmtIdentifier()}, - ), - "default", - ); - parts.ptr[generated[1]].stmts = try this.allocator().alloc(Stmt, 1); - parts.ptr[generated[1]].stmts[0] = Stmt.alloc( - S.ExportDefault, - S.ExportDefault{ - .default_name = .{ - .ref = generated[0], - .loc = stmt.loc, - }, - .value = .{ - .expr = expr, - }, - }, - stmt.loc, - ); - } - }, - } -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const ImportRecord = bun.ImportRecord; -const BitSet = bun.bit_set.DynamicBitSetUnmanaged; - -const js_ast = bun.ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const Part = js_ast.Part; -const S = js_ast.S; -const Stmt = js_ast.Stmt; -const Symbol = js_ast.Symbol; - -const Index = bun.bundle_v2.Index; -const LinkerContext = bun.bundle_v2.LinkerContext; -const Ref = bun.bundle_v2.Ref; - -const Logger = bun.logger; -const Loc = Logger.Loc; diff --git a/src/bundler/linker_context/generateCompileResultForCssChunk.zig b/src/bundler/linker_context/generateCompileResultForCssChunk.zig deleted file mode 100644 index 3597f3180129..000000000000 --- a/src/bundler/linker_context/generateCompileResultForCssChunk.zig +++ /dev/null @@ -1,178 +0,0 @@ -pub fn generateCompileResultForCssChunk(task: *ThreadPoolLib.Task) void { - const part_range: *const PendingPartRange = @fieldParentPtr("task", task); - const ctx = part_range.ctx; - var worker = ThreadPool.Worker.get(@fieldParentPtr("linker", ctx.c)); - defer worker.unget(); - - const prev_action = if (Environment.show_crash_trace) bun.crash_handler.current_action; - defer if (Environment.show_crash_trace) { - bun.crash_handler.current_action = prev_action; - }; - if (Environment.show_crash_trace) bun.crash_handler.current_action = .{ .bundle_generate_chunk = .{ - .chunk = ctx.chunk, - .context = ctx.c, - .part_range = &part_range.part_range, - } }; - - ctx.chunk.compile_results_for_chunk[part_range.i] = generateCompileResultForCssChunkImpl(worker, ctx.c, ctx.chunk, part_range.i); -} - -fn generateCompileResultForCssChunkImpl(worker: *ThreadPool.Worker, c: *LinkerContext, chunk: *Chunk, imports_in_chunk_index: u32) CompileResult { - const trace = bun.perf.trace("Bundler.generateCodeForFileInChunkCss"); - defer trace.end(); - - var arena = &worker.temporary_arena; - var allocating_writer = std.Io.Writer.Allocating.init(worker.allocator); - defer _ = arena.reset(.retain_capacity); - - const css_import = chunk.content.css.imports_in_chunk_in_order.at(imports_in_chunk_index); - const css: *const bun.css.BundlerStyleSheet = &chunk.content.css.asts[imports_in_chunk_index]; - // const symbols: []const Symbol.List = c.graph.ast.items(.symbols); - const symbols = &c.graph.symbols; - - switch (css_import.kind) { - .layers => { - const printer_options = bun.css.PrinterOptions{ - // TODO: make this more configurable - .minify = c.options.minify_whitespace, - .targets = bun.css.Targets.forBundlerTarget(c.options.target), - }; - _ = switch (css.toCssWithWriter( - worker.allocator, - &allocating_writer.writer, - printer_options, - .{ - .import_records = &css_import.condition_import_records, - .ast_urls_for_css = c.parse_graph.ast.items(.url_for_css), - .ast_unique_key_for_additional_file = c.parse_graph.input_files.items(.unique_key_for_additional_file), - }, - &c.mangled_props, - // layer does not need symbols i think - symbols, - )) { - .result => {}, - .err => { - return CompileResult{ - .css = .{ - .result = .{ .err = error.PrintError }, - .source_index = Index.invalid.get(), - }, - }; - }, - }; - return CompileResult{ - .css = .{ - .result = .{ .result = allocating_writer.written() }, - .source_index = Index.invalid.get(), - }, - }; - }, - .external_path => { - var import_records = BabyList(ImportRecord).fromBorrowedSliceDangerous( - css_import.condition_import_records.sliceConst(), - ); - const printer_options = bun.css.PrinterOptions{ - // TODO: make this more configurable - .minify = c.options.minify_whitespace, - .targets = bun.css.Targets.forBundlerTarget(c.options.target), - }; - _ = switch (css.toCssWithWriter( - worker.allocator, - &allocating_writer.writer, - printer_options, - .{ - .import_records = &import_records, - .ast_urls_for_css = c.parse_graph.ast.items(.url_for_css), - .ast_unique_key_for_additional_file = c.parse_graph.input_files.items(.unique_key_for_additional_file), - }, - &c.mangled_props, - // external_path does not need symbols i think - symbols, - )) { - .result => {}, - .err => { - return CompileResult{ - .css = .{ - .result = .{ .err = error.PrintError }, - .source_index = Index.invalid.get(), - }, - }; - }, - }; - return CompileResult{ - .css = .{ - .result = .{ .result = allocating_writer.written() }, - - .source_index = Index.invalid.get(), - }, - }; - }, - .source_index => |idx| { - const printer_options = bun.css.PrinterOptions{ - .targets = bun.css.Targets.forBundlerTarget(c.options.target), - // TODO: make this more configurable - .minify = c.options.minify_whitespace or c.options.minify_syntax or c.options.minify_identifiers, - }; - _ = switch (css.toCssWithWriter( - worker.allocator, - &allocating_writer.writer, - printer_options, - .{ - .import_records = &c.graph.ast.items(.import_records)[idx.get()], - .ast_urls_for_css = c.parse_graph.ast.items(.url_for_css), - .ast_unique_key_for_additional_file = c.parse_graph.input_files.items(.unique_key_for_additional_file), - }, - &c.mangled_props, - symbols, - )) { - .result => {}, - .err => { - return CompileResult{ - .css = .{ - .result = .{ .err = error.PrintError }, - .source_index = idx.get(), - }, - }; - }, - }; - const output = allocating_writer.written(); - // Update bytesInOutput for this source in the chunk (for metafile) - // Use atomic operation since multiple threads may update the same counter - if (output.len > 0) { - if (chunk.files_with_parts_in_chunk.getPtr(idx.get())) |bytes_ptr| { - _ = @atomicRmw(usize, bytes_ptr, .Add, output.len, .monotonic); - } - } - return CompileResult{ - .css = .{ - .result = .{ .result = output }, - .source_index = idx.get(), - }, - }; - }, - } -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const Environment = bun.Environment; -const ImportRecord = bun.ImportRecord; -const ThreadPoolLib = bun.ThreadPool; -const options = bun.options; - -const js_ast = bun.ast; -const Symbol = js_ast.Symbol; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const CompileResult = bundler.CompileResult; -const Index = bun.bundle_v2.Index; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const PendingPartRange = LinkerContext.PendingPartRange; diff --git a/src/bundler/linker_context/generateCompileResultForHtmlChunk.zig b/src/bundler/linker_context/generateCompileResultForHtmlChunk.zig deleted file mode 100644 index aadd9dce5335..000000000000 --- a/src/bundler/linker_context/generateCompileResultForHtmlChunk.zig +++ /dev/null @@ -1,344 +0,0 @@ -/// Rrewrite the HTML with the following transforms: -/// 1. Remove all ", .{js_chunk.unique_key}, 0)); - defer allocator.free(script); - try endTag.before(script, true); - } - } - - fn getHeadTags(this: *@This(), allocator: std.mem.Allocator) bun.BoundedArray([]const u8, 2) { - var array: bun.BoundedArray([]const u8, 2) = .{}; - if (this.compile_to_standalone_html) { - // In standalone HTML mode, only put CSS in ; JS goes before - if (this.chunk.getCSSChunkForHTML(this.chunks)) |css_chunk| { - const style_tag = bun.handleOom(std.fmt.allocPrintSentinel(allocator, "", .{css_chunk.unique_key}, 0)); - array.appendAssumeCapacity(style_tag); - } - } else { - // Put CSS before JS to reduce chances of flash of unstyled content - if (this.chunk.getCSSChunkForHTML(this.chunks)) |css_chunk| { - const link_tag = bun.handleOom(std.fmt.allocPrintSentinel(allocator, "", .{css_chunk.unique_key}, 0)); - array.appendAssumeCapacity(link_tag); - } - if (this.chunk.getJSChunkForHTML(this.chunks)) |js_chunk| { - // type="module" scripts do not block rendering, so it is okay to put them in head - const script = bun.handleOom(std.fmt.allocPrintSentinel(allocator, "", .{js_chunk.unique_key}, 0)); - array.appendAssumeCapacity(script); - } - } - return array; - } - - fn endHeadTagHandler(end: *lol.EndTag, opaque_this: ?*anyopaque) callconv(.c) lol.Directive { - const this: *@This() = @ptrCast(@alignCast(opaque_this.?)); - if (this.linker.dev_server == null) { - this.addHeadTags(end) catch return .stop; - } else { - this.end_tag_indices.head = @intCast(this.output.items.len); - } - return .@"continue"; - } - - fn endBodyTagHandler(end: *lol.EndTag, opaque_this: ?*anyopaque) callconv(.c) lol.Directive { - const this: *@This() = @ptrCast(@alignCast(opaque_this.?)); - if (this.linker.dev_server == null) { - if (this.compile_to_standalone_html) { - // In standalone mode, insert JS before so DOM is available - this.addBodyTags(end) catch return .stop; - } else { - this.addHeadTags(end) catch return .stop; - } - } else { - this.end_tag_indices.body = @intCast(this.output.items.len); - } - return .@"continue"; - } - - fn endHtmlTagHandler(end: *lol.EndTag, opaque_this: ?*anyopaque) callconv(.c) lol.Directive { - const this: *@This() = @ptrCast(@alignCast(opaque_this.?)); - if (this.linker.dev_server == null) { - if (this.compile_to_standalone_html) { - // Fallback: if no was found, insert both CSS and JS before - this.addHeadTags(end) catch return .stop; - this.addBodyTags(end) catch return .stop; - } else { - this.addHeadTags(end) catch return .stop; - } - } else { - this.end_tag_indices.html = @intCast(this.output.items.len); - } - return .@"continue"; - } - }; - - // HTML bundles for dev server must be allocated to it, as it must outlive - // the bundle task. See `DevServer.RouteBundle.HTML.bundled_html_text` - const output_allocator = if (c.dev_server) |dev| dev.allocator() else worker.allocator; - - var html_loader: HTMLLoader = .{ - .linker = c, - .source_index = chunk.entry_point.source_index, - .import_records = import_records[chunk.entry_point.source_index].slice(), - .log = c.log, - .allocator = worker.allocator, - .minify_whitespace = c.options.minify_whitespace, - .compile_to_standalone_html = c.options.compile_to_standalone_html, - .chunk = chunk, - .chunks = chunks, - .output = std.array_list.Managed(u8).init(output_allocator), - .current_import_record_index = 0, - .end_tag_indices = .{ - .html = null, - .body = null, - .head = null, - }, - .added_head_tags = false, - .added_body_script = false, - }; - - HTMLScanner.HTMLProcessor(HTMLLoader, true).run( - &html_loader, - sources[chunk.entry_point.source_index].contents, - ) catch std.debug.panic("unexpected error from HTMLProcessor.run", .{}); - - // There are some cases where invalid HTML will make it so is - // never emitted, even if the literal text DOES appear. These cases are - // along the lines of having a self-closing tag for a non-self closing - // element. In this case, head_end_tag_index will be 0, and a simple - // search through the page is done to find the "" - // See https://github.com/oven-sh/bun/issues/17554 - const script_injection_offset: u32 = if (c.dev_server != null) brk: { - if (html_loader.end_tag_indices.head) |head| - break :brk head; - if (bun.strings.indexOf(html_loader.output.items, "")) |head| - break :brk @intCast(head); - if (html_loader.end_tag_indices.body) |body| - break :brk body; - if (html_loader.end_tag_indices.html) |html| - break :brk html; - break :brk @intCast(html_loader.output.items.len); // inject at end of file. - } else brk: { - if (!html_loader.added_head_tags or !html_loader.added_body_script) { - @branchHint(.cold); // this is if the document is missing all head, body, and html elements. - var html_appender = std.heap.stackFallback(256, bun.default_allocator); - const allocator = html_appender.get(); - if (!html_loader.added_head_tags) { - const slices = html_loader.getHeadTags(allocator); - for (slices.slice()) |slice| { - bun.handleOom(html_loader.output.appendSlice(slice)); - allocator.free(slice); - } - html_loader.added_head_tags = true; - } - if (!html_loader.added_body_script) { - if (html_loader.compile_to_standalone_html) { - if (html_loader.chunk.getJSChunkForHTML(html_loader.chunks)) |js_chunk| { - const script = bun.handleOom(std.fmt.allocPrintSentinel(allocator, "", .{js_chunk.unique_key}, 0)); - defer allocator.free(script); - bun.handleOom(html_loader.output.appendSlice(script)); - } - } - html_loader.added_body_script = true; - } - } - break :brk if (Environment.isDebug) undefined else 0; // value is ignored. fail loud if hit in debug - }; - - return .{ .html = .{ - .code = html_loader.output.items, - .source_index = chunk.entry_point.source_index, - .script_injection_offset = script_injection_offset, - } }; -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const ImportKind = bun.ImportKind; -const ImportRecord = bun.ImportRecord; -const Loader = bun.Loader; -const Logger = bun.logger; -const Output = bun.Output; -const ThreadPoolLib = bun.ThreadPool; -const default_allocator = bun.default_allocator; -const lol = bun.LOLHTML; -const strings = bun.strings; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const CompileResult = bundler.CompileResult; -const HTMLScanner = bun.bundle_v2.HTMLScanner; -const Index = bun.bundle_v2.Index; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const PendingPartRange = LinkerContext.PendingPartRange; -const debug = LinkerContext.debug; diff --git a/src/bundler/linker_context/generateCompileResultForJSChunk.zig b/src/bundler/linker_context/generateCompileResultForJSChunk.zig deleted file mode 100644 index 58b16bf2d638..000000000000 --- a/src/bundler/linker_context/generateCompileResultForJSChunk.zig +++ /dev/null @@ -1,110 +0,0 @@ -pub fn generateCompileResultForJSChunk(task: *ThreadPoolLib.Task) void { - const part_range: *const PendingPartRange = @fieldParentPtr("task", task); - const ctx = part_range.ctx; - var worker = ThreadPool.Worker.get(@fieldParentPtr("linker", ctx.c)); - defer worker.unget(); - - const prev_action = if (Environment.show_crash_trace) bun.crash_handler.current_action; - defer if (Environment.show_crash_trace) { - bun.crash_handler.current_action = prev_action; - }; - if (Environment.show_crash_trace) bun.crash_handler.current_action = .{ .bundle_generate_chunk = .{ - .chunk = ctx.chunk, - .context = ctx.c, - .part_range = &part_range.part_range, - } }; - - if (Environment.show_crash_trace) { - const path = ctx.c.parse_graph.input_files.items(.source)[part_range.part_range.source_index.get()].path; - if (bun.cli.debug_flags.hasPrintBreakpoint(path)) { - @breakpoint(); - } - } - - ctx.chunk.compile_results_for_chunk[part_range.i] = generateCompileResultForJSChunkImpl(worker, ctx.c, ctx.chunk, part_range.part_range); -} - -fn generateCompileResultForJSChunkImpl(worker: *ThreadPool.Worker, c: *LinkerContext, chunk: *Chunk, part_range: PartRange) CompileResult { - const trace = bun.perf.trace("Bundler.generateCodeForFileInChunkJS"); - defer trace.end(); - - // Client and server bundles for Bake must be globally allocated, as they - // must outlive the bundle task. - const allocator = blk: { - const dev = c.dev_server orelse break :blk default_allocator; - break :blk dev.allocator(); - }; - - var arena = &worker.temporary_arena; - var buffer_writer = js_printer.BufferWriter.init(allocator); - defer _ = arena.reset(.retain_capacity); - worker.stmt_list.reset(); - - var runtime_scope: *Scope = &c.graph.ast.items(.module_scope)[c.graph.files.items(.input_file)[Index.runtime.value].get()]; - var runtime_members = &runtime_scope.members; - const toCommonJSRef = c.graph.symbols.follow(runtime_members.get("__toCommonJS").?.ref); - const toESMRef = c.graph.symbols.follow(runtime_members.get("__toESM").?.ref); - const runtimeRequireRef = if (c.options.output_format == .cjs) null else c.graph.symbols.follow(runtime_members.get("__require").?.ref); - - const collect_decls = c.options.generate_bytecode_cache and c.options.output_format == .esm and c.options.compile; - var dc = DeclCollector{ .allocator = allocator }; - - const result = c.generateCodeForFileInChunkJS( - &buffer_writer, - chunk.renamer, - chunk, - part_range, - toCommonJSRef, - toESMRef, - runtimeRequireRef, - &worker.stmt_list, - worker.allocator, - arena.allocator(), - if (collect_decls) &dc else null, - ); - - // Update bytesInOutput for this source in the chunk (for metafile) - // Use atomic operation since multiple threads may update the same counter - const code_len = switch (result) { - .result => |r| r.code.len, - else => 0, - }; - if (code_len > 0 and !part_range.source_index.isRuntime()) { - if (chunk.files_with_parts_in_chunk.getPtr(part_range.source_index.get())) |bytes_ptr| { - _ = @atomicRmw(usize, bytes_ptr, .Add, code_len, .monotonic); - } - } - - return .{ - .javascript = .{ - .source_index = part_range.source_index.get(), - .result = result, - .decls = if (collect_decls) dc.decls.items else &.{}, - }, - }; -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const DeclCollector = @import("./generateCodeForFileInChunkJS.zig").DeclCollector; - -const bun = @import("bun"); -const Environment = bun.Environment; -const ThreadPoolLib = bun.ThreadPool; -const default_allocator = bun.default_allocator; -const js_printer = bun.js_printer; -const renamer = bun.renamer; - -const js_ast = bun.ast; -const Scope = js_ast.Scope; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const CompileResult = bundler.CompileResult; -const Index = bun.bundle_v2.Index; -const PartRange = bundler.PartRange; -const ThreadPool = bun.bundle_v2.ThreadPool; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const PendingPartRange = LinkerContext.PendingPartRange; diff --git a/src/bundler/linker_context/postProcessCSSChunk.zig b/src/bundler/linker_context/postProcessCSSChunk.zig deleted file mode 100644 index e3f680676ca3..000000000000 --- a/src/bundler/linker_context/postProcessCSSChunk.zig +++ /dev/null @@ -1,127 +0,0 @@ -/// This runs after we've already populated the compile results -pub fn postProcessCSSChunk(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, chunk: *Chunk) !void { - const c = ctx.c; - var j = StringJoiner{ - .allocator = worker.allocator, - .watcher = .{ - .input = chunk.unique_key, - }, - }; - - var line_offset: bun.SourceMap.LineColumnOffset.Optional = if (c.options.source_maps != .none) .{ .value = .{} } else .{ .null = {} }; - - var newline_before_comment = false; - - // TODO: css banner - // if len(c.options.CSSBanner) > 0 { - // prevOffset.AdvanceString(c.options.CSSBanner) - // j.AddString(c.options.CSSBanner) - // prevOffset.AdvanceString("\n") - // j.AddString("\n") - // } - - // TODO: (this is where we would put the imports) - // Generate any prefix rules now - // (THIS SHOULD BE SET WHEN GENERATING PREFIX RULES!) - // newline_before_comment = true; - - // TODO: meta - - // Concatenate the generated CSS chunks together - const compile_results = chunk.compile_results_for_chunk; - - var compile_results_for_source_map: std.MultiArrayList(CompileResultForSourceMap) = .{}; - bun.handleOom(compile_results_for_source_map.setCapacity(worker.allocator, compile_results.len)); - - const sources: []const Logger.Source = c.parse_graph.input_files.items(.source); - for (compile_results) |compile_result| { - const source_index = compile_result.sourceIndex(); - - if (c.options.mode == .bundle and !c.options.minify_whitespace and Index.init(source_index).isValid()) { - if (newline_before_comment) { - j.pushStatic("\n"); - line_offset.advance("\n"); - } - - const pretty = sources[source_index].path.pretty; - - j.pushStatic("/* "); - line_offset.advance("/* "); - - j.pushStatic(pretty); - line_offset.advance(pretty); - - j.pushStatic(" */\n"); - line_offset.advance(" */\n"); - } - - if (compile_result.code().len > 0) { - newline_before_comment = true; - } - - // Save the offset to the start of the stored JavaScript - j.push(compile_result.code(), bun.default_allocator); - - if (compile_result.sourceMapChunk()) |source_map_chunk| { - if (c.options.source_maps != .none) { - try compile_results_for_source_map.append(worker.allocator, CompileResultForSourceMap{ - .source_map_chunk = source_map_chunk, - .generated_offset = line_offset.value, - .source_index = compile_result.sourceIndex(), - }); - } - - line_offset.reset(); - } else { - line_offset.advance(compile_result.code()); - } - } - - // Make sure the file ends with a newline - j.ensureNewlineAtEnd(); - // if c.options.UnsupportedCSSFeatures.Has(compat.InlineStyle) { - // slashTag = "" - // } - // c.maybeAppendLegalComments(c.options.LegalComments, legalCommentList, chunk, &j, slashTag) - - // if len(c.options.CSSFooter) > 0 { - // j.AddString(c.options.CSSFooter) - // j.AddString("\n") - // } - - chunk.intermediate_output = c.breakOutputIntoPieces( - worker.allocator, - &j, - @as(u32, @truncate(ctx.chunks.len)), - ) catch |err| bun.handleOom(err); - // TODO: meta contents - - chunk.isolated_hash = c.generateIsolatedHash(chunk); - // chunk.flags.is_executable = is_executable; - - if (c.options.source_maps != .none) { - const can_have_shifts = chunk.intermediate_output == .pieces; - chunk.output_source_map = try c.generateSourceMapForChunk( - chunk.isolated_hash, - worker, - compile_results_for_source_map, - c.resolver.opts.output_dir, - can_have_shifts, - ); - } -} - -const std = @import("std"); - -const bun = @import("bun"); -const Logger = bun.logger; -const StringJoiner = bun.StringJoiner; -const options = bun.options; - -const Chunk = bun.bundle_v2.Chunk; -const CompileResultForSourceMap = bun.bundle_v2.CompileResultForSourceMap; -const Index = bun.bundle_v2.Index; -const ThreadPool = bun.bundle_v2.ThreadPool; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const GenerateChunkCtx = bun.bundle_v2.LinkerContext.GenerateChunkCtx; diff --git a/src/bundler/linker_context/postProcessHTMLChunk.zig b/src/bundler/linker_context/postProcessHTMLChunk.zig deleted file mode 100644 index 65ff00a67c57..000000000000 --- a/src/bundler/linker_context/postProcessHTMLChunk.zig +++ /dev/null @@ -1,35 +0,0 @@ -pub fn postProcessHTMLChunk(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, chunk: *Chunk) !void { - // This is where we split output into pieces - const c = ctx.c; - var j = StringJoiner{ - .allocator = worker.allocator, - .watcher = .{ - .input = chunk.unique_key, - }, - }; - - const compile_results = chunk.compile_results_for_chunk; - - for (compile_results) |compile_result| { - j.push(compile_result.code(), bun.default_allocator); - } - - j.ensureNewlineAtEnd(); - - chunk.intermediate_output = c.breakOutputIntoPieces( - worker.allocator, - &j, - @as(u32, @truncate(ctx.chunks.len)), - ) catch |err| bun.handleOom(err); - - chunk.isolated_hash = c.generateIsolatedHash(chunk); -} - -const bun = @import("bun"); -const StringJoiner = bun.StringJoiner; - -const Chunk = bun.bundle_v2.Chunk; -const ThreadPool = bun.bundle_v2.ThreadPool; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const GenerateChunkCtx = bun.bundle_v2.LinkerContext.GenerateChunkCtx; diff --git a/src/bundler/linker_context/postProcessJSChunk.zig b/src/bundler/linker_context/postProcessJSChunk.zig deleted file mode 100644 index 06520ba28ef0..000000000000 --- a/src/bundler/linker_context/postProcessJSChunk.zig +++ /dev/null @@ -1,1125 +0,0 @@ -/// This runs after we've already populated the compile results -pub fn postProcessJSChunk(ctx: GenerateChunkCtx, worker: *ThreadPool.Worker, chunk: *Chunk, chunk_index: usize) !void { - const trace = bun.perf.trace("Bundler.postProcessJSChunk"); - defer trace.end(); - - _ = chunk_index; - const c = ctx.c; - bun.assert(chunk.content == .javascript); - - js_ast.Expr.Data.Store.create(); - js_ast.Stmt.Data.Store.create(); - - defer chunk.renamer.deinit(bun.default_allocator); - - var arena = bun.ArenaAllocator.init(worker.allocator); - defer arena.deinit(); - - // Also generate the cross-chunk binding code - var cross_chunk_prefix: js_printer.PrintResult = undefined; - var cross_chunk_suffix: js_printer.PrintResult = undefined; - - var runtime_scope: *Scope = &c.graph.ast.items(.module_scope)[c.graph.files.items(.input_file)[Index.runtime.value].get()]; - var runtime_members = &runtime_scope.members; - const toCommonJSRef = c.graph.symbols.follow(runtime_members.get("__toCommonJS").?.ref); - const toESMRef = c.graph.symbols.follow(runtime_members.get("__toESM").?.ref); - const runtimeRequireRef = if (c.options.output_format == .cjs) null else c.graph.symbols.follow(runtime_members.get("__require").?.ref); - - // Create ModuleInfo for ESM bytecode in --compile builds - const generate_module_info = c.options.generate_bytecode_cache and c.options.output_format == .esm and c.options.compile; - const loader = c.parse_graph.input_files.items(.loader)[chunk.entry_point.source_index]; - const is_typescript = loader.isTypeScript(); - const module_info: ?*analyze_transpiled_module.ModuleInfo = if (generate_module_info) - analyze_transpiled_module.ModuleInfo.create(bun.default_allocator, is_typescript) catch null - else - null; - - { - const print_options = js_printer.Options{ - .bundling = true, - .indent = .{}, - .has_run_symbol_renamer = true, - - .allocator = worker.allocator, - .require_ref = runtimeRequireRef, - .minify_whitespace = c.options.minify_whitespace, - .minify_identifiers = c.options.minify_identifiers, - .minify_syntax = c.options.minify_syntax, - .target = c.options.target, - .print_dce_annotations = c.options.emit_dce_annotations, - .mangled_props = &c.mangled_props, - .module_info = module_info, - // .const_values = c.graph.const_values, - }; - - var cross_chunk_import_records = ImportRecord.List.initCapacity(worker.allocator, chunk.cross_chunk_imports.len) catch unreachable; - defer cross_chunk_import_records.deinit(worker.allocator); - for (chunk.cross_chunk_imports.slice()) |import_record| { - cross_chunk_import_records.appendAssumeCapacity( - .{ - .kind = import_record.import_kind, - .path = Fs.Path.init(ctx.chunks[import_record.chunk_index].unique_key), - .range = Logger.Range.None, - }, - ); - } - - const ast = c.graph.ast.get(chunk.entry_point.source_index); - - cross_chunk_prefix = js_printer.print( - worker.allocator, - c.resolver.opts.target, - ast.toAST(), - c.getSource(chunk.entry_point.source_index), - print_options, - cross_chunk_import_records.slice(), - &[_]Part{ - .{ .stmts = chunk.content.javascript.cross_chunk_prefix_stmts.slice() }, - }, - chunk.renamer, - false, - ); - cross_chunk_suffix = js_printer.print( - worker.allocator, - c.resolver.opts.target, - ast.toAST(), - c.getSource(chunk.entry_point.source_index), - print_options, - &.{}, - &[_]Part{ - .{ .stmts = chunk.content.javascript.cross_chunk_suffix_stmts.slice() }, - }, - chunk.renamer, - false, - ); - } - - // Populate ModuleInfo with declarations collected during parallel printing, - // external import records from the original AST, and wrapper refs. - if (module_info) |mi| { - // 1. Add declarations collected by DeclCollector during parallel part printing. - // These come from the CONVERTED statements (after convertStmtsForChunk transforms - // export default → var, strips exports, etc.), so they match what's actually printed. - for (chunk.compile_results_for_chunk) |cr| { - const decls = switch (cr) { - .javascript => |js| js.decls, - else => continue, - }; - for (decls) |decl| { - const var_kind: analyze_transpiled_module.ModuleInfo.VarKind = switch (decl.kind) { - .declared => .declared, - .lexical => .lexical, - }; - const string_id = mi.str(decl.name) catch continue; - mi.addVar(string_id, var_kind) catch continue; - } - } - - // 1b. Check if any source in this chunk uses import.meta. The per-part - // parallel printer does not have module_info, so the printer cannot set - // this flag during per-part printing. We derive it from the AST instead. - // Note: the runtime source (index 0) also uses import.meta (e.g. - // `import.meta.require`), so we must not skip it. - { - const all_ast_flags = c.graph.ast.items(.flags); - for (chunk.content.javascript.parts_in_chunk_in_order) |part_range| { - if (all_ast_flags[part_range.source_index.get()].has_import_meta) { - mi.flags.contains_import_meta = true; - break; - } - } - } - - // 1c. Same idea for top-level await. The new JSC module loader decides - // sync vs async evaluation from JSModuleRecord::hasTLA(), which we set - // from this bit when constructing the record from cached module_info - // (BunAnalyzeTranspiledModule). Without it, a bytecode-compiled module - // that contains TLA gets evaluated on the sync path and the suspended - // generator is dropped — the entry promise resolves immediately and the - // process exits before the awaited value lands. - { - const tla_keywords = c.parse_graph.ast.items(.top_level_await_keyword); - const wraps = c.graph.meta.items(.flags); - for (chunk.content.javascript.parts_in_chunk_in_order) |part_range| { - const idx = part_range.source_index.get(); - if (idx >= tla_keywords.len) continue; - if (wraps[idx].wrap != .none) continue; - if (!tla_keywords[idx].isEmpty()) { - mi.flags.has_tla = true; - break; - } - } - } - - // 2. Collect truly-external imports from the original AST. Bundled imports - // (where source_index is valid) are removed by convertStmtsForChunk and - // re-created as cross-chunk imports — those are already captured by the - // printer when it prints cross_chunk_prefix_stmts above. Only truly-external - // imports (node built-ins, etc.) survive as s_import in per-file parts and - // need recording here. - const all_parts = c.graph.ast.items(.parts); - const all_flags = c.graph.meta.items(.flags); - const all_import_records = c.graph.ast.items(.import_records); - for (chunk.content.javascript.parts_in_chunk_in_order) |part_range| { - if (all_flags[part_range.source_index.get()].wrap == .cjs) continue; - const source_parts = all_parts[part_range.source_index.get()].slice(); - const source_import_records = all_import_records[part_range.source_index.get()].slice(); - var part_i = part_range.part_index_begin; - while (part_i < part_range.part_index_end) : (part_i += 1) { - for (source_parts[part_i].stmts) |stmt| { - switch (stmt.data) { - .s_import => |s| { - const record = &source_import_records[s.import_record_index]; - if (record.path.is_disabled) continue; - if (record.tag == .bun) continue; - // Skip bundled imports — these are converted to cross-chunk - // imports by the linker. The printer already recorded them - // when printing cross_chunk_prefix_stmts. - if (record.source_index.isValid()) continue; - // Skip barrel-optimized-away imports — marked is_unused by - // barrel_imports.zig. Never resolved (source_index invalid), - // and removed by convertStmtsForChunk. Not in emitted code. - if (record.flags.is_unused) continue; - - const import_path = record.path.text; - const irp_id = mi.str(import_path) catch continue; - mi.requestModule(irp_id, .none) catch continue; - - if (s.default_name) |name| { - if (name.ref) |name_ref| { - const local_name = chunk.renamer.nameForSymbol(name_ref); - const local_name_id = mi.str(local_name) catch continue; - mi.addVar(local_name_id, .lexical) catch continue; - mi.addImportInfoSingle(irp_id, mi.str("default") catch continue, local_name_id, false) catch continue; - } - } - - for (s.items) |item| { - if (item.name.ref) |name_ref| { - const local_name = chunk.renamer.nameForSymbol(name_ref); - const local_name_id = mi.str(local_name) catch continue; - mi.addVar(local_name_id, .lexical) catch continue; - mi.addImportInfoSingle(irp_id, mi.str(item.alias) catch continue, local_name_id, false) catch continue; - } - } - - if (record.flags.contains_import_star) { - const local_name = chunk.renamer.nameForSymbol(s.namespace_ref); - const local_name_id = mi.str(local_name) catch continue; - mi.addVar(local_name_id, .lexical) catch continue; - mi.addImportInfoNamespace(irp_id, local_name_id) catch continue; - } - }, - else => {}, - } - } - } - } - - // 3. Add wrapper-generated declarations (init_xxx, require_xxx) that are - // not in any part statement. - const all_wrapper_refs = c.graph.ast.items(.wrapper_ref); - for (chunk.content.javascript.parts_in_chunk_in_order) |part_range| { - const source_index = part_range.source_index.get(); - if (all_flags[source_index].wrap != .none) { - const wrapper_ref = all_wrapper_refs[source_index]; - if (!wrapper_ref.isEmpty()) { - const name = chunk.renamer.nameForSymbol(wrapper_ref); - if (name.len > 0) { - const string_id = mi.str(name) catch continue; - mi.addVar(string_id, .declared) catch continue; - } - } - } - } - } - - // Generate the exports for the entry point, if there are any. - // This must happen before module_info serialization so the printer - // can populate export entries in module_info. - const entry_point_tail = brk: { - if (chunk.isEntryPoint()) { - break :brk generateEntryPointTailJS( - c, - toCommonJSRef, - toESMRef, - chunk.entry_point.source_index, - worker.allocator, - arena.allocator(), - chunk.renamer, - module_info, - ); - } - - break :brk CompileResult.empty; - }; - - // Store unserialized ModuleInfo on the chunk. Serialization is deferred to - // generateChunksInParallel after final chunk paths are computed, so that - // cross-chunk import specifiers (which use unique_key placeholders during - // printing) can be resolved to actual paths. - if (module_info) |mi| { - chunk.content.javascript.module_info = mi; - } - - var j = StringJoiner{ - .allocator = worker.allocator, - .watcher = .{ - .input = chunk.unique_key, - }, - }; - errdefer j.deinit(); - const output_format = c.options.output_format; - - var line_offset: bun.SourceMap.LineColumnOffset.Optional = if (c.options.source_maps != .none) .{ .value = .{} } else .{ .null = {} }; - - // Concatenate the generated JavaScript chunks together - - var newline_before_comment = false; - var is_executable = false; - - // Extract hashbang and banner for entry points - const hashbang, const banner = if (chunk.isEntryPoint()) brk: { - const source_hashbang = c.graph.ast.items(.hashbang)[chunk.entry_point.source_index]; - - // If source file has a hashbang, use it - if (source_hashbang.len > 0) { - break :brk .{ source_hashbang, c.options.banner }; - } - - // Otherwise check if banner starts with hashbang - if (c.options.banner.len > 0 and strings.hasPrefixComptime(c.options.banner, "#!")) { - const newline_pos = strings.indexOfChar(c.options.banner, '\n') orelse c.options.banner.len; - const banner_hashbang = c.options.banner[0..newline_pos]; - - break :brk .{ banner_hashbang, std.mem.trimLeft(u8, c.options.banner[newline_pos..], "\r\n") }; - } - - // No hashbang anywhere - break :brk .{ "", c.options.banner }; - } else .{ "", c.options.banner }; - - // Start with the hashbang if there is one. This must be done before the - // banner because it only works if it's literally the first character. - if (hashbang.len > 0) { - j.pushStatic(hashbang); - j.pushStatic("\n"); - line_offset.advance(hashbang); - line_offset.advance("\n"); - newline_before_comment = true; - is_executable = true; - } - - // Add @bun comments and CJS wrapper start for each chunk when targeting Bun. - const is_bun = c.graph.ast.items(.target)[chunk.entry_point.source_index].isBun(); - if (is_bun) { - const cjs_entry_chunk = "(function(exports, require, module, __filename, __dirname) {"; - if (ctx.c.options.generate_bytecode_cache and output_format == .cjs) { - const input = "// @bun @bytecode @bun-cjs\n" ++ cjs_entry_chunk; - j.pushStatic(input); - line_offset.advance(input); - } else if (ctx.c.options.generate_bytecode_cache) { - j.pushStatic("// @bun @bytecode\n"); - line_offset.advance("// @bun @bytecode\n"); - } else if (output_format == .cjs) { - j.pushStatic("// @bun @bun-cjs\n" ++ cjs_entry_chunk); - line_offset.advance("// @bun @bun-cjs\n" ++ cjs_entry_chunk); - } else { - j.pushStatic("// @bun\n"); - line_offset.advance("// @bun\n"); - } - } - - // Add the banner (excluding any hashbang part) for all chunks - if (banner.len > 0) { - j.pushStatic(banner); - line_offset.advance(banner); - if (!strings.endsWithChar(banner, '\n')) { - j.pushStatic("\n"); - line_offset.advance("\n"); - } - newline_before_comment = true; - } - - // Add the top-level directive if present (but omit "use strict" in ES - // modules because all ES modules are automatically in strict mode) - if (chunk.isEntryPoint() and !output_format.isAlwaysStrictMode()) { - const flags: JSAst.Flags = c.graph.ast.items(.flags)[chunk.entry_point.source_index]; - - if (flags.has_explicit_use_strict_directive) { - j.pushStatic("\"use strict\";\n"); - line_offset.advance("\"use strict\";\n"); - newline_before_comment = true; - } - } - - // For Kit, hoist runtime.js outside of the IIFE - const compile_results = chunk.compile_results_for_chunk; - if (c.options.output_format == .internal_bake_dev) { - for (compile_results) |compile_result| { - const source_index = compile_result.sourceIndex(); - if (source_index != Index.runtime.value) break; - line_offset.advance(compile_result.code()); - j.push(compile_result.code(), bun.default_allocator); - } - } - - switch (c.options.output_format) { - .internal_bake_dev => { - const start = bun.bake.getHmrRuntime(if (c.options.target.isServerSide()) .server else .client); - j.pushStatic(start.code); - line_offset.advance(start.code); - }, - .iife => { - // Bun does not do arrow function lowering. So the wrapper can be an arrow. - const start = if (c.options.minify_whitespace) "(()=>{" else "(() => {\n"; - j.pushStatic(start); - line_offset.advance(start); - }, - else => {}, // no wrapper - } - - if (cross_chunk_prefix.result.code.len > 0) { - newline_before_comment = true; - line_offset.advance(cross_chunk_prefix.result.code); - j.push(cross_chunk_prefix.result.code, worker.allocator); - } - - // Concatenate the generated JavaScript chunks together - var prev_filename_comment: Index.Int = 0; - - var compile_results_for_source_map: std.MultiArrayList(CompileResultForSourceMap) = .{}; - bun.handleOom(compile_results_for_source_map.setCapacity(worker.allocator, compile_results.len)); - - const show_comments = c.options.mode == .bundle and - !c.options.minify_whitespace; - - const emit_targets_in_commands = show_comments and (if (ctx.c.framework) |fw| fw.server_components != null else false); - - const sources: []const Logger.Source = c.parse_graph.input_files.items(.source); - const targets: []const options.Target = c.parse_graph.ast.items(.target); - for (compile_results) |compile_result| { - const source_index = compile_result.sourceIndex(); - const is_runtime = source_index == Index.runtime.value; - - // TODO: extracated legal comments - - // Add a comment with the file path before the file contents - if (show_comments and source_index != prev_filename_comment and compile_result.code().len > 0) { - prev_filename_comment = source_index; - - if (newline_before_comment) { - j.pushStatic("\n"); - line_offset.advance("\n"); - } - - // Make sure newlines in the path can't cause a syntax error. - const CommentType = enum { - multiline, - single, - }; - - const pretty = sources[source_index].path.pretty; - - // TODO: quote this. This is really janky. - const comment_type = if (strings.indexOfNewlineOrNonASCII(pretty, 0) != null) - CommentType.multiline - else - CommentType.single; - - if (!c.options.minify_whitespace and - (output_format == .iife or output_format == .internal_bake_dev)) - { - j.pushStatic(" "); - line_offset.advance(" "); - } - - switch (comment_type) { - .multiline => { - j.pushStatic("/* "); - line_offset.advance("/* "); - }, - .single => { - j.pushStatic("// "); - line_offset.advance("// "); - }, - } - - j.pushStatic(pretty); - line_offset.advance(pretty); - - if (emit_targets_in_commands) { - j.pushStatic(" ("); - line_offset.advance(" ("); - const target = @tagName(targets[source_index].bakeGraph()); - j.pushStatic(target); - line_offset.advance(target); - j.pushStatic(")"); - line_offset.advance(")"); - } - - switch (comment_type) { - .multiline => { - j.pushStatic(" */\n"); - line_offset.advance(" */\n"); - }, - .single => { - j.pushStatic("\n"); - line_offset.advance("\n"); - }, - } - } - - if (is_runtime) { - if (c.options.output_format != .internal_bake_dev) { - line_offset.advance(compile_result.code()); - j.push(compile_result.code(), bun.default_allocator); - } - } else { - j.push(compile_result.code(), bun.default_allocator); - - if (compile_result.sourceMapChunk()) |source_map_chunk| { - if (c.options.source_maps != .none) { - try compile_results_for_source_map.append(worker.allocator, CompileResultForSourceMap{ - .source_map_chunk = source_map_chunk, - .generated_offset = line_offset.value, - .source_index = compile_result.sourceIndex(), - }); - } - - line_offset.reset(); - } else { - line_offset.advance(compile_result.code()); - } - } - - // TODO: metafile - newline_before_comment = compile_result.code().len > 0; - } - - const tail_code = entry_point_tail.code(); - if (tail_code.len > 0) { - // Stick the entry point tail at the end of the file. Deliberately don't - // include any source mapping information for this because it's automatically - // generated and doesn't correspond to a location in the input file. - j.push(tail_code, worker.allocator); - } - - // Put the cross-chunk suffix inside the IIFE - if (cross_chunk_suffix.result.code.len > 0) { - if (newline_before_comment) { - j.pushStatic("\n"); - } - - j.push(cross_chunk_suffix.result.code, worker.allocator); - } - - switch (output_format) { - .iife => { - const without_newline = "})();"; - - const with_newline = if (newline_before_comment) - without_newline ++ "\n" - else - without_newline; - - j.pushStatic(with_newline); - }, - .internal_bake_dev => { - { - const str = "}, {\n main: "; - j.pushStatic(str); - line_offset.advance(str); - } - { - const input = c.parse_graph.input_files.items(.source)[chunk.entry_point.source_index].path; - var buf = MutableString.initEmpty(worker.allocator); - bun.handleOom(js_printer.quoteForJSON(input.pretty, &buf, true)); - const str = buf.slice(); // worker.allocator is an arena - j.pushStatic(str); - line_offset.advance(str); - } - // { - // const str = "\n react_refresh: "; - // j.pushStatic(str); - // line_offset.advance(str); - // } - { - const str = "\n});"; - j.pushStatic(str); - line_offset.advance(str); - } - }, - .cjs => { - if (is_bun) { - j.pushStatic("})\n"); - line_offset.advance("})\n"); - } - }, - else => {}, - } - - j.ensureNewlineAtEnd(); - // TODO: maybeAppendLegalComments - - if (c.options.footer.len > 0) { - if (newline_before_comment) { - j.pushStatic("\n"); - line_offset.advance("\n"); - } - j.pushStatic(ctx.c.options.footer); - line_offset.advance(ctx.c.options.footer); - j.pushStatic("\n"); - line_offset.advance("\n"); - } - - chunk.intermediate_output = c.breakOutputIntoPieces( - worker.allocator, - &j, - @as(u32, @truncate(ctx.chunks.len)), - ) catch @panic("Unhandled out of memory error in breakOutputIntoPieces()"); - - // TODO: meta contents - - chunk.isolated_hash = c.generateIsolatedHash(chunk); - chunk.flags.is_executable = is_executable; - - if (c.options.source_maps != .none) { - const can_have_shifts = chunk.intermediate_output == .pieces; - chunk.output_source_map = try c.generateSourceMapForChunk( - chunk.isolated_hash, - worker, - compile_results_for_source_map, - c.resolver.opts.output_dir, - can_have_shifts, - ); - } -} - -/// Recursively walk a binding and add all declared names to `ModuleInfo`. -/// Handles `b_identifier`, `b_array`, `b_object`, and `b_missing`. -fn addBindingVarsToModuleInfo( - mi: *analyze_transpiled_module.ModuleInfo, - binding: Binding, - var_kind: analyze_transpiled_module.ModuleInfo.VarKind, - r: renamer.Renamer, - symbols: *const js_ast.Symbol.Map, -) void { - switch (binding.data) { - .b_identifier => |b| { - const name = r.nameForSymbol(symbols.follow(b.ref)); - if (name.len > 0) { - const str_id = mi.str(name) catch return; - mi.addVar(str_id, var_kind) catch {}; - } - }, - .b_array => |b| { - for (b.items) |item| { - addBindingVarsToModuleInfo(mi, item.binding, var_kind, r, symbols); - } - }, - .b_object => |b| { - for (b.properties) |prop| { - addBindingVarsToModuleInfo(mi, prop.value, var_kind, r, symbols); - } - }, - .b_missing => {}, - } -} - -pub fn generateEntryPointTailJS( - c: *LinkerContext, - toCommonJSRef: Ref, - toESMRef: Ref, - source_index: Index.Int, - allocator: std.mem.Allocator, - temp_allocator: std.mem.Allocator, - r: renamer.Renamer, - module_info: ?*analyze_transpiled_module.ModuleInfo, -) CompileResult { - const flags: JSMeta.Flags = c.graph.meta.items(.flags)[source_index]; - var stmts = std.array_list.Managed(Stmt).init(temp_allocator); - defer stmts.deinit(); - const ast: JSAst = c.graph.ast.get(source_index); - - switch (c.options.output_format) { - .esm => { - switch (flags.wrap) { - .cjs => { - stmts.append( - Stmt.alloc( - // "export default require_foo();" - S.ExportDefault, - .{ - .default_name = .{ - .loc = Logger.Loc.Empty, - .ref = ast.wrapper_ref, - }, - .value = .{ - .expr = Expr.init( - E.Call, - E.Call{ - .target = Expr.initIdentifier( - ast.wrapper_ref, - Logger.Loc.Empty, - ), - }, - Logger.Loc.Empty, - ), - }, - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - }, - else => { - if (flags.wrap == .esm and ast.wrapper_ref.isValid()) { - if (flags.is_async_or_has_async_dependency) { - // "await init_foo();" - stmts.append( - Stmt.alloc( - S.SExpr, - .{ - .value = Expr.init( - E.Await, - E.Await{ - .value = Expr.init( - E.Call, - E.Call{ - .target = Expr.initIdentifier( - ast.wrapper_ref, - Logger.Loc.Empty, - ), - }, - Logger.Loc.Empty, - ), - }, - Logger.Loc.Empty, - ), - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - } else { - // "init_foo();" - stmts.append( - Stmt.alloc( - S.SExpr, - .{ - .value = Expr.init( - E.Call, - E.Call{ - .target = Expr.initIdentifier( - ast.wrapper_ref, - Logger.Loc.Empty, - ), - }, - Logger.Loc.Empty, - ), - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - } - } - - const sorted_and_filtered_export_aliases = c.graph.meta.items(.sorted_and_filtered_export_aliases)[source_index]; - - if (sorted_and_filtered_export_aliases.len > 0) { - const resolved_exports: ResolvedExports = c.graph.meta.items(.resolved_exports)[source_index]; - const imports_to_bind: RefImportData = c.graph.meta.items(.imports_to_bind)[source_index]; - - // If the output format is ES6 modules and we're an entry point, generate an - // ES6 export statement containing all exports. Except don't do that if this - // entry point is a CommonJS-style module, since that would generate an ES6 - // export statement that's not top-level. Instead, we will export the CommonJS - // exports as a default export later on. - var items = std.array_list.Managed(js_ast.ClauseItem).init(temp_allocator); - const cjs_export_copies = c.graph.meta.items(.cjs_export_copies)[source_index]; - - var had_default_export = false; - - for (sorted_and_filtered_export_aliases, 0..) |alias, i| { - var resolved_export = resolved_exports.get(alias).?; - - had_default_export = had_default_export or strings.eqlComptime(alias, "default"); - - // If this is an export of an import, reference the symbol that the import - // was eventually resolved to. We need to do this because imports have - // already been resolved by this point, so we can't generate a new import - // and have that be resolved later. - if (imports_to_bind.get(resolved_export.data.import_ref)) |import_data| { - resolved_export.data.import_ref = import_data.data.import_ref; - resolved_export.data.source_index = import_data.data.source_index; - } - - // Exports of imports need EImportIdentifier in case they need to be re- - // written to a property access later on - if (c.graph.symbols.get(resolved_export.data.import_ref).?.namespace_alias != null) { - const temp_ref = cjs_export_copies[i]; - - // Create both a local variable and an export clause for that variable. - // The local variable is initialized with the initial value of the - // export. This isn't fully correct because it's a "dead" binding and - // doesn't update with the "live" value as it changes. But ES6 modules - // don't have any syntax for bare named getter functions so this is the - // best we can do. - // - // These input files: - // - // // entry_point.js - // export {foo} from './cjs-format.js' - // - // // cjs-format.js - // Object.defineProperty(exports, 'foo', { - // enumerable: true, - // get: () => Math.random(), - // }) - // - // Become this output file: - // - // // cjs-format.js - // var require_cjs_format = __commonJS((exports) => { - // Object.defineProperty(exports, "foo", { - // enumerable: true, - // get: () => Math.random() - // }); - // }); - // - // // entry_point.js - // var cjs_format = __toESM(require_cjs_format()); - // var export_foo = cjs_format.foo; - // export { - // export_foo as foo - // }; - // - stmts.append( - Stmt.alloc( - S.Local, - .{ - .decls = js_ast.G.Decl.List.fromSlice( - temp_allocator, - &.{ - .{ - .binding = Binding.alloc( - temp_allocator, - B.Identifier{ - .ref = temp_ref, - }, - Logger.Loc.Empty, - ), - .value = Expr.init( - E.ImportIdentifier, - E.ImportIdentifier{ - .ref = resolved_export.data.import_ref, - }, - Logger.Loc.Empty, - ), - }, - }, - ) catch unreachable, - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - - items.append( - .{ - .name = js_ast.LocRef{ - .ref = temp_ref, - .loc = Logger.Loc.Empty, - }, - .alias = alias, - .alias_loc = Logger.Loc.Empty, - }, - ) catch unreachable; - } else { - // Local identifiers can be exported using an export clause. This is done - // this way instead of leaving the "export" keyword on the local declaration - // itself both because it lets the local identifier be minified and because - // it works transparently for re-exports across files. - // - // These input files: - // - // // entry_point.js - // export * from './esm-format.js' - // - // // esm-format.js - // export let foo = 123 - // - // Become this output file: - // - // // esm-format.js - // let foo = 123; - // - // // entry_point.js - // export { - // foo - // }; - // - items.append(.{ - .name = js_ast.LocRef{ - .ref = resolved_export.data.import_ref, - .loc = resolved_export.data.name_loc, - }, - .alias = alias, - .alias_loc = resolved_export.data.name_loc, - }) catch unreachable; - } - } - - stmts.append( - Stmt.alloc( - S.ExportClause, - .{ - .items = items.items, - .is_single_line = false, - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - - if (flags.needs_synthetic_default_export and !had_default_export) { - var properties = G.Property.List.initCapacity(allocator, items.items.len) catch unreachable; - const getter_fn_body = allocator.alloc(Stmt, items.items.len) catch unreachable; - var remain_getter_fn_body = getter_fn_body; - for (items.items) |export_item| { - var fn_body = remain_getter_fn_body[0..1]; - remain_getter_fn_body = remain_getter_fn_body[1..]; - fn_body[0] = Stmt.alloc( - S.Return, - S.Return{ - .value = Expr.init( - E.Identifier, - E.Identifier{ - .ref = export_item.name.ref.?, - }, - export_item.name.loc, - ), - }, - Logger.Loc.Empty, - ); - properties.appendAssumeCapacity( - G.Property{ - .key = Expr.init( - E.String, - E.String{ - .data = export_item.alias, - .is_utf16 = false, - }, - export_item.alias_loc, - ), - .value = Expr.init( - E.Function, - E.Function{ - .func = G.Fn{ - .body = G.FnBody{ - .loc = Logger.Loc.Empty, - .stmts = fn_body, - }, - }, - }, - export_item.alias_loc, - ), - .kind = G.Property.Kind.get, - .flags = js_ast.Flags.Property.init(.{ - .is_method = true, - }), - }, - ); - } - stmts.append( - Stmt.alloc( - S.ExportDefault, - S.ExportDefault{ - .default_name = .{ - .ref = Ref.None, - .loc = Logger.Loc.Empty, - }, - .value = .{ - .expr = Expr.init( - E.Object, - E.Object{ - .properties = properties, - }, - Logger.Loc.Empty, - ), - }, - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - } - } - }, - } - }, - - // TODO: iife - .iife => {}, - - .internal_bake_dev => { - // nothing needs to be done here, as the exports are already - // forwarded in the module closure. - }, - - .cjs => { - switch (flags.wrap) { - .cjs => { - // "module.exports = require_foo();" - stmts.append( - Stmt.assign( - Expr.init( - E.Dot, - .{ - .target = Expr.initIdentifier(c.unbound_module_ref, Logger.Loc.Empty), - .name = "exports", - .name_loc = Logger.Loc.Empty, - }, - Logger.Loc.Empty, - ), - Expr.init( - E.Call, - .{ - .target = Expr.initIdentifier(ast.wrapper_ref, Logger.Loc.Empty), - }, - Logger.Loc.Empty, - ), - ), - ) catch unreachable; - }, - .esm => { - // "init_foo();" - stmts.append( - Stmt.alloc( - S.SExpr, - .{ - .value = Expr.init( - E.Call, - .{ - .target = Expr.initIdentifier(ast.wrapper_ref, Logger.Loc.Empty), - }, - Logger.Loc.Empty, - ), - }, - Logger.Loc.Empty, - ), - ) catch unreachable; - }, - else => {}, - } - - // TODO: - // If we are generating CommonJS for node, encode the known export names in - // a form that node can understand them. This relies on the specific behavior - // of this parser, which the node project uses to detect named exports in - // CommonJS files: https://github.com/guybedford/cjs-module-lexer. Think of - // this code as an annotation for that parser. - }, - } - - // Add generated local declarations from entry point tail to module_info. - // This captures vars like `var export_foo = cjs.foo` for CJS export copies. - if (module_info) |mi| { - for (stmts.items) |stmt| { - switch (stmt.data) { - .s_local => |s| { - const var_kind: analyze_transpiled_module.ModuleInfo.VarKind = if (s.kind == .k_var) .declared else .lexical; - for (s.decls.slice()) |decl| { - addBindingVarsToModuleInfo(mi, decl.binding, var_kind, r, &c.graph.symbols); - } - }, - else => {}, - } - } - } - - if (stmts.items.len == 0) { - return .{ - .javascript = .{ - .source_index = source_index, - .result = .{ - .result = .{ .code = "" }, - }, - }, - }; - } - - const print_options = js_printer.Options{ - // TODO: IIFE indent - .indent = .{}, - .has_run_symbol_renamer = true, - - .allocator = allocator, - .to_esm_ref = toESMRef, - .to_commonjs_ref = toCommonJSRef, - .require_or_import_meta_for_source_callback = js_printer.RequireOrImportMeta.Callback.init(LinkerContext, LinkerContext.requireOrImportMetaForSource, c), - - .minify_whitespace = c.options.minify_whitespace, - .print_dce_annotations = c.options.emit_dce_annotations, - .minify_syntax = c.options.minify_syntax, - .mangled_props = &c.mangled_props, - .module_info = module_info, - // .const_values = c.graph.const_values, - }; - - return .{ - .javascript = .{ - .result = js_printer.print( - allocator, - c.resolver.opts.target, - ast.toAST(), - c.getSource(source_index), - print_options, - ast.import_records.slice(), - &[_]Part{ - .{ - .stmts = stmts.items, - }, - }, - r, - false, - ), - .source_index = source_index, - }, - }; -} - -const analyze_transpiled_module = @import("../analyze_transpiled_module.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const ImportRecord = bun.ImportRecord; -const Logger = bun.logger; -const MutableString = bun.MutableString; -const StringJoiner = bun.StringJoiner; -const options = bun.options; -const strings = bun.strings; - -const Chunk = bun.bundle_v2.Chunk; -const CompileResult = bun.bundle_v2.CompileResult; -const CompileResultForSourceMap = bun.bundle_v2.CompileResultForSourceMap; -const Fs = bun.bundle_v2.Fs; -const Index = bun.bundle_v2.Index; -const JSAst = bun.bundle_v2.JSAst; -const JSMeta = bun.bundle_v2.JSMeta; -const Part = bun.bundle_v2.Part; -const RefImportData = bun.bundle_v2.RefImportData; -const ResolvedExports = bun.bundle_v2.ResolvedExports; -const ThreadPool = bun.bundle_v2.ThreadPool; -const js_printer = bun.bundle_v2.js_printer; -const renamer = bun.bundle_v2.renamer; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const GenerateChunkCtx = bun.bundle_v2.LinkerContext.GenerateChunkCtx; - -const js_ast = bun.bundle_v2.js_ast; -const B = js_ast.B; -const Binding = js_ast.Binding; -const E = js_ast.E; -const Expr = js_ast.Expr; -const G = js_ast.G; -const Ref = bun.bundle_v2.js_ast.Ref; -const S = js_ast.S; -const Scope = js_ast.Scope; -const Stmt = js_ast.Stmt; diff --git a/src/bundler/linker_context/prepareCssAstsForChunk.zig b/src/bundler/linker_context/prepareCssAstsForChunk.zig deleted file mode 100644 index d7d8883707c1..000000000000 --- a/src/bundler/linker_context/prepareCssAstsForChunk.zig +++ /dev/null @@ -1,331 +0,0 @@ -pub const PrepareCssAstTask = struct { - task: ThreadPoolLib.Task, - chunk: *Chunk, - linker: *LinkerContext, -}; - -pub fn prepareCssAstsForChunk(task: *ThreadPoolLib.Task) void { - const prepare_css_asts: *const PrepareCssAstTask = @fieldParentPtr("task", task); - var worker = ThreadPool.Worker.get(@fieldParentPtr("linker", prepare_css_asts.linker)); - defer worker.unget(); - - prepareCssAstsForChunkImpl(prepare_css_asts.linker, prepare_css_asts.chunk, worker.allocator); -} - -fn prepareCssAstsForChunkImpl(c: *LinkerContext, chunk: *Chunk, allocator: std.mem.Allocator) void { - const asts: []const ?*bun.css.BundlerStyleSheet = c.graph.ast.items(.css); - - // Prepare CSS asts - // Remove duplicate rules across files. This must be done in serial, not - // in parallel, and must be done from the last rule to the first rule. - { - var i: usize = chunk.content.css.imports_in_chunk_in_order.len; - while (i != 0) { - i -= 1; - const entry = chunk.content.css.imports_in_chunk_in_order.mut(i); - switch (entry.kind) { - .layers => |layers| { - const len = layers.inner().len; - var rules = bun.css.BundlerCssRuleList{}; - if (len > 0) { - rules.v.append(allocator, bun.css.BundlerCssRule{ - .layer_statement = bun.css.LayerStatementRule{ - .names = bun.css.SmallList(bun.css.LayerName, 1).fromBabyListNoDeinit(layers.inner().*), - .loc = bun.css.Location.dummy(), - }, - }) catch |err| bun.handleOom(err); - } - var ast = bun.css.BundlerStyleSheet{ - .rules = rules, - .sources = .{}, - .source_map_urls = .{}, - .license_comments = .{}, - .options = bun.css.ParserOptions.default(allocator, null), - .composes = .{}, - }; - wrapRulesWithConditions(&ast, allocator, &entry.conditions); - chunk.content.css.asts[i] = ast; - }, - .external_path => |*p| { - var conditions: ?*bun.css.ImportConditions = null; - if (entry.conditions.len > 0) { - conditions = entry.conditions.mut(0); - entry.condition_import_records.append( - allocator, - bun.ImportRecord{ .kind = .at, .path = p.*, .range = Logger.Range{} }, - ) catch |err| bun.handleOom(err); - - // Handling a chain of nested conditions is complicated. We can't - // necessarily join them together because a) there may be multiple - // layer names and b) layer names are only supposed to be inserted - // into the layer order if the parent conditions are applied. - // - // Instead we handle them by preserving the "@import" nesting using - // imports of data URL stylesheets. This may seem strange but I think - // this is the only way to do this in CSS. - var j: usize = entry.conditions.len; - while (j != 1) { - j -= 1; - - const ast_import = bun.css.BundlerStyleSheet{ - .options = bun.css.ParserOptions.default(allocator, null), - .license_comments = .{}, - .sources = .{}, - .source_map_urls = .{}, - .rules = rules: { - var rules = bun.css.BundlerCssRuleList{}; - var import_rule = bun.css.ImportRule{ - .url = p.pretty, - .import_record_idx = entry.condition_import_records.len, - .loc = bun.css.Location.dummy(), - }; - import_rule.conditionsMut().* = entry.conditions.at(j).*; - rules.v.append(allocator, bun.css.BundlerCssRule{ - .import = import_rule, - }) catch |err| bun.handleOom(err); - break :rules rules; - }, - .composes = .{}, - }; - - const printer_options = bun.css.PrinterOptions{ - .targets = bun.css.Targets.forBundlerTarget(c.options.target), - // TODO: make this more configurable - .minify = c.options.minify_whitespace or c.options.minify_syntax or c.options.minify_identifiers, - }; - - const print_result = switch (ast_import.toCss( - allocator, - printer_options, - .{ - .import_records = &entry.condition_import_records, - .ast_urls_for_css = c.parse_graph.ast.items(.url_for_css), - .ast_unique_key_for_additional_file = c.parse_graph.input_files.items(.unique_key_for_additional_file), - }, - &c.mangled_props, - &c.graph.symbols, - )) { - .result => |v| v, - .err => |e| { - bun.handleOom(c.log.addErrorFmt(null, Loc.Empty, c.allocator(), "Error generating CSS for import: {f}", .{e})); - continue; - }, - }; - p.* = bun.fs.Path.init(DataURL.encodeStringAsShortestDataURL(allocator, "text/css", std.mem.trim(u8, print_result.code, " \n\r\t"))); - } - } - - var empty_conditions = bun.css.ImportConditions{}; - const actual_conditions = if (conditions) |cc| cc else &empty_conditions; - - entry.condition_import_records.append(allocator, bun.ImportRecord{ - .kind = .at, - .path = p.*, - .range = Logger.Range.none, - }) catch |err| bun.handleOom(err); - - chunk.content.css.asts[i] = bun.css.BundlerStyleSheet{ - .rules = rules: { - var rules = bun.css.BundlerCssRuleList{}; - var import_rule = bun.css.ImportRule.fromUrlAndImportRecordIdx(p.pretty, entry.condition_import_records.len); - import_rule.conditionsMut().* = actual_conditions.*; - rules.v.append(allocator, bun.css.BundlerCssRule{ - .import = import_rule, - }) catch |err| bun.handleOom(err); - break :rules rules; - }, - .sources = .{}, - .source_map_urls = .{}, - .license_comments = .{}, - .options = bun.css.ParserOptions.default(allocator, null), - .composes = .{}, - }; - }, - .source_index => |source_index| { - // Multiple imports may refer to the same file/AST, but they - // may wrap or modify the AST in different ways. So we need - // to make a shallow copy and be careful not to modify shared - // references. - var ast = ast: { - const original_stylesheet = asts[source_index.get()].?; - chunk.content.css.asts[i] = original_stylesheet.*; - break :ast &chunk.content.css.asts[i]; - }; - - { - // Strip leading "@import" and ".ignored" rules. Any - // "@layer" statement rules interleaved with them are - // preserved, because they carry layer ordering - // information that is not re-emitted elsewhere by - // the bundler (e.g. Tailwind's - // `@layer theme, base, components, utilities;`). - // - // IMPORTANT: `ast` is only a shallow copy of the - // per-source stylesheet, so `ast.rules.v.items` still - // points at the backing array owned by - // `c.graph.ast.items(.css)`. We MUST NOT mutate that - // buffer in place — a second import of the same - // source_index would observe the compacted prefix and - // drop rules. Instead we either reslice the copied - // header (fast path) or build a fresh rules list. - // - // Regression: #28914 - const original_rules = ast.rules.v.items; - var layer_count: usize = 0; - var prefix_end: usize = original_rules.len; - prefix_scan: for (original_rules, 0..) |rule, idx| { - switch (rule) { - .import, .ignored => {}, - .layer_statement => layer_count += 1, - else => { - prefix_end = idx; - break :prefix_scan; - }, - } - } - const dropped = prefix_end - layer_count; - - if (dropped == 0) { - // Prefix is all "@layer" (or empty). Nothing to - // strip — leave `ast.rules.v` untouched. - } else if (layer_count == 0) { - // Fast path: no "@layer" statements to preserve, - // reslice the copied header forward. This does - // not touch the backing array. - const tail = original_rules[prefix_end..]; - ast.rules.v = .{ - .items = tail, - .capacity = ast.rules.v.capacity - (original_rules.len - tail.len), - }; - } else { - // Interleaved case: allocate a fresh rules list - // so we don't mutate the shared backing array. - // Preserve the "@layer" statements from the - // prefix and append the remaining tail. - var new_rules = bun.css.BundlerCssRuleList{}; - for (original_rules[0..prefix_end]) |rule| { - if (rule == .layer_statement) { - new_rules.v.append(allocator, rule) catch |err| bun.handleOom(err); - } - } - for (original_rules[prefix_end..]) |rule| { - new_rules.v.append(allocator, rule) catch |err| bun.handleOom(err); - } - ast.rules = new_rules; - } - } - - wrapRulesWithConditions(ast, allocator, &entry.conditions); - // TODO: Remove top-level duplicate rules across files - }, - } - } - } -} - -fn wrapRulesWithConditions( - ast: *bun.css.BundlerStyleSheet, - temp_allocator: std.mem.Allocator, - conditions: *const BabyList(bun.css.ImportConditions), -) void { - var dummy_import_records = bun.BabyList(bun.ImportRecord){}; - defer bun.debugAssert(dummy_import_records.len == 0); - - var i: usize = conditions.len; - while (i > 0) { - i -= 1; - const item = conditions.at(i); - - // Generate "@layer" wrappers. Note that empty "@layer" rules still have - // a side effect (they set the layer order) so they cannot be removed. - if (item.layer) |l| { - const layer = l.v; - var do_block_rule = true; - if (ast.rules.v.items.len == 0) { - if (l.v == null) { - // Omit an empty "@layer {}" entirely - continue; - } else { - // Generate "@layer foo;" instead of "@layer foo {}" - ast.rules.v = .{}; - do_block_rule = false; - } - } - - ast.rules = brk: { - var new_rules = bun.css.BundlerCssRuleList{}; - new_rules.v.append( - temp_allocator, - if (do_block_rule) .{ .layer_block = bun.css.BundlerLayerBlockRule{ - .name = layer, - .rules = ast.rules, - .loc = bun.css.Location.dummy(), - } } else .{ - .layer_statement = .{ - .names = if (layer) |ly| bun.css.SmallList(bun.css.LayerName, 1).withOne(ly) else .{}, - .loc = bun.css.Location.dummy(), - }, - }, - ) catch |err| bun.handleOom(err); - - break :brk new_rules; - }; - } - - // Generate "@supports" wrappers. This is not done if the rule block is - // empty because empty "@supports" rules have no effect. - if (ast.rules.v.items.len > 0) { - if (item.supports) |*supports| { - ast.rules = brk: { - var new_rules = bun.css.BundlerCssRuleList{}; - new_rules.v.append(temp_allocator, .{ - .supports = bun.css.BundlerSupportsRule{ - .condition = supports.cloneWithImportRecords( - temp_allocator, - &dummy_import_records, - ), - .rules = ast.rules, - .loc = bun.css.Location.dummy(), - }, - }) catch |err| bun.handleOom(err); - break :brk new_rules; - }; - } - } - - // Generate "@media" wrappers. This is not done if the rule block is - // empty because empty "@media" rules have no effect. - if (ast.rules.v.items.len > 0 and item.media.media_queries.items.len > 0) { - ast.rules = brk: { - var new_rules = bun.css.BundlerCssRuleList{}; - new_rules.v.append(temp_allocator, .{ - .media = bun.css.BundlerMediaRule{ - .query = item.media.cloneWithImportRecords(temp_allocator, &dummy_import_records), - .rules = ast.rules, - .loc = bun.css.Location.dummy(), - }, - }) catch |err| bun.handleOom(err); - break :brk new_rules; - }; - } - } -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const std = @import("std"); - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const ImportRecord = bun.ImportRecord; -const ThreadPoolLib = bun.ThreadPool; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const DataURL = bun.bundle_v2.DataURL; -const LinkerContext = bun.bundle_v2.LinkerContext; - -const Logger = bun.logger; -const Loc = Logger.Loc; diff --git a/src/bundler/linker_context/renameSymbolsInChunk.zig b/src/bundler/linker_context/renameSymbolsInChunk.zig deleted file mode 100644 index 0e88ef97ae9e..000000000000 --- a/src/bundler/linker_context/renameSymbolsInChunk.zig +++ /dev/null @@ -1,276 +0,0 @@ -/// TODO: investigate if we need to parallelize this function -/// esbuild does parallelize it. -pub fn renameSymbolsInChunk( - c: *LinkerContext, - allocator: std.mem.Allocator, - chunk: *Chunk, - files_in_order: []const u32, -) !renamer.Renamer { - const trace = bun.perf.trace("Bundler.renameSymbolsInChunk"); - defer trace.end(); - const all_module_scopes = c.graph.ast.items(.module_scope); - const all_flags: []const JSMeta.Flags = c.graph.meta.items(.flags); - const all_parts: []const Part.List = c.graph.ast.items(.parts); - const all_wrapper_refs: []const Ref = c.graph.ast.items(.wrapper_ref); - const all_import_records: []const ImportRecord.List = c.graph.ast.items(.import_records); - - var reserved_names = try renamer.computeInitialReservedNames(allocator, c.options.output_format); - for (files_in_order) |source_index| { - renamer.computeReservedNamesForScope(&all_module_scopes[source_index], &c.graph.symbols, &reserved_names, allocator); - } - - var sorted_imports_from_other_chunks: std.array_list.Managed(StableRef) = brk: { - var list = std.array_list.Managed(StableRef).init(allocator); - var count: u32 = 0; - const imports_from_other_chunks = chunk.content.javascript.imports_from_other_chunks.values(); - for (imports_from_other_chunks) |item| { - count += item.len; - } - - list.ensureTotalCapacityPrecise(count) catch unreachable; - list.items.len = count; - var remain = list.items; - const stable_source_indices = c.graph.stable_source_indices; - for (imports_from_other_chunks) |item| { - for (item.slice()) |ref| { - remain[0] = StableRef{ - .stable_source_index = stable_source_indices[ref.ref.sourceIndex()], - .ref = ref.ref, - }; - remain = remain[1..]; - } - } - - std.sort.pdq(StableRef, list.items, {}, StableRef.isLessThan); - break :brk list; - }; - defer sorted_imports_from_other_chunks.deinit(); - - if (c.options.minify_identifiers) { - const first_top_level_slots: js_ast.SlotCounts = brk: { - var slots = js_ast.SlotCounts{}; - const nested_scope_slot_counts = c.graph.ast.items(.nested_scope_slot_counts); - for (files_in_order) |i| { - slots.unionMax(nested_scope_slot_counts[i]); - } - break :brk slots; - }; - - var minify_renamer = try MinifyRenamer.init(allocator, c.graph.symbols, first_top_level_slots, reserved_names); - - var top_level_symbols = renamer.StableSymbolCount.Array.init(allocator); - defer top_level_symbols.deinit(); - - var top_level_symbols_all = renamer.StableSymbolCount.Array.init(allocator); - - const stable_source_indices = c.graph.stable_source_indices; - var freq = js_ast.CharFreq{ - .freqs = [_]i32{0} ** 64, - }; - const ast_flags_list = c.graph.ast.items(.flags); - - var capacity = sorted_imports_from_other_chunks.items.len; - { - const char_freqs = c.graph.ast.items(.char_freq); - - for (files_in_order) |source_index| { - if (ast_flags_list[source_index].has_char_freq) { - freq.include(char_freqs[source_index]); - } - } - } - - const exports_ref_list = c.graph.ast.items(.exports_ref); - const module_ref_list = c.graph.ast.items(.module_ref); - const parts_list = c.graph.ast.items(.parts); - - for (files_in_order) |source_index| { - const ast_flags = ast_flags_list[source_index]; - const uses_exports_ref = ast_flags.uses_exports_ref; - const uses_module_ref = ast_flags.uses_module_ref; - const exports_ref = exports_ref_list[source_index]; - const module_ref = module_ref_list[source_index]; - const parts = parts_list[source_index]; - - top_level_symbols.clearRetainingCapacity(); - - if (uses_exports_ref) { - try minify_renamer.accumulateSymbolUseCount(&top_level_symbols, exports_ref, 1, stable_source_indices); - } - if (uses_module_ref) { - try minify_renamer.accumulateSymbolUseCount(&top_level_symbols, module_ref, 1, stable_source_indices); - } - - for (parts.slice()) |part| { - if (!part.is_live) { - continue; - } - - try minify_renamer.accumulateSymbolUseCounts(&top_level_symbols, part.symbol_uses, stable_source_indices); - - for (part.declared_symbols.refs()) |declared_ref| { - try minify_renamer.accumulateSymbolUseCount(&top_level_symbols, declared_ref, 1, stable_source_indices); - } - } - - std.sort.pdq(renamer.StableSymbolCount, top_level_symbols.items, {}, StableSymbolCount.lessThan); - capacity += top_level_symbols.items.len; - top_level_symbols_all.appendSlice(top_level_symbols.items) catch unreachable; - } - - top_level_symbols.clearRetainingCapacity(); - for (sorted_imports_from_other_chunks.items) |stable_ref| { - try minify_renamer.accumulateSymbolUseCount(&top_level_symbols, stable_ref.ref, 1, stable_source_indices); - } - top_level_symbols_all.appendSlice(top_level_symbols.items) catch unreachable; - try minify_renamer.allocateTopLevelSymbolSlots(top_level_symbols_all); - - var minifier = freq.compile(allocator); - try minify_renamer.assignNamesByFrequency(&minifier); - - return minify_renamer.toRenamer(); - } - - var r = try renamer.NumberRenamer.init( - allocator, - allocator, - c.graph.symbols, - reserved_names, - ); - for (sorted_imports_from_other_chunks.items) |stable_ref| { - r.addTopLevelSymbol(stable_ref.ref); - } - - var sorted_ = std.array_list.Managed(u32).init(r.temp_allocator); - var sorted = &sorted_; - defer sorted.deinit(); - - for (files_in_order) |source_index| { - const wrap = all_flags[source_index].wrap; - const parts: []const Part = all_parts[source_index].slice(); - - switch (wrap) { - // Modules wrapped in a CommonJS closure look like this: - // - // // foo.js - // var require_foo = __commonJS((exports, module) => { - // exports.foo = 123; - // }); - // - // The symbol "require_foo" is stored in "file.ast.WrapperRef". We want - // to be able to minify everything inside the closure without worrying - // about collisions with other CommonJS modules. Set up the scopes such - // that it appears as if the file was structured this way all along. It's - // not completely accurate (e.g. we don't set the parent of the module - // scope to this new top-level scope) but it's good enough for the - // renaming code. - .cjs => { - r.addTopLevelSymbol(all_wrapper_refs[source_index]); - - // External import statements will be hoisted outside of the CommonJS - // wrapper if the output format supports import statements. We need to - // add those symbols to the top-level scope to avoid causing name - // collisions. This code special-cases only those symbols. - if (c.options.output_format.keepES6ImportExportSyntax()) { - const import_records = all_import_records[source_index].slice(); - for (parts) |*part| { - for (part.stmts) |stmt| { - switch (stmt.data) { - .s_import => |import| { - if (!import_records[import.import_record_index].source_index.isValid()) { - r.addTopLevelSymbol(import.namespace_ref); - if (import.default_name) |default_name| { - if (default_name.ref) |ref| { - r.addTopLevelSymbol(ref); - } - } - - for (import.items) |*item| { - if (item.name.ref) |ref| { - r.addTopLevelSymbol(ref); - } - } - } - }, - .s_export_star => |export_| { - if (!import_records[export_.import_record_index].source_index.isValid()) { - r.addTopLevelSymbol(export_.namespace_ref); - } - }, - .s_export_from => |export_| { - if (!import_records[export_.import_record_index].source_index.isValid()) { - r.addTopLevelSymbol(export_.namespace_ref); - - for (export_.items) |*item| { - if (item.name.ref) |ref| { - r.addTopLevelSymbol(ref); - } - } - } - }, - else => {}, - } - } - } - } - r.assignNamesRecursiveWithNumberScope(&r.root, &all_module_scopes[source_index], source_index, sorted); - continue; - }, - - // Modules wrapped in an ESM closure look like this: - // - // // foo.js - // var foo, foo_exports = {}; - // __export(foo_exports, { - // foo: () => foo - // }); - // let init_foo = __esm(() => { - // foo = 123; - // }); - // - // The symbol "init_foo" is stored in "file.ast.WrapperRef". We need to - // minify everything inside the closure without introducing a new scope - // since all top-level variables will be hoisted outside of the closure. - .esm => { - r.addTopLevelSymbol(all_wrapper_refs[source_index]); - }, - - else => {}, - } - - for (parts) |*part| { - if (!part.is_live) continue; - - r.addTopLevelDeclaredSymbols(part.declared_symbols); - for (part.scopes) |scope| { - r.assignNamesRecursiveWithNumberScope(&r.root, scope, source_index, sorted); - } - r.number_scope_pool.hive.used = @TypeOf(r.number_scope_pool.hive.used).initEmpty(); - } - } - - return r.toRenamer(); -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const std = @import("std"); - -const bun = @import("bun"); -const ImportRecord = bun.ImportRecord; - -const js_ast = bun.ast; -const Part = js_ast.Part; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const JSMeta = bundler.JSMeta; -const LinkerContext = bun.bundle_v2.LinkerContext; -const Ref = bun.bundle_v2.Ref; -const StableRef = bundler.StableRef; - -const renamer = bun.renamer; -const MinifyRenamer = renamer.MinifyRenamer; -const StableSymbolCount = renamer.StableSymbolCount; diff --git a/src/bundler/linker_context/scanImportsAndExports.zig b/src/bundler/linker_context/scanImportsAndExports.zig deleted file mode 100644 index b6bdb6bf0a31..000000000000 --- a/src/bundler/linker_context/scanImportsAndExports.zig +++ /dev/null @@ -1,1261 +0,0 @@ -pub const ScanImportsAndExportsError = bun.OOM || error{ImportResolutionFailed}; - -pub fn scanImportsAndExports(this: *LinkerContext) ScanImportsAndExportsError!void { - const outer_trace = bun.perf.trace("Bundler.scanImportsAndExports"); - defer outer_trace.end(); - const reachable = this.graph.reachable_files; - const output_format = this.options.output_format; - { - var import_records_list: []ImportRecord.List = this.graph.ast.items(.import_records); - - // var parts_list: [][]Part = this.graph.ast.items(.parts); - var exports_kind: []js_ast.ExportsKind = this.graph.ast.items(.exports_kind); - var entry_point_kinds: []EntryPoint.Kind = this.graph.files.items(.entry_point_kind); - var named_imports: []js_ast.Ast.NamedImports = this.graph.ast.items(.named_imports); - var flags: []JSMeta.Flags = this.graph.meta.items(.flags); - - const input_files = this.parse_graph.input_files.items(.source); - const loaders: []const Loader = this.parse_graph.input_files.items(.loader); - - const export_star_import_records: [][]u32 = this.graph.ast.items(.export_star_import_records); - const exports_refs: []Ref = this.graph.ast.items(.exports_ref); - const module_refs: []Ref = this.graph.ast.items(.module_ref); - const ast_flags_list = this.graph.ast.items(.flags); - - const css_asts: []?*bun.css.BundlerStyleSheet = this.graph.ast.items(.css); - - var symbols = &this.graph.symbols; - defer this.graph.symbols = symbols.*; - - // Step 1: Figure out what modules must be CommonJS - for (reachable) |source_index_| { - const trace = bun.perf.trace("Bundler.FigureOutCommonJS"); - defer trace.end(); - const id = source_index_.get(); - - // does it have a JS AST? - if (!(id < import_records_list.len)) continue; - - const import_records: []ImportRecord = import_records_list[id].slice(); - - // Is it CSS? - if (css_asts[id] != null) { - const css_ast = css_asts[id].?; - // Inline URLs for non-CSS files into the CSS file - _ = this.scanCSSImports( - id, - import_records, - css_asts, - input_files, - loaders, - this.log, - ); - - // Validate cross-file "composes: ... from" named imports - for (css_ast.composes.values()) |*composes| { - for (composes.composes.slice()) |*compose| { - if (compose.from == null or compose.from.? != .import_record_index) continue; - const import_record_idx = compose.from.?.import_record_index; - const record = &import_records[import_record_idx]; - if (!record.source_index.isValid()) continue; - const other_css_ast = css_asts[record.source_index.get()] orelse continue; - for (compose.names.slice()) |name| { - if (!other_css_ast.local_scope.contains(name.v)) { - try this.log.addErrorFmt( - &input_files[record.source_index.get()], - compose.loc, - this.allocator(), - "The name \"{s}\" never appears in \"{s}\" as a CSS modules locally scoped class name. Note that \"composes\" only works with single class selectors.", - .{ - name.v, - input_files[record.source_index.get()].path.pretty, - }, - ); - } - } - } - } - validateComposesFromProperties(this, id, css_ast, import_records_list, css_asts); - - continue; - } - - for (import_records) |record| { - if (!record.source_index.isValid()) { - continue; - } - - const other_file = record.source_index.get(); - const other_flags = ast_flags_list[other_file]; - // other file is empty - if (other_file >= exports_kind.len) continue; - const other_kind = exports_kind[other_file]; - - switch (record.kind) { - .stmt => { - // Importing using ES6 syntax from a file without any ES6 syntax - // causes that module to be considered CommonJS-style, even if it - // doesn't have any CommonJS exports. - // - // That means the ES6 imports will become undefined instead of - // causing errors. This is for compatibility with older CommonJS- - // style bundlers. - // - // We emit a warning in this case but try to avoid turning the module - // into a CommonJS module if possible. This is possible with named - // imports (the module stays an ECMAScript module but the imports are - // rewritten with undefined) but is not possible with star or default - // imports: - // - // import * as ns from './empty-file' - // import defVal from './empty-file' - // console.log(ns, defVal) - // - // In that case the module *is* considered a CommonJS module because - // the namespace object must be created. - if ((record.flags.contains_import_star or record.flags.contains_default_alias) and - !other_flags.has_lazy_export and !other_flags.force_cjs_to_esm and - exports_kind[other_file] == .none) - { - exports_kind[other_file] = .cjs; - flags[other_file].wrap = .cjs; - } - - if (record.flags.contains_default_alias and - other_flags.force_cjs_to_esm) - { - exports_kind[other_file] = .cjs; - flags[other_file].wrap = .cjs; - } - }, - .require => - // Files that are imported with require() must be CommonJS modules - { - if (other_kind == .esm) { - flags[other_file].wrap = .esm; - } else { - // TODO: introduce a NamedRequire for require("./foo").Bar AST nodes to support tree-shaking those. - flags[other_file].wrap = .cjs; - exports_kind[other_file] = .cjs; - } - }, - .dynamic => { - if (!this.graph.code_splitting) { - // If we're not splitting, then import() is just a require() that - // returns a promise, so the imported file must be a CommonJS module - if (exports_kind[other_file] == .esm) { - flags[other_file].wrap = .esm; - } else { - // TODO: introduce a NamedRequire for require("./foo").Bar AST nodes to support tree-shaking those. - flags[other_file].wrap = .cjs; - exports_kind[other_file] = .cjs; - } - } - }, - else => {}, - } - } - - const kind = exports_kind[id]; - - // If the output format doesn't have an implicit CommonJS wrapper, any file - // that uses CommonJS features will need to be wrapped, even though the - // resulting wrapper won't be invoked by other files. An exception is - // made for entry point files in CommonJS format (or when in pass-through mode). - if (kind == .cjs and (!entry_point_kinds[id].isEntryPoint() or output_format == .iife or output_format == .esm)) { - flags[id].wrap = .cjs; - } - } - - if (comptime Environment.enable_logs) { - var cjs_count: usize = 0; - var esm_count: usize = 0; - var wrap_cjs_count: usize = 0; - var wrap_esm_count: usize = 0; - for (exports_kind) |kind| { - cjs_count += @intFromBool(kind == .cjs); - esm_count += @intFromBool(kind == .esm); - } - - for (flags) |flag| { - wrap_cjs_count += @intFromBool(flag.wrap == .cjs); - wrap_esm_count += @intFromBool(flag.wrap == .esm); - } - - debug("Step 1: {d} CommonJS modules (+ {d} wrapped), {d} ES modules (+ {d} wrapped)", .{ - cjs_count, - wrap_cjs_count, - esm_count, - wrap_esm_count, - }); - } - - // Step 2: Propagate dynamic export status for export star statements that - // are re-exports from a module whose exports are not statically analyzable. - // In this case the export star must be evaluated at run time instead of at - // bundle time. - - { - const trace = bun.perf.trace("Bundler.WrapDependencies"); - defer trace.end(); - var dependency_wrapper = DependencyWrapper{ - .linker = this, - .flags = flags, - .import_records = import_records_list, - .exports_kind = exports_kind, - .entry_point_kinds = entry_point_kinds, - .export_star_map = std.AutoHashMap(u32, void).init(this.allocator()), - .export_star_records = export_star_import_records, - .output_format = output_format, - }; - defer dependency_wrapper.export_star_map.deinit(); - - for (reachable) |source_index_| { - const source_index = source_index_.get(); - const id = source_index; - - // does it have a JS AST? - if (!(id < import_records_list.len)) continue; - - if (flags[id].wrap != .none) { - dependency_wrapper.wrap(id); - } - - if (export_star_import_records[id].len > 0) { - dependency_wrapper.export_star_map.clearRetainingCapacity(); - _ = dependency_wrapper.hasDynamicExportsDueToExportStar(id); - } - - // Even if the output file is CommonJS-like, we may still need to wrap - // CommonJS-style files. Any file that imports a CommonJS-style file will - // cause that file to need to be wrapped. This is because the import - // method, whatever it is, will need to invoke the wrapper. Note that - // this can include entry points (e.g. an entry point that imports a file - // that imports that entry point). - for (import_records_list[id].slice()) |record| { - if (record.source_index.isValid()) { - if (exports_kind[record.source_index.get()] == .cjs) { - dependency_wrapper.wrap(record.source_index.get()); - } - } - } - } - } - - // Step 3: Resolve "export * from" statements. This must be done after we - // discover all modules that can have dynamic exports because export stars - // are ignored for those modules. - { - var export_star_ctx: ?ExportStarContext = null; - const trace = bun.perf.trace("Bundler.ResolveExportStarStatements"); - defer trace.end(); - defer { - if (export_star_ctx) |*export_ctx| { - export_ctx.source_index_stack.deinit(); - } - } - var resolved_exports: []ResolvedExports = this.graph.meta.items(.resolved_exports); - var resolved_export_stars: []ExportData = this.graph.meta.items(.resolved_export_star); - - for (reachable) |source_index_| { - const source_index = source_index_.get(); - const id = source_index; - - // Expression-style loaders defer code generation until linking. Code - // generation is done here because at this point we know that the - // "ExportsKind" field has its final value and will not be changed. - if (ast_flags_list[id].has_lazy_export) { - try this.generateCodeForLazyExport(id); - } - - // Propagate exports for export star statements - const export_star_ids = export_star_import_records[id]; - if (export_star_ids.len > 0) { - if (export_star_ctx == null) { - export_star_ctx = ExportStarContext{ - .allocator = this.allocator(), - .resolved_exports = resolved_exports, - .import_records_list = import_records_list, - .export_star_records = export_star_import_records, - - .imports_to_bind = this.graph.meta.items(.imports_to_bind), - - .source_index_stack = try std.array_list.Managed(u32).initCapacity(this.allocator(), 32), - .exports_kind = exports_kind, - .named_exports = this.graph.ast.items(.named_exports), - }; - } - export_star_ctx.?.addExports(&resolved_exports[id], source_index); - } - - // Also add a special export so import stars can bind to it. This must be - // done in this step because it must come after CommonJS module discovery - // but before matching imports with exports. - resolved_export_stars[id] = ExportData{ - .data = .{ - .source_index = Index.source(source_index), - .import_ref = exports_refs[id], - }, - }; - } - } - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.checkForMemoryCorruption(); - } - - // Step 4: Match imports with exports. This must be done after we process all - // export stars because imports can bind to export star re-exports. - { - this.cycle_detector.clearRetainingCapacity(); - const trace = bun.perf.trace("Bundler.MatchImportsWithExports"); - defer trace.end(); - const wrapper_part_indices = this.graph.meta.items(.wrapper_part_index); - const imports_to_bind = this.graph.meta.items(.imports_to_bind); - for (reachable) |source_index_| { - const source_index = source_index_.get(); - - // not a JS ast or empty - if (source_index >= named_imports.len) { - continue; - } - - const named_imports_ = &named_imports[source_index]; - if (named_imports_.count() > 0) { - this.matchImportsWithExportsForFile( - named_imports_, - &imports_to_bind[source_index], - source_index, - ); - - if (this.log.errors > 0) { - return error.ImportResolutionFailed; - } - } - const export_kind = exports_kind[source_index]; - var flag = flags[source_index]; - // If we're exporting as CommonJS and this file was originally CommonJS, - // then we'll be using the actual CommonJS "exports" and/or "module" - // symbols. In that case make sure to mark them as such so they don't - // get minified. - if ((output_format == .cjs) and - entry_point_kinds[source_index].isEntryPoint() and - export_kind == .cjs and flag.wrap == .none) - { - const exports_ref = symbols.follow(exports_refs[source_index]); - const module_ref = symbols.follow(module_refs[source_index]); - symbols.get(exports_ref).?.kind = .unbound; - symbols.get(module_ref).?.kind = .unbound; - } else if (flag.force_include_exports_for_entry_point or export_kind != .cjs) { - flag.needs_exports_variable = true; - flags[source_index] = flag; - } - - const wrapped_ref = this.graph.ast.items(.wrapper_ref)[source_index]; - - // Create the wrapper part for wrapped files. This is needed by a later step. - this.createWrapperForFile( - flag.wrap, - // if this one is null, the AST does not need to be wrapped. - wrapped_ref, - &wrapper_part_indices[source_index], - source_index, - ); - } - } - - // Step 5: Create namespace exports for every file. This is always necessary - // for CommonJS files, and is also necessary for other files if they are - // imported using an import star statement. - // Note: `do` will wait for all to finish before moving forward - try this.parse_graph.pool.worker_pool.each( - this.allocator(), - this, - LinkerContext.doStep5, - this.graph.reachable_files, - ); - - // Some parts of the AST may now be owned by worker allocators. Transfer ownership back - // to the graph allocator. - this.graph.takeAstOwnership(); - } - - if (comptime FeatureFlags.help_catch_memory_issues) { - this.checkForMemoryCorruption(); - } - - // Step 6: Bind imports to exports. This adds non-local dependencies on the - // parts that declare the export to all parts that use the import. Also - // generate wrapper parts for wrapped files. - { - const trace = bun.perf.trace("Bundler.BindImportsToExports"); - defer trace.end(); - // const needs_export_symbol_from_runtime: []const bool = this.graph.meta.items(.needs_export_symbol_from_runtime); - - var runtime_export_symbol_ref: Ref = Ref.None; - var entry_point_kinds: []EntryPoint.Kind = this.graph.files.items(.entry_point_kind); - var flags: []JSMeta.Flags = this.graph.meta.items(.flags); - var ast_fields = this.graph.ast.slice(); - - const wrapper_refs = ast_fields.items(.wrapper_ref); - const exports_kind = ast_fields.items(.exports_kind); - const exports_refs = ast_fields.items(.exports_ref); - const module_refs = ast_fields.items(.module_ref); - const named_imports = ast_fields.items(.named_imports); - const import_records_list = ast_fields.items(.import_records); - const export_star_import_records = ast_fields.items(.export_star_import_records); - const ast_flags = ast_fields.items(.flags); - for (reachable) |source_index_| { - const source_index = source_index_.get(); - const id = source_index; - - const is_entry_point = entry_point_kinds[source_index].isEntryPoint(); - const aliases = this.graph.meta.items(.sorted_and_filtered_export_aliases)[id]; - const flag = flags[id]; - const wrap = flag.wrap; - const export_kind = exports_kind[id]; - const source: *const Logger.Source = &this.parse_graph.input_files.items(.source)[source_index]; - - const exports_ref = exports_refs[id]; - - const module_ref = module_refs[id]; - - const string_buffer_len: usize = brk: { - var count: usize = 0; - if (is_entry_point and output_format == .esm) { - for (aliases) |alias| { - count += std.fmt.count("export_{f}", .{bun.fmt.fmtIdentifier(alias)}); - } - } - - const ident_fmt_len: usize = if (source.identifier_name.len > 0) - source.identifier_name.len - else - std.fmt.count("{f}", .{source.fmtIdentifier()}); - - if (wrap == .esm and wrapper_refs[id].isValid()) { - count += "init_".len + ident_fmt_len; - } - - if (wrap != .cjs and export_kind != .cjs and output_format != .internal_bake_dev) { - count += "exports_".len + ident_fmt_len; - count += "module_".len + ident_fmt_len; - } - - break :brk count; - }; - - const string_buffer = try this.allocator().alloc(u8, string_buffer_len); - var builder = bun.StringBuilder{ - .len = 0, - .cap = string_buffer.len, - .ptr = string_buffer.ptr, - }; - - defer bun.assert(builder.len == builder.cap); // ensure we used all of it - - // Pre-generate symbols for re-exports CommonJS symbols in case they - // are necessary later. This is done now because the symbols map cannot be - // mutated later due to parallelism. - if (is_entry_point and output_format == .esm) { - const copies = try this.allocator().alloc(Ref, aliases.len); - - for (aliases, copies) |alias, *copy| { - const original_name = builder.fmt("export_{f}", .{bun.fmt.fmtIdentifier(alias)}); - copy.* = this.graph.generateNewSymbol(source_index, .other, original_name); - } - this.graph.meta.items(.cjs_export_copies)[id] = copies; - } - - // Use "init_*" for ESM wrappers instead of "require_*" - if (wrap == .esm) { - const ref = wrapper_refs[id]; - if (ref.isValid()) { - const original_name = builder.fmt( - "init_{f}", - .{source.fmtIdentifier()}, - ); - - this.graph.symbols.get(ref).?.original_name = original_name; - } - } - - // If this isn't CommonJS, then rename the unused "exports" and "module" - // variables to avoid them causing the identically-named variables in - // actual CommonJS files from being renamed. This is purely about - // aesthetics and is not about correctness. This is done here because by - // this point, we know the CommonJS status will not change further. - if (wrap != .cjs and export_kind != .cjs and output_format != .internal_bake_dev) { - const exports_name = builder.fmt("exports_{f}", .{source.fmtIdentifier()}); - const module_name = builder.fmt("module_{f}", .{source.fmtIdentifier()}); - - // Note: it's possible for the symbols table to be resized - // so we cannot call .get() above this scope. - var exports_symbol: ?*js_ast.Symbol = if (exports_ref.isValid()) - this.graph.symbols.get(exports_ref) - else - null; - var module_symbol: ?*js_ast.Symbol = if (module_ref.isValid()) - this.graph.symbols.get(module_ref) - else - null; - - if (exports_symbol != null) - exports_symbol.?.original_name = exports_name; - if (module_symbol != null) - module_symbol.?.original_name = module_name; - } - - // Include the "__export" symbol from the runtime if it was used in the - // previous step. The previous step can't do this because it's running in - // parallel and can't safely mutate the "importsToBind" map of another file. - if (flag.needs_export_symbol_from_runtime) { - if (!runtime_export_symbol_ref.isValid()) { - runtime_export_symbol_ref = this.runtimeFunction("__export"); - } - - bun.assert(runtime_export_symbol_ref.isValid()); - - try this.graph.generateSymbolImportAndUse( - id, - js_ast.namespace_export_part_index, - runtime_export_symbol_ref, - 1, - Index.runtime, - ); - } - var imports_to_bind_list: []RefImportData = this.graph.meta.items(.imports_to_bind); - var parts_list: []Part.List = ast_fields.items(.parts); - - var parts: []Part = parts_list[id].slice(); - - const imports_to_bind = &imports_to_bind_list[id]; - for (imports_to_bind.keys(), imports_to_bind.values()) |ref_untyped, import_untyped| { - const ref: Ref = ref_untyped; // ZLS - const import: ImportData = import_untyped; // ZLS - - const import_source_index = import.data.source_index.get(); - - if (named_imports[id].get(ref)) |named_import| { - for (named_import.local_parts_with_uses.slice()) |part_index| { - var part: *Part = &parts[part_index]; - const parts_declaring_symbol: []const u32 = this.graph.topLevelSymbolToParts(import_source_index, import.data.import_ref); - - const total_len = parts_declaring_symbol.len + @as(usize, import.re_exports.len) + @as(usize, part.dependencies.len); - if (part.dependencies.cap < total_len) { - bun.handleOom(part.dependencies.ensureTotalCapacity(this.allocator(), total_len)); - } - - // Depend on the file containing the imported symbol - for (parts_declaring_symbol) |resolved_part_index| { - part.dependencies.appendAssumeCapacity(.{ - .source_index = Index.source(import_source_index), - .part_index = resolved_part_index, - }); - } - - // Also depend on any files that re-exported this symbol in between the - // file containing the import and the file containing the imported symbol - part.dependencies.appendSliceAssumeCapacity(import.re_exports.slice()); - } - } - - _ = this.graph.symbols.merge(ref, import.data.import_ref); - } - - // If this is an entry point, depend on all exports so they are included - if (is_entry_point) { - const force_include_exports = flag.force_include_exports_for_entry_point; - const add_wrapper = wrap != .none; - - const extra_count = @as(usize, @intFromBool(force_include_exports)) + - @as(usize, @intFromBool(add_wrapper)); - - var dependencies = bun.handleOom(std.array_list.Managed(js_ast.Dependency).initCapacity(this.allocator(), extra_count)); - - var resolved_exports_list: *ResolvedExports = &this.graph.meta.items(.resolved_exports)[id]; - for (aliases) |alias| { - const exp = resolved_exports_list.get(alias).?; - var target_source_index = exp.data.source_index; - var target_ref = exp.data.import_ref; - - // If this is an import, then target what the import points to - if (imports_to_bind_list[target_source_index.get()].get(target_ref)) |import_data| { - target_source_index = import_data.data.source_index; - target_ref = import_data.data.import_ref; - - bun.handleOom(dependencies.appendSlice(import_data.re_exports.slice())); - } - - // Pull in all declarations of this symbol - const top_to_parts = this.topLevelSymbolsToParts(target_source_index.get(), target_ref); - bun.handleOom(dependencies.ensureUnusedCapacity(top_to_parts.len)); - for (top_to_parts) |part_index| { - dependencies.appendAssumeCapacity(.{ - .source_index = target_source_index, - .part_index = part_index, - }); - } - } - - bun.handleOom(dependencies.ensureUnusedCapacity(extra_count)); - - // Ensure "exports" is included if the current output format needs it - if (force_include_exports) { - dependencies.appendAssumeCapacity( - .{ .source_index = Index.source(source_index), .part_index = js_ast.namespace_export_part_index }, - ); - } - - // Include the wrapper if present - if (add_wrapper) { - dependencies.appendAssumeCapacity( - .{ - .source_index = Index.source(source_index), - .part_index = this.graph.meta.items(.wrapper_part_index)[id].get(), - }, - ); - } - - // Represent these constraints with a dummy part - const entry_point_part_index = this.graph.addPartToFile( - id, - .{ - .dependencies = js_ast.Dependency.List.moveFromList(&dependencies), - .can_be_removed_if_unused = false, - }, - ) catch |err| bun.handleOom(err); - - parts = parts_list[id].slice(); - this.graph.meta.items(.entry_point_part_index)[id] = Index.part(entry_point_part_index); - - // Pull in the "__toCommonJS" symbol if we need it due to being an entry point - if (force_include_exports and output_format != .internal_bake_dev) { - try this.graph.generateRuntimeSymbolImportAndUse( - source_index, - Index.part(entry_point_part_index), - "__toCommonJS", - 1, - ); - } - } - - // Encode import-specific constraints in the dependency graph - const import_records: []ImportRecord = import_records_list[id].slice(); - debug("Binding {d} imports for file {s} (#{d})", .{ import_records.len, source.path.text, id }); - - for (parts, 0..) |*part, part_index| { - var to_esm_uses: u32 = 0; - var to_common_js_uses: u32 = 0; - var runtime_require_uses: u32 = 0; - - // Imports of wrapped files must depend on the wrapper - for (part.import_record_indices.slice()) |import_record_index| { - var record = &import_records[import_record_index]; - const kind = record.kind; - const other_id = record.source_index.value; - - // Don't follow external imports (this includes import() expressions) - if (!record.source_index.isValid() or this.isExternalDynamicImport(record, source_index)) { - if (output_format == .internal_bake_dev) continue; - - // This is an external import. Check if it will be a "require()" call. - if (kind == .require or !output_format.keepES6ImportExportSyntax() or kind == .dynamic) { - if (record.source_index.isValid() and kind == .dynamic and ast_flags[other_id].force_cjs_to_esm) { - // If the CommonJS module was converted to ESM - // and the developer `import("cjs_module")`, then - // they may have code that expects the default export to return the CommonJS module.exports object - // That module.exports object does not exist. - // We create a default object with getters for each statically-known export - // This is kind of similar to what Node.js does - // Once we track usages of the dynamic import, we can remove this. - if (!ast_fields.items(.named_exports)[other_id].contains("default")) - flags[other_id].needs_synthetic_default_export = true; - - continue; - } else { - // We should use "__require" instead of "require" if we're not - // generating a CommonJS output file, since it won't exist otherwise. - if (shouldCallRuntimeRequire(output_format)) { - runtime_require_uses += 1; - } - - // If this wasn't originally a "require()" call, then we may need - // to wrap this in a call to the "__toESM" wrapper to convert from - // CommonJS semantics to ESM semantics. - // - // Unfortunately this adds some additional code since the conversion - // is somewhat complex. As an optimization, we can avoid this if the - // following things are true: - // - // - The import is an ES module statement (e.g. not an "import()" expression) - // - The ES module namespace object must not be captured - // - The "default" and "__esModule" exports must not be accessed - // - if (kind != .require and - (kind != .stmt or - record.flags.contains_import_star or - record.flags.contains_default_alias or - record.flags.contains_es_module_alias)) - { - // For dynamic imports to cross-chunk CJS modules, we need extra - // unwrapping in js_printer (.then((m)=>__toESM(m.default))). - // For other cases (static imports, truly external), use standard wrapping. - if (record.source_index.isValid() and - this.isExternalDynamicImport(record, source_index) and - exports_kind[record.source_index.get()] == .cjs) - { - // Cross-chunk dynamic import to CJS - needs special handling in printer - record.flags.wrap_with_to_esm = true; - to_esm_uses += 1; - } else if (kind != .dynamic) { - // Static imports to external CJS modules need __toESM wrapping - record.flags.wrap_with_to_esm = true; - to_esm_uses += 1; - } - // Dynamic imports to truly external modules: no wrapping (preserve native format) - } - } - } - continue; - } - - bun.assert(@as(usize, @intCast(other_id)) < this.graph.meta.len); - const other_flags = flags[other_id]; - const other_export_kind = exports_kind[other_id]; - const other_source_index = other_id; - - if (other_flags.wrap != .none) { - // Depend on the automatically-generated require wrapper symbol - const wrapper_ref = wrapper_refs[other_id]; - if (wrapper_ref.isValid()) { - try this.graph.generateSymbolImportAndUse( - source_index, - @as(u32, @intCast(part_index)), - wrapper_ref, - 1, - Index.source(other_source_index), - ); - } - - // This is an ES6 import of a CommonJS module, so it needs the - // "__toESM" wrapper as long as it's not a bare "require()" - if (kind != .require and other_export_kind == .cjs and output_format != .internal_bake_dev) { - record.flags.wrap_with_to_esm = true; - to_esm_uses += 1; - } - - // If this is an ESM wrapper, also depend on the exports object - // since the final code will contain an inline reference to it. - // This must be done for "require()" and "import()" expressions - // but does not need to be done for "import" statements since - // those just cause us to reference the exports directly. - if (other_flags.wrap == .esm and kind != .stmt) { - try this.graph.generateSymbolImportAndUse( - source_index, - @as(u32, @intCast(part_index)), - this.graph.ast.items(.exports_ref)[other_id], - 1, - Index.source(other_source_index), - ); - - // If this is a "require()" call, then we should add the - // "__esModule" marker to behave as if the module was converted - // from ESM to CommonJS. This is done via a wrapper instead of - // by modifying the exports object itself because the same ES - // module may be simultaneously imported and required, and the - // importing code should not see "__esModule" while the requiring - // code should see "__esModule". This is an extremely complex - // and subtle set of transpiler interop issues. See for example - // https://github.com/evanw/esbuild/issues/1591. - if (kind == .require) { - record.flags.wrap_with_to_commonjs = true; - to_common_js_uses += 1; - } - } - } else if (kind == .stmt and export_kind == .esm_with_dynamic_fallback) { - // This is an import of a module that has a dynamic export fallback - // object. In that case we need to depend on that object in case - // something ends up needing to use it later. This could potentially - // be omitted in some cases with more advanced analysis if this - // dynamic export fallback object doesn't end up being needed. - try this.graph.generateSymbolImportAndUse( - source_index, - @as(u32, @intCast(part_index)), - this.graph.ast.items(.exports_ref)[other_id], - 1, - Index.source(other_source_index), - ); - } - } - - // If there's an ES6 export star statement of a non-ES6 module, then we're - // going to need the "__reExport" symbol from the runtime - var re_export_uses: u32 = 0; - - for (export_star_import_records[id]) |import_record_index| { - var record = &import_records[import_record_index]; - - var happens_at_runtime = record.source_index.isInvalid() and (!is_entry_point or !output_format.keepES6ImportExportSyntax()); - if (record.source_index.isValid()) { - const other_source_index = record.source_index.get(); - const other_id = other_source_index; - bun.assert(@as(usize, @intCast(other_id)) < this.graph.meta.len); - const other_export_kind = exports_kind[other_id]; - if (other_source_index != source_index and other_export_kind.isDynamic()) { - happens_at_runtime = true; - } - - if (other_export_kind.isESMWithDynamicFallback()) { - // This looks like "__reExport(exports_a, exports_b)". Make sure to - // pull in the "exports_b" symbol into this export star. This matters - // in code splitting situations where the "export_b" symbol might live - // in a different chunk than this export star. - try this.graph.generateSymbolImportAndUse( - source_index, - @as(u32, @intCast(part_index)), - this.graph.ast.items(.exports_ref)[other_id], - 1, - Index.source(other_source_index), - ); - } - } - - if (happens_at_runtime) { - // Depend on this file's "exports" object for the first argument to "__reExport" - try this.graph.generateSymbolImportAndUse( - source_index, - @as(u32, @intCast(part_index)), - this.graph.ast.items(.exports_ref)[id], - 1, - Index.source(source_index), - ); - this.graph.ast.items(.flags)[id].uses_exports_ref = true; - record.flags.calls_runtime_re_export_fn = true; - re_export_uses += 1; - } - } - - if (output_format != .internal_bake_dev) { - // If there's an ES6 import of a CommonJS module, then we're going to need the - // "__toESM" symbol from the runtime to wrap the result of "require()" - try this.graph.generateRuntimeSymbolImportAndUse( - source_index, - Index.part(part_index), - "__toESM", - to_esm_uses, - ); - - // If there's a CommonJS require of an ES6 module, then we're going to need the - // "__toCommonJS" symbol from the runtime to wrap the exports object - try this.graph.generateRuntimeSymbolImportAndUse( - source_index, - Index.part(part_index), - "__toCommonJS", - to_common_js_uses, - ); - - // If there are unbundled calls to "require()" and we're not generating - // code for node, then substitute a "__require" wrapper for "require". - try this.graph.generateRuntimeSymbolImportAndUse( - source_index, - Index.part(part_index), - "__require", - runtime_require_uses, - ); - - try this.graph.generateRuntimeSymbolImportAndUse( - source_index, - Index.part(part_index), - "__reExport", - re_export_uses, - ); - } - } - } - } -} - -inline fn shouldCallRuntimeRequire(format: options.Format) bool { - return format != .cjs; -} - -const DependencyWrapper = struct { - linker: *LinkerContext, - flags: []JSMeta.Flags, - exports_kind: []js_ast.ExportsKind, - import_records: []ImportRecord.List, - export_star_map: std.AutoHashMap(Index.Int, void), - entry_point_kinds: []EntryPoint.Kind, - export_star_records: [][]u32, - output_format: options.Format, - - pub fn hasDynamicExportsDueToExportStar(this: *DependencyWrapper, source_index: Index.Int) bool { - // Terminate the traversal now if this file already has dynamic exports - const export_kind = this.exports_kind[source_index]; - switch (export_kind) { - .cjs, .esm_with_dynamic_fallback => return true, - else => {}, - } - - // Avoid infinite loops due to cycles in the export star graph - const has_visited = this.export_star_map.getOrPut(source_index) catch unreachable; - if (has_visited.found_existing) { - return false; - } - - const records = this.import_records[source_index].slice(); - for (this.export_star_records[source_index]) |id| { - const record = records[id]; - - // This file has dynamic exports if the exported imports are from a file - // that either has dynamic exports directly or transitively by itself - // having an export star from a file with dynamic exports. - const kind = this.entry_point_kinds[source_index]; - if ((record.source_index.isInvalid() and (!kind.isEntryPoint() or !this.output_format.keepES6ImportExportSyntax())) or - (record.source_index.isValid() and record.source_index.get() != source_index and this.hasDynamicExportsDueToExportStar(record.source_index.get()))) - { - this.exports_kind[source_index] = .esm_with_dynamic_fallback; - return true; - } - } - - return false; - } - - pub fn wrap(this: *DependencyWrapper, source_index: Index.Int) void { - var flags = this.flags[source_index]; - - if (flags.did_wrap_dependencies) return; - flags.did_wrap_dependencies = true; - - // Never wrap the runtime file since it always comes first - if (source_index == Index.runtime.get()) { - return; - } - - this.flags[source_index] = brk: { - - // This module must be wrapped - if (flags.wrap == .none) { - flags.wrap = switch (this.exports_kind[source_index]) { - .cjs => .cjs, - else => .esm, - }; - } - break :brk flags; - }; - - const records = this.import_records[source_index].slice(); - for (records) |record| { - if (!record.source_index.isValid()) { - continue; - } - this.wrap(record.source_index.get()); - } - } -}; - -const ExportStarContext = struct { - import_records_list: []const ImportRecord.List, - source_index_stack: std.array_list.Managed(Index.Int), - exports_kind: []js_ast.ExportsKind, - named_exports: []js_ast.Ast.NamedExports, - resolved_exports: []ResolvedExports, - imports_to_bind: []RefImportData, - export_star_records: []const []const Index.Int, - allocator: std.mem.Allocator, - - pub fn addExports( - this: *ExportStarContext, - resolved_exports: *ResolvedExports, - source_index: Index.Int, - ) void { - // Avoid infinite loops due to cycles in the export star graph - for (this.source_index_stack.items) |i| { - if (i == source_index) - return; - } - bun.handleOom(this.source_index_stack.append(source_index)); - const stack_end_pos = this.source_index_stack.items.len; - defer this.source_index_stack.shrinkRetainingCapacity(stack_end_pos - 1); - - const import_records = this.import_records_list[source_index].slice(); - - for (this.export_star_records[source_index]) |import_id| { - const other_source_index = import_records[import_id].source_index.get(); - - const other_id = other_source_index; - if (other_id >= this.named_exports.len) - // this AST was empty or it wasn't a JS AST - continue; - - // Export stars from a CommonJS module don't work because they can't be - // statically discovered. Just silently ignore them in this case. - // - // We could attempt to check whether the imported file still has ES6 - // exports even though it still uses CommonJS features. However, when - // doing this we'd also have to rewrite any imports of these export star - // re-exports as property accesses off of a generated require() call. - if (this.exports_kind[other_id] == .cjs) - continue; - - var iter = this.named_exports[other_id].iterator(); - next_export: while (iter.next()) |entry| { - const alias = entry.key_ptr.*; - const name = entry.value_ptr.*; - - // ES6 export star statements ignore exports named "default" - if (strings.eqlComptime(alias, "default")) - continue; - - // This export star is shadowed if any file in the stack has a matching real named export - for (this.source_index_stack.items[0..stack_end_pos]) |prev| { - if (this.named_exports[prev].contains(alias)) { - continue :next_export; - } - } - - const gop = bun.handleOom(resolved_exports.getOrPut(this.allocator, alias)); - if (!gop.found_existing) { - // Initialize the re-export - gop.value_ptr.* = .{ - .data = .{ - .import_ref = name.ref, - .source_index = Index.source(other_source_index), - .name_loc = name.alias_loc, - }, - }; - - // Make sure the symbol is marked as imported so that code splitting - // imports it correctly if it ends up being shared with another chunk - this.imports_to_bind[source_index].put(this.allocator, name.ref, .{ - .data = .{ - .import_ref = name.ref, - .source_index = Index.source(other_source_index), - }, - }) catch |err| bun.handleOom(err); - } else if (gop.value_ptr.data.source_index.get() != other_source_index) { - // Two different re-exports colliding makes it potentially ambiguous - gop.value_ptr.potentially_ambiguous_export_star_refs.append(this.allocator, .{ - .data = .{ - .source_index = Index.source(other_source_index), - .import_ref = name.ref, - .name_loc = name.alias_loc, - }, - }) catch |err| bun.handleOom(err); - } - } - - // Search further through this file's export stars - this.addExports(resolved_exports, other_source_index); - } - } -}; - -/// CSS modules spec says that the following is undefined behavior: -/// -/// ```css -/// .foo { -/// composes: bar; -/// color: red; -/// } -/// -/// .bar { -/// color: blue; -/// } -/// ``` -/// -/// Specfically, composing two classes that both define the same property is undefined behavior. -/// -/// We check this by recording, at parse time, properties that classes use in the `PropertyUsage` struct. -/// Then here, we compare the properties of the two classes to ensure that there are no conflicts. -/// -/// There is one case we skip, which is checking the properties of composing from the global scope (`composes: X from global`). -/// -/// The reason we skip this is because it would require tracking _every_ property of _every_ class (not just CSS module local classes). -/// This sucks because: -/// 1. It introduces a performance hit even if the user did not use CSS modules -/// 2. Composing from the global scope is pretty rare -/// -/// We should find a way to do this without incurring performance penalties to the common cases. -fn validateComposesFromProperties( - this: *LinkerContext, - index: Index.Int, - root_css_ast: *bun.css.BundlerStyleSheet, - import_records_list: []ImportRecord.List, - all_css_asts: []const ?*bun.css.BundlerStyleSheet, -) void { - const PropertyInFile = struct { - source_index: Index.Int, - range: bun.logger.Range, - }; - const Visitor = struct { - visited: std.AutoArrayHashMap(Ref, void), - properties: bun.StringArrayHashMap(PropertyInFile), - all_import_records: []const ImportRecord.List, - all_css_asts: []const ?*bun.css.BundlerStyleSheet, - all_symbols: *const Symbol.Map, - all_sources: []const Logger.Source, - temp_allocator: std.mem.Allocator, - allocator: std.mem.Allocator, - log: *Logger.Log, - - pub fn deinit(v: *@This()) void { - v.visited.deinit(); - v.properties.deinit(); - } - - fn addPropertyOrWarn(v: *@This(), local: Ref, property_name: []const u8, source_index: Index.Int, range: bun.logger.Range) void { - const entry = bun.handleOom(v.properties.getOrPut(property_name)); - - if (!entry.found_existing) { - entry.value_ptr.* = .{ - .source_index = source_index, - .range = range, - }; - return; - } - - if (entry.value_ptr.source_index == source_index or entry.value_ptr.source_index == Index.invalid.get()) { - return; - } - - const local_original_name = v.all_symbols.get(local).?.original_name; - - v.log.addMsg(.{ - .kind = .err, - .data = Logger.rangeData( - &v.all_sources[source_index], - range, - Logger.Log.allocPrint( - v.allocator, - "The value of {s} in the class {s} is undefined.", - .{ property_name, local_original_name }, - ) catch |err| bun.handleOom(err), - ).cloneLineText(v.log.clone_line_text, v.log.msgs.allocator) catch |err| bun.handleOom(err), - .notes = v.allocator.dupe( - Logger.Data, - &.{ - bun.logger.rangeData( - &v.all_sources[entry.value_ptr.source_index], - entry.value_ptr.range, - bun.handleOom(Logger.Log.allocPrint(v.allocator, "The first definition of {s} is in this style rule:", .{property_name})), - ), - .{ .text = std.fmt.allocPrint( - v.allocator, - "The specification of \"composes\" does not define an order when class declarations from separate files are composed together. " ++ - "The value of the {f} property for {f} may change unpredictably as the code is edited. " ++ - "Make sure that all definitions of {f} for {f} are in a single file.", - .{ bun.fmt.quote(property_name), bun.fmt.quote(local_original_name), bun.fmt.quote(property_name), bun.fmt.quote(local_original_name) }, - ) catch |err| bun.handleOom(err) }, - }, - ) catch |err| bun.handleOom(err), - }) catch |err| bun.handleOom(err); - - // Don't warn more than once - entry.value_ptr.source_index = Index.invalid.get(); - } - - fn clearRetainingCapacity(v: *@This()) void { - v.visited.clearRetainingCapacity(); - v.properties.clearRetainingCapacity(); - } - - fn visit(v: *@This(), idx: Index.Int, ast: *bun.css.BundlerStyleSheet, ref: Ref) void { - if (v.visited.contains(ref)) return; - v.visited.put(ref, {}) catch unreachable; - - // This local name was in a style rule that - if (ast.composes.getPtr(ref)) |composes| { - for (composes.composes.sliceConst()) |*compose| { - // is an import - if (compose.from != null) { - if (compose.from.? == .import_record_index) { - const import_record_idx = compose.from.?.import_record_index; - const record = v.all_import_records[idx].at(import_record_idx); - if (record.source_index.isInvalid()) continue; - const other_ast = v.all_css_asts[record.source_index.get()] orelse continue; - for (compose.names.slice()) |name| { - const other_name = other_ast.local_scope.get(name.v) orelse continue; - const other_name_ref = other_name.ref.toRealRef(record.source_index.get()); - v.visit(record.source_index.get(), other_ast, other_name_ref); - } - } else { - bun.assert(compose.from.? == .global); - // Otherwise it is composed from the global scope. - // - // See comment above for why we are skipping checking this for now. - } - } else { - // inside this file - for (compose.names.slice()) |name| { - const name_entry = ast.local_scope.get(name.v) orelse continue; - v.visit(idx, ast, name_entry.ref.toRealRef(idx)); - } - } - } - } - - const property_usage = ast.local_properties.getPtr(ref) orelse return; - // Warn about cross-file composition with the same CSS properties - var iter = property_usage.bitset.iterator(.{}); - while (iter.next()) |property_tag| { - const property_id_tag: bun.css.PropertyIdTag = @enumFromInt(@as(u16, @intCast(property_tag))); - bun.assert(property_id_tag != .custom); - bun.assert(property_id_tag != .unparsed); - v.addPropertyOrWarn(ref, @tagName(property_id_tag), idx, property_usage.range); - } - - for (property_usage.custom_properties) |property| { - v.addPropertyOrWarn(ref, property, idx, property_usage.range); - } - } - }; - var sfb = std.heap.stackFallback(1024, this.graph.allocator); - const temp_allocator = sfb.get(); - var visitor = Visitor{ - .visited = std.AutoArrayHashMap(Ref, void).init(temp_allocator), - .properties = bun.StringArrayHashMap(PropertyInFile).init(temp_allocator), - .all_import_records = import_records_list, - .all_css_asts = all_css_asts, - .all_symbols = &this.graph.symbols, - .all_sources = this.parse_graph.input_files.items(.source), - .temp_allocator = temp_allocator, - .allocator = this.graph.allocator, - .log = this.log, - }; - defer visitor.deinit(); - for (root_css_ast.local_scope.values()) |local| { - visitor.clearRetainingCapacity(); - visitor.visit(index, root_css_ast, local.ref.toRealRef(index)); - } -} - -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const FeatureFlags = bun.FeatureFlags; -const ImportRecord = bun.ImportRecord; -const Loader = bun.Loader; -const Logger = bun.logger; -const options = bun.options; -const strings = bun.strings; - -const EntryPoint = bun.bundle_v2.EntryPoint; -const ExportData = bun.bundle_v2.ExportData; -const ImportData = bun.bundle_v2.ImportData; -const Index = bun.bundle_v2.Index; -const JSMeta = bun.bundle_v2.JSMeta; -const Part = bun.bundle_v2.Part; -const RefImportData = bun.bundle_v2.RefImportData; -const ResolvedExports = bun.bundle_v2.ResolvedExports; -const Symbol = bun.bundle_v2.Symbol; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const debug = LinkerContext.debug; - -const js_ast = bun.bundle_v2.js_ast; -const Dependency = js_ast.Dependency; -const Ref = bun.bundle_v2.js_ast.Ref; diff --git a/src/bundler/linker_context/writeOutputFilesToDisk.zig b/src/bundler/linker_context/writeOutputFilesToDisk.zig deleted file mode 100644 index 6a56979a02a4..000000000000 --- a/src/bundler/linker_context/writeOutputFilesToDisk.zig +++ /dev/null @@ -1,483 +0,0 @@ -pub fn writeOutputFilesToDisk( - c: *LinkerContext, - root_path: string, - chunks: []Chunk, - output_files: *OutputFileListBuilder, - standalone_chunk_contents: ?[]const ?[]const u8, -) !void { - const trace = bun.perf.trace("Bundler.writeOutputFilesToDisk"); - defer trace.end(); - var root_dir = std.fs.cwd().makeOpenPath(root_path, .{}) catch |err| { - if (err == error.NotDir) { - c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "Failed to create output directory {f} is a file. Please choose a different outdir or delete {f}", .{ - bun.fmt.quote(root_path), - bun.fmt.quote(root_path), - }) catch unreachable; - } else { - c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "Failed to create output directory {s} {f}", .{ - @errorName(err), - bun.fmt.quote(root_path), - }) catch unreachable; - } - - return err; - }; - defer root_dir.close(); - // Optimization: when writing to disk, we can re-use the memory - var max_heap_allocator: bun.MaxHeapAllocator = undefined; - defer max_heap_allocator.deinit(); - - const code_allocator = max_heap_allocator.init(bun.default_allocator); - - var max_heap_allocator_source_map: bun.MaxHeapAllocator = undefined; - defer max_heap_allocator_source_map.deinit(); - - const source_map_allocator = max_heap_allocator_source_map.init(bun.default_allocator); - - var max_heap_allocator_inline_source_map: bun.MaxHeapAllocator = undefined; - defer max_heap_allocator_inline_source_map.deinit(); - - const code_with_inline_source_map_allocator = max_heap_allocator_inline_source_map.init(bun.default_allocator); - - var pathbuf: bun.PathBuffer = undefined; - const bv2: *bundler.BundleV2 = @fieldParentPtr("linker", c); - - for (chunks, 0..) |*chunk, chunk_index_in_chunks_list| { - // In standalone mode, only write HTML chunks to disk. - // Insert placeholder output files for non-HTML chunks to keep indices aligned. - if (standalone_chunk_contents != null and chunk.content != .html) { - _ = output_files.insertForChunk(options.OutputFile.init(.{ - .data = .{ .saved = 0 }, - .hash = null, - .loader = chunk.content.loader(), - .input_path = "", - .display_size = 0, - .output_kind = .chunk, - .input_loader = .js, - .output_path = "", - .is_executable = false, - .source_map_index = null, - .bytecode_index = null, - .module_info_index = null, - .side = .client, - .entry_point_index = null, - .referenced_css_chunks = &.{}, - })); - continue; - } - - const trace2 = bun.perf.trace("Bundler.writeChunkToDisk"); - defer trace2.end(); - defer max_heap_allocator.reset(); - - const rel_path = chunk.final_rel_path; - if (std.fs.path.dirnamePosix(rel_path)) |rel_parent| { - if (rel_parent.len > 0) { - root_dir.makePath(rel_parent) catch |err| { - c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "{s} creating outdir {f} while saving chunk {f}", .{ - @errorName(err), - bun.fmt.quote(rel_parent), - bun.fmt.quote(chunk.final_rel_path), - }) catch unreachable; - return err; - }; - } - } - var display_size: usize = 0; - const public_path = if (chunk.flags.is_browser_chunk_from_server_build) - bv2.transpilerForTarget(.browser).options.public_path - else - c.resolver.opts.public_path; - - var code_result = if (standalone_chunk_contents) |scc| - chunk.intermediate_output.codeStandalone( - code_allocator, - c.parse_graph, - &c.graph, - public_path, - chunk, - chunks, - &display_size, - false, - false, - scc, - ) catch |err| bun.Output.panic("Failed to create output chunk: {s}", .{@errorName(err)}) - else - chunk.intermediate_output.code( - code_allocator, - c.parse_graph, - &c.graph, - public_path, - chunk, - chunks, - &display_size, - c.resolver.opts.compile and !chunk.flags.is_browser_chunk_from_server_build, - chunk.content.sourcemap(c.options.source_maps) != .none, - ) catch |err| bun.Output.panic("Failed to create output chunk: {s}", .{@errorName(err)}); - - var source_map_output_file: ?options.OutputFile = null; - - const input_path = try bun.default_allocator.dupe( - u8, - if (chunk.entry_point.is_entry_point) - c.parse_graph.input_files.items(.source)[chunk.entry_point.source_index].path.text - else - chunk.final_rel_path, - ); - - switch (chunk.content.sourcemap(c.options.source_maps)) { - .external, .linked => |tag| { - const output_source_map = chunk.output_source_map.finalize(source_map_allocator, code_result.shifts) catch @panic("Failed to allocate memory for external source map"); - const source_map_final_rel_path = strings.concat(default_allocator, &.{ - chunk.final_rel_path, - ".map", - }) catch @panic("Failed to allocate memory for external source map path"); - - if (tag == .linked) { - const a, const b = if (public_path.len > 0) - cheapPrefixNormalizer(public_path, source_map_final_rel_path) - else - .{ "", std.fs.path.basename(source_map_final_rel_path) }; - - const source_map_start = "//# sourceMappingURL="; - const total_len = code_result.buffer.len + source_map_start.len + a.len + b.len + "\n".len; - var buf = std.array_list.Managed(u8).initCapacity(Chunk.IntermediateOutput.allocatorForSize(total_len), total_len) catch @panic("Failed to allocate memory for output file with inline source map"); - buf.appendSliceAssumeCapacity(code_result.buffer); - buf.appendSliceAssumeCapacity(source_map_start); - buf.appendSliceAssumeCapacity(a); - buf.appendSliceAssumeCapacity(b); - buf.appendAssumeCapacity('\n'); - code_result.buffer = buf.items; - } - - switch (jsc.Node.fs.NodeFS.writeFileWithPathBuffer( - &pathbuf, - .{ - .data = jsc.Node.StringOrBuffer{ - .buffer = bun.api.node.Buffer{ - .buffer = .{ - .ptr = @constCast(output_source_map.ptr), - // TODO: handle > 4 GB files - .len = @as(u32, @truncate(output_source_map.len)), - .byte_len = @as(u32, @truncate(output_source_map.len)), - }, - }, - }, - .encoding = .buffer, - .dirfd = .fromStdDir(root_dir), - .file = .{ - .path = .{ - .string = bun.PathString.init(source_map_final_rel_path), - }, - }, - }, - )) { - .err => |err| { - try c.log.addSysError(bun.default_allocator, err, "writing sourcemap for chunk {f}", .{ - bun.fmt.quote(chunk.final_rel_path), - }); - return error.WriteFailed; - }, - .result => {}, - } - - source_map_output_file = options.OutputFile.init(.{ - .output_path = source_map_final_rel_path, - .input_path = try strings.concat(bun.default_allocator, &.{ input_path, ".map" }), - .loader = .json, - .input_loader = .file, - .output_kind = .sourcemap, - .size = @as(u32, @truncate(output_source_map.len)), - .data = .{ - .saved = 0, - }, - .side = .client, - .entry_point_index = null, - .is_executable = false, - }); - }, - .@"inline" => { - const output_source_map = chunk.output_source_map.finalize(source_map_allocator, code_result.shifts) catch @panic("Failed to allocate memory for external source map"); - const encode_len = base64.encodeLen(output_source_map); - - const source_map_start = "//# sourceMappingURL=data:application/json;base64,"; - const total_len = code_result.buffer.len + source_map_start.len + encode_len + 1; - var buf = std.array_list.Managed(u8).initCapacity(code_with_inline_source_map_allocator, total_len) catch @panic("Failed to allocate memory for output file with inline source map"); - - buf.appendSliceAssumeCapacity(code_result.buffer); - buf.appendSliceAssumeCapacity(source_map_start); - - buf.items.len += encode_len; - _ = base64.encode(buf.items[buf.items.len - encode_len ..], output_source_map); - - buf.appendAssumeCapacity('\n'); - code_result.buffer = buf.items; - }, - .none => {}, - } - const bytecode_output_file: ?options.OutputFile = brk: { - if (c.options.generate_bytecode_cache) { - const loader: Loader = if (chunk.entry_point.is_entry_point) - c.parse_graph.input_files.items(.loader)[ - chunk.entry_point.source_index - ] - else - .js; - - if (loader.isJavaScriptLike()) { - jsc.VirtualMachine.is_bundler_thread_for_bytecode_cache = true; - jsc.initialize(false); - var fdpath: bun.PathBuffer = undefined; - var source_provider_url = try bun.String.createFormat("{s}" ++ bun.bytecode_extension, .{chunk.final_rel_path}); - source_provider_url.ref(); - - defer source_provider_url.deref(); - - if (jsc.CachedBytecode.generate(c.options.output_format, code_result.buffer, &source_provider_url)) |result| { - const source_provider_url_str = source_provider_url.toSlice(bun.default_allocator); - defer source_provider_url_str.deinit(); - const bytecode, const cached_bytecode = result; - debug("Bytecode cache generated {s}: {f}", .{ source_provider_url_str.slice(), bun.fmt.size(bytecode.len, .{ .space_between_number_and_unit = true }) }); - @memcpy(fdpath[0..chunk.final_rel_path.len], chunk.final_rel_path); - fdpath[chunk.final_rel_path.len..][0..bun.bytecode_extension.len].* = bun.bytecode_extension.*; - defer cached_bytecode.deref(); - switch (jsc.Node.fs.NodeFS.writeFileWithPathBuffer( - &pathbuf, - .{ - .data = .{ - .buffer = .{ - .buffer = .{ - .ptr = @constCast(bytecode.ptr), - .len = @as(u32, @truncate(bytecode.len)), - .byte_len = @as(u32, @truncate(bytecode.len)), - }, - }, - }, - .encoding = .buffer, - .mode = if (chunk.flags.is_executable) 0o755 else 0o644, - - .dirfd = .fromStdDir(root_dir), - .file = .{ - .path = .{ - .string = bun.PathString.init(fdpath[0 .. chunk.final_rel_path.len + bun.bytecode_extension.len]), - }, - }, - }, - )) { - .result => {}, - .err => |err| { - c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "{f} writing bytecode for chunk {f}", .{ - err, - bun.fmt.quote(chunk.final_rel_path), - }) catch unreachable; - return error.WriteFailed; - }, - } - - break :brk options.OutputFile.init(.{ - .output_path = bun.default_allocator.dupe(u8, source_provider_url_str.slice()) catch unreachable, - .input_path = std.fmt.allocPrint(bun.default_allocator, "{s}" ++ bun.bytecode_extension, .{chunk.final_rel_path}) catch unreachable, - .input_loader = .file, - .hash = if (chunk.template.placeholder.hash != null) bun.hash(bytecode) else null, - .output_kind = .bytecode, - .loader = .file, - .size = @as(u32, @truncate(bytecode.len)), - .display_size = @as(u32, @truncate(bytecode.len)), - .data = .{ - .saved = 0, - }, - .side = null, - .entry_point_index = null, - .is_executable = false, - }); - } - } - } - - break :brk null; - }; - - switch (jsc.Node.fs.NodeFS.writeFileWithPathBuffer( - &pathbuf, - .{ - .data = .{ - .buffer = .{ - .buffer = .{ - .ptr = @constCast(code_result.buffer.ptr), - // TODO: handle > 4 GB files - .len = @as(u32, @truncate(code_result.buffer.len)), - .byte_len = @as(u32, @truncate(code_result.buffer.len)), - }, - }, - }, - .encoding = .buffer, - .mode = if (chunk.flags.is_executable) 0o755 else 0o644, - - .dirfd = .fromStdDir(root_dir), - .file = .{ - .path = jsc.Node.PathLike{ - .string = bun.PathString.init(rel_path), - }, - }, - }, - )) { - .err => |err| { - try c.log.addSysError(bun.default_allocator, err, "writing chunk {f}", .{ - bun.fmt.quote(chunk.final_rel_path), - }); - return error.WriteFailed; - }, - .result => {}, - } - - const source_map_index: ?u32 = if (source_map_output_file != null) - try output_files.insertForSourcemapOrBytecode(source_map_output_file.?) - else - null; - - const bytecode_index: ?u32 = if (bytecode_output_file != null) - try output_files.insertForSourcemapOrBytecode(bytecode_output_file.?) - else - null; - - const output_kind = if (chunk.content == .css) - .asset - else if (chunk.entry_point.is_entry_point) - c.graph.files.items(.entry_point_kind)[chunk.entry_point.source_index].outputKind() - else - .chunk; - - const chunk_index = output_files.insertForChunk(options.OutputFile.init(.{ - .output_path = bun.default_allocator.dupe(u8, chunk.final_rel_path) catch unreachable, - .input_path = input_path, - .input_loader = if (chunk.entry_point.is_entry_point) - c.parse_graph.input_files.items(.loader)[chunk.entry_point.source_index] - else - .js, - .hash = chunk.template.placeholder.hash, - .output_kind = output_kind, - .loader = chunk.content.loader(), - .source_map_index = source_map_index, - .bytecode_index = bytecode_index, - .size = @as(u32, @truncate(code_result.buffer.len)), - .display_size = @as(u32, @truncate(display_size)), - .is_executable = chunk.flags.is_executable, - .data = .{ - .saved = 0, - }, - .side = if (chunk.content == .css) - .client - else switch (c.graph.ast.items(.target)[chunk.entry_point.source_index]) { - .browser => .client, - else => .server, - }, - .entry_point_index = if (output_kind == .@"entry-point") - chunk.entry_point.source_index - @as(u32, (if (c.framework) |fw| if (fw.server_components != null) 3 else 1 else 1)) - else - null, - .referenced_css_chunks = switch (chunk.content) { - .javascript => |js| @ptrCast(try bun.default_allocator.dupe(u32, js.css_chunks)), - .css => &.{}, - .html => &.{}, - }, - })); - - // We want the chunk index to remain the same in `output_files` so the indices in `OutputFile.referenced_css_chunks` work. - // In standalone mode, non-HTML chunks are skipped so this invariant doesn't apply. - if (standalone_chunk_contents == null) - bun.assertf(chunk_index == chunk_index_in_chunks_list, "chunk_index ({d}) != chunk_index_in_chunks_list ({d})", .{ chunk_index, chunk_index_in_chunks_list }); - } - - // In standalone mode, additional output files (assets) are inlined into the HTML. - if (standalone_chunk_contents != null) return; - - { - const additional_output_files = output_files.getMutableAdditionalOutputFiles(); - output_files.total_insertions += @intCast(additional_output_files.len); - for (c.parse_graph.additional_output_files.items, additional_output_files) |*src, *dest| { - const bytes = src.value.buffer.bytes; - src.value.buffer.bytes.len = 0; - - defer { - src.value.buffer.allocator.free(bytes); - } - - if (std.fs.path.dirname(src.dest_path)) |rel_parent| { - if (rel_parent.len > 0) { - root_dir.makePath(rel_parent) catch |err| { - c.log.addErrorFmt(null, Logger.Loc.Empty, bun.default_allocator, "{s} creating outdir {f} while saving file {f}", .{ - @errorName(err), - bun.fmt.quote(rel_parent), - bun.fmt.quote(src.dest_path), - }) catch unreachable; - return err; - }; - } - } - - switch (jsc.Node.fs.NodeFS.writeFileWithPathBuffer( - &pathbuf, - .{ - .data = .{ - .buffer = .{ - .buffer = .{ - .ptr = @constCast(bytes.ptr), - .len = @as(u32, @truncate(bytes.len)), - .byte_len = @as(u32, @truncate(bytes.len)), - }, - }, - }, - .encoding = .buffer, - .dirfd = .fromStdDir(root_dir), - .file = .{ - .path = jsc.Node.PathLike{ - .string = bun.PathString.init(src.dest_path), - }, - }, - }, - )) { - .err => |err| { - c.log.addSysError(bun.default_allocator, err, "writing file {f}", .{ - bun.fmt.quote(src.src_path.text), - }) catch unreachable; - return error.WriteFailed; - }, - .result => {}, - } - - dest.* = src.*; - dest.value = .{ - .saved = .{}, - }; - dest.size = @as(u32, @truncate(bytes.len)); - } - } -} - -pub const DeferredBatchTask = bun.bundle_v2.DeferredBatchTask; -pub const ThreadPool = bun.bundle_v2.ThreadPool; -pub const ParseTask = bun.bundle_v2.ParseTask; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const Loader = bun.Loader; -const Output = bun.Output; -const base64 = bun.base64; -const default_allocator = bun.default_allocator; -const jsc = bun.jsc; -const options = bun.options; -const strings = bun.strings; - -const bundler = bun.bundle_v2; -const Chunk = bundler.Chunk; -const cheapPrefixNormalizer = bundler.cheapPrefixNormalizer; - -const LinkerContext = bun.bundle_v2.LinkerContext; -const OutputFileListBuilder = bun.bundle_v2.LinkerContext.OutputFileListBuilder; -const debug = LinkerContext.debug; - -const Logger = bun.logger; -const Loc = Logger.Loc; diff --git a/src/bundler/options.zig b/src/bundler/options.zig deleted file mode 100644 index daea5ced59a3..000000000000 --- a/src/bundler/options.zig +++ /dev/null @@ -1,2654 +0,0 @@ -/// This file is mostly the API schema but with all the options normalized. -/// Normalization is necessary because most fields in the API schema are optional -const std = @import("std"); - -pub const defines = @import("./defines.zig"); -pub const Define = defines.Define; - -pub const WriteDestination = enum { - stdout, - disk, - // eventually: wasm -}; - -pub fn validatePath( - log: *logger.Log, - _: *Fs.FileSystem.Implementation, - cwd: string, - rel_path: string, - allocator: std.mem.Allocator, - _: string, -) string { - if (rel_path.len == 0) { - return ""; - } - const paths = [_]string{ cwd, rel_path }; - // TODO: switch to getFdPath()-based implementation - const out = std.fs.path.resolve(allocator, &paths) catch |err| { - log.addErrorFmt( - null, - logger.Loc.Empty, - allocator, - "{s} resolving external: \"{s}\"", - .{ @errorName(err), rel_path }, - ) catch unreachable; - return ""; - }; - - return out; -} - -pub fn stringHashMapFromArrays(comptime t: type, allocator: std.mem.Allocator, total_capacity: usize, keys: anytype, values: anytype) !t { - var hash_map = t.init(allocator); - if (keys.len > 0) { - try hash_map.ensureTotalCapacity(@as(u32, @intCast(total_capacity))); - for (keys, 0..) |key, i| { - hash_map.putAssumeCapacity(key, values[i]); - } - } - - return hash_map; -} - -pub const AllowUnresolved = union(enum) { - /// Default. Skip all checks — current behavior. - all, - /// Always error on dynamic specifiers. - none, - /// Glob patterns; at least one must match the extracted shape. - patterns: []const string, - - pub const default: AllowUnresolved = .all; - - /// Normalize from raw CLI/JS input. - /// [] → .none, contains "*" → .all, else → .patterns - pub fn fromStrings(strs: []const string) AllowUnresolved { - if (strs.len == 0) return .none; - for (strs) |s| if (bun.strings.eqlComptime(s, "*")) return .all; - return .{ .patterns = strs }; - } - - /// shape is the extracted template representation (may be ""). - pub fn allows(self: AllowUnresolved, shape: []const u8) bool { - return switch (self) { - .all => true, - .none => false, - .patterns => |pats| for (pats) |p| { - if (bun.glob.match(p, shape).matches()) break true; - } else false, - }; - } -}; - -pub const ExternalModules = struct { - node_modules: std.BufSet, - abs_paths: std.BufSet, - patterns: []const WildcardPattern, - - pub const WildcardPattern = struct { - prefix: string, - suffix: string, - }; - - pub fn isNodeBuiltin(str: string) bool { - return bun.jsc.ModuleLoader.HardcodedModule.Alias.has(str, .node, .{}); - } - - const default_wildcard_patterns = &[_]WildcardPattern{ - .{ - .prefix = "/bun:", - .suffix = "", - }, - // .{ - // .prefix = "/src:", - // .suffix = "", - // }, - // .{ - // .prefix = "/blob:", - // .suffix = "", - // }, - }; - - pub fn init( - allocator: std.mem.Allocator, - fs: *Fs.FileSystem.Implementation, - cwd: string, - externals: []const string, - log: *logger.Log, - target: Target, - ) ExternalModules { - var result = ExternalModules{ - .node_modules = std.BufSet.init(allocator), - .abs_paths = std.BufSet.init(allocator), - .patterns = default_wildcard_patterns[0..], - }; - - switch (target) { - .node => { - // TODO: fix this stupid copy - result.node_modules.hash_map.ensureTotalCapacity(NodeBuiltinPatterns.len) catch unreachable; - for (NodeBuiltinPatterns) |pattern| { - result.node_modules.insert(pattern) catch unreachable; - } - }, - .bun => { - - // // TODO: fix this stupid copy - // result.node_modules.hash_map.ensureTotalCapacity(BunNodeBuiltinPatternsCompat.len) catch unreachable; - // for (BunNodeBuiltinPatternsCompat) |pattern| { - // result.node_modules.insert(pattern) catch unreachable; - // } - }, - else => {}, - } - - if (externals.len == 0) { - return result; - } - - var patterns = std.array_list.Managed(WildcardPattern).initCapacity(allocator, default_wildcard_patterns.len) catch unreachable; - patterns.appendSliceAssumeCapacity(default_wildcard_patterns[0..]); - - for (externals) |external| { - const path = external; - if (strings.indexOfChar(path, '*')) |i| { - if (strings.indexOfChar(path[i + 1 .. path.len], '*') != null) { - log.addErrorFmt(null, logger.Loc.Empty, allocator, "External path \"{s}\" cannot have more than one \"*\" wildcard", .{external}) catch unreachable; - return result; - } - - patterns.append(WildcardPattern{ - .prefix = external[0..i], - .suffix = external[i + 1 .. external.len], - }) catch unreachable; - } else if (resolver.isPackagePath(external)) { - result.node_modules.insert(external) catch unreachable; - } else { - const normalized = validatePath(log, fs, cwd, external, allocator, "external path"); - - if (normalized.len > 0) { - result.abs_paths.insert(normalized) catch unreachable; - } - } - } - - result.patterns = bun.handleOom(patterns.toOwnedSlice()); - - return result; - } - - const NodeBuiltinPatternsRaw = [_]string{ - "_http_agent", - "_http_client", - "_http_common", - "_http_incoming", - "_http_outgoing", - "_http_server", - "_stream_duplex", - "_stream_passthrough", - "_stream_readable", - "_stream_transform", - "_stream_wrap", - "_stream_writable", - "_tls_common", - "_tls_wrap", - "assert", - "async_hooks", - "buffer", - "child_process", - "cluster", - "console", - "constants", - "crypto", - "dgram", - "diagnostics_channel", - "dns", - "domain", - "events", - "fs", - "http", - "http2", - "https", - "inspector", - "module", - "net", - "os", - "path", - "perf_hooks", - "process", - "punycode", - "querystring", - "readline", - "repl", - "stream", - "string_decoder", - "sys", - "test", - "timers", - "tls", - "trace_events", - "tty", - "url", - "util", - "v8", - "vm", - "wasi", - "worker_threads", - "zlib", - }; - - pub const NodeBuiltinPatterns = NodeBuiltinPatternsRaw ++ brk: { - var builtins = NodeBuiltinPatternsRaw; - for (&builtins) |*builtin| { - builtin.* = "node:" ++ builtin.*; - } - break :brk builtins; - }; - - pub const BunNodeBuiltinPatternsCompat = [_]string{ - "_http_agent", - "_http_client", - "_http_common", - "_http_incoming", - "_http_outgoing", - "_http_server", - "_stream_duplex", - "_stream_passthrough", - "_stream_readable", - "_stream_transform", - "_stream_wrap", - "_stream_writable", - "_tls_common", - "_tls_wrap", - "assert", - "async_hooks", - // "buffer", - "child_process", - "cluster", - "console", - "constants", - "crypto", - "dgram", - "diagnostics_channel", - "dns", - "domain", - "events", - "http", - "http2", - "https", - "inspector", - "module", - "net", - "os", - // "path", - "perf_hooks", - // "process", - "punycode", - "querystring", - "readline", - "repl", - "stream", - "string_decoder", - "sys", - "timers", - "tls", - "trace_events", - "tty", - "url", - "util", - "v8", - "vm", - "wasi", - "worker_threads", - "zlib", - }; - - pub const NodeBuiltinsMap = bun.ComptimeStringMap(void, .{ - .{ "_http_agent", {} }, - .{ "_http_client", {} }, - .{ "_http_common", {} }, - .{ "_http_incoming", {} }, - .{ "_http_outgoing", {} }, - .{ "_http_server", {} }, - .{ "_stream_duplex", {} }, - .{ "_stream_passthrough", {} }, - .{ "_stream_readable", {} }, - .{ "_stream_transform", {} }, - .{ "_stream_wrap", {} }, - .{ "_stream_writable", {} }, - .{ "_tls_common", {} }, - .{ "_tls_wrap", {} }, - .{ "assert", {} }, - .{ "async_hooks", {} }, - .{ "buffer", {} }, - .{ "child_process", {} }, - .{ "cluster", {} }, - .{ "console", {} }, - .{ "constants", {} }, - .{ "crypto", {} }, - .{ "dgram", {} }, - .{ "diagnostics_channel", {} }, - .{ "dns", {} }, - .{ "domain", {} }, - .{ "events", {} }, - .{ "fs", {} }, - .{ "http", {} }, - .{ "http2", {} }, - .{ "https", {} }, - .{ "inspector", {} }, - .{ "module", {} }, - .{ "net", {} }, - .{ "os", {} }, - .{ "path", {} }, - .{ "perf_hooks", {} }, - .{ "process", {} }, - .{ "punycode", {} }, - .{ "querystring", {} }, - .{ "readline", {} }, - .{ "repl", {} }, - .{ "stream", {} }, - .{ "string_decoder", {} }, - .{ "sys", {} }, - .{ "timers", {} }, - .{ "tls", {} }, - .{ "trace_events", {} }, - .{ "tty", {} }, - .{ "url", {} }, - .{ "util", {} }, - .{ "v8", {} }, - .{ "vm", {} }, - .{ "wasi", {} }, - .{ "worker_threads", {} }, - .{ "zlib", {} }, - }); -}; - -pub const BundlePackage = @import("../options_types/BundleEnums.zig").BundlePackage; - -pub const ModuleType = enum { - unknown, - cjs, - esm, - - pub const List = bun.ComptimeStringMap(ModuleType, .{ - .{ "commonjs", ModuleType.cjs }, - .{ "module", ModuleType.esm }, - }); -}; - -pub const Target = enum { - browser, - bun, - bun_macro, - node, - - /// This is used by bake.Framework.ServerComponents.separate_ssr_graph - bake_server_components_ssr, - - pub const Map = bun.ComptimeStringMap(Target, .{ - .{ "browser", .browser }, - .{ "bun", .bun }, - .{ "bun_macro", .bun_macro }, - .{ "macro", .bun_macro }, - .{ "node", .node }, - }); - - pub const fromJS = @import("../bundler_jsc/options_jsc.zig").targetFromJS; - - pub fn toAPI(this: Target) api.Target { - return switch (this) { - .node => .node, - .browser => .browser, - .bun, .bake_server_components_ssr => .bun, - .bun_macro => .bun_macro, - }; - } - - pub inline fn isServerSide(this: Target) bool { - return switch (this) { - .bun_macro, .node, .bun, .bake_server_components_ssr => true, - else => false, - }; - } - - pub inline fn isBun(this: Target) bool { - return switch (this) { - .bun_macro, .bun, .bake_server_components_ssr => true, - else => false, - }; - } - - pub inline fn isNode(this: Target) bool { - return switch (this) { - .node => true, - else => false, - }; - } - - pub inline fn processBrowserDefineValue(this: Target) ?string { - return switch (this) { - .browser => "true", - else => "false", - }; - } - - pub fn bakeGraph(target: Target) bun.bake.Graph { - return switch (target) { - .browser => .client, - .bake_server_components_ssr => .ssr, - .bun_macro, .bun, .node => .server, - }; - } - - pub fn outExtensions(target: Target, allocator: std.mem.Allocator) bun.StringHashMap(string) { - var exts = bun.StringHashMap(string).init(allocator); - - const out_extensions_list = [_][]const u8{ ".js", ".cjs", ".mts", ".cts", ".ts", ".tsx", ".jsx", ".json" }; - - if (target == .node) { - exts.ensureTotalCapacity(out_extensions_list.len * 2) catch unreachable; - for (out_extensions_list) |ext| { - exts.put(ext, ".mjs") catch unreachable; - } - } else { - exts.ensureTotalCapacity(out_extensions_list.len + 1) catch unreachable; - exts.put(".mjs", ".js") catch unreachable; - } - - for (out_extensions_list) |ext| { - exts.put(ext, ".js") catch unreachable; - } - - return exts; - } - - pub fn from(plat: ?api.Target) Target { - return switch (plat orelse api.Target._none) { - .node => .node, - .browser => .browser, - .bun => .bun, - .bun_macro => .bun_macro, - else => .browser, - }; - } - - const MAIN_FIELD_NAMES = [_]string{ - "browser", - "module", - - "main", - - // https://github.com/jsforum/jsforum/issues/5 - // Older packages might use jsnext:main in place of module - "jsnext:main", - }; - pub const DefaultMainFields: std.EnumArray(Target, []const string) = brk: { - var array = std.EnumArray(Target, []const string).initUndefined(); - - // Note that this means if a package specifies "module" and "main", the ES6 - // module will not be selected. This means tree shaking will not work when - // targeting node environments. - // - // Some packages incorrectly treat the "module" field as "code for the browser". It - // actually means "code for ES6 environments" which includes both node and the browser. - // - // For example, the package "@firebase/app" prints a warning on startup about - // the bundler incorrectly using code meant for the browser if the bundler - // selects the "module" field instead of the "main" field. - // - // This is unfortunate but it's a problem on the side of those packages. - // They won't work correctly with other popular bundlers (with node as a target) anyway. - const list = [_]string{ MAIN_FIELD_NAMES[2], MAIN_FIELD_NAMES[1] }; - array.set(Target.node, &list); - - // Note that this means if a package specifies "main", "module", and - // "browser" then "browser" will win out over "module". This is the - // same behavior as webpack: https://github.com/webpack/webpack/issues/4674. - // - // This is deliberate because the presence of the "browser" field is a - // good signal that this should be preferred. Some older packages might only use CJS in their "browser" - // but in such a case they probably don't have any ESM files anyway. - const listc = [_]string{ MAIN_FIELD_NAMES[0], MAIN_FIELD_NAMES[1], MAIN_FIELD_NAMES[3], MAIN_FIELD_NAMES[2] }; - const listd = [_]string{ MAIN_FIELD_NAMES[1], MAIN_FIELD_NAMES[2], MAIN_FIELD_NAMES[3] }; - - array.set(Target.browser, &listc); - array.set(Target.bun, &listd); - array.set(Target.bun_macro, &listd); - array.set(Target.bake_server_components_ssr, &listd); - - // Original comment: - // The neutral target is for people that don't want esbuild to try to - // pick good defaults for their platform. In that case, the list of main - // fields is empty by default. You must explicitly configure it yourself. - // array.set(Target.neutral, &listc); - - break :brk array; - }; - - pub const default_conditions: std.EnumArray(Target, []const string) = brk: { - var array = std.EnumArray(Target, []const string).initUndefined(); - - array.set(Target.node, &.{ - "node", - }); - array.set(Target.browser, &.{ - "browser", - "module", - }); - array.set(Target.bun, &.{ - "bun", - "node", - }); - array.set(Target.bake_server_components_ssr, &.{ - "bun", - "node", - }); - array.set(Target.bun_macro, &.{ - "macro", - "bun", - "node", - }); - - break :brk array; - }; - - pub fn defaultConditions(t: Target) []const []const u8 { - return default_conditions.get(t); - } -}; - -pub const Format = @import("../options_types/BundleEnums.zig").Format; - -pub const WindowsOptions = @import("../options_types/BundleEnums.zig").WindowsOptions; - -// The max integer value in this enum can only be appended to. -// It has dependencies in several places: -// - bun-native-bundler-plugin-api/bundler_plugin.h -// - src/jsc/bindings/headers-handwritten.h -pub const Loader = enum(u8) { - jsx = 0, - js = 1, - ts = 2, - tsx = 3, - css = 4, - file = 5, - json = 6, - jsonc = 7, - toml = 8, - wasm = 9, - napi = 10, - base64 = 11, - dataurl = 12, - text = 13, - bunsh = 14, - sqlite = 15, - sqlite_embedded = 16, - html = 17, - yaml = 18, - json5 = 19, - md = 20, - - pub const Optional = enum(u8) { - none = 254, - _, - pub fn unwrap(opt: Optional) ?Loader { - return if (opt == .none) null else @enumFromInt(@intFromEnum(opt)); - } - - pub fn fromAPI(loader: bun.schema.api.Loader) Optional { - if (loader == ._none) { - return .none; - } - const l: Loader = .fromAPI(loader); - return @enumFromInt(@intFromEnum(l)); - } - }; - - pub fn isCSS(this: Loader) bool { - return this == .css; - } - - pub fn isJSLike(this: Loader) bool { - return switch (this) { - .jsx, .js, .ts, .tsx => true, - else => false, - }; - } - - pub fn disableHTML(this: Loader) Loader { - return switch (this) { - .html => .file, - else => this, - }; - } - - pub inline fn isSQLite(this: Loader) bool { - return switch (this) { - .sqlite, .sqlite_embedded => true, - else => false, - }; - } - - pub fn shouldCopyForBundling(this: Loader) bool { - return switch (this) { - .file, - .napi, - .sqlite, - .sqlite_embedded, - // TODO: loader for reading bytes and creating module or instance - .wasm, - => true, - .css => false, - .html => false, - else => false, - }; - } - - pub fn handlesEmptyFile(this: Loader) bool { - return switch (this) { - .wasm, .file, .text => true, - else => false, - }; - } - - pub fn toMimeType(this: Loader, paths: []const []const u8) bun.http.MimeType { - return switch (this) { - .jsx, .js, .ts, .tsx => bun.http.MimeType.javascript, - .css => bun.http.MimeType.css, - .toml, .yaml, .json, .jsonc, .json5 => bun.http.MimeType.json, - .wasm => bun.http.MimeType.wasm, - .html, .md => bun.http.MimeType.html, - else => { - for (paths) |path| { - var extname = std.fs.path.extension(path); - if (strings.startsWithChar(extname, '.')) { - extname = extname[1..]; - } - if (extname.len > 0) { - if (bun.http.MimeType.byExtensionNoDefault(extname)) |mime| { - return mime; - } - } - } - - return bun.http.MimeType.other; - }, - }; - } - - pub const HashTable = bun.StringArrayHashMap(Loader); - - pub fn canHaveSourceMap(this: Loader) bool { - return switch (this) { - .jsx, .js, .ts, .tsx => true, - else => false, - }; - } - - pub fn canBeRunByBun(this: Loader) bool { - return switch (this) { - .jsx, .js, .ts, .tsx, .wasm, .bunsh => true, - else => false, - }; - } - - pub const Map = std.EnumArray(Loader, string); - pub const stdin_name: Map = brk: { - var map = Map.initFill(""); - map.set(.jsx, "input.jsx"); - map.set(.js, "input.js"); - map.set(.ts, "input.ts"); - map.set(.tsx, "input.tsx"); - map.set(.css, "input.css"); - map.set(.file, "input"); - map.set(.json, "input.json"); - map.set(.toml, "input.toml"); - map.set(.yaml, "input.yaml"); - map.set(.json5, "input.json5"); - map.set(.wasm, "input.wasm"); - map.set(.napi, "input.node"); - map.set(.text, "input.txt"); - map.set(.bunsh, "input.sh"); - map.set(.html, "input.html"); - map.set(.md, "input.md"); - break :brk map; - }; - - pub inline fn stdinName(this: Loader) string { - return stdin_name.get(this); - } - - pub const fromJS = @import("../bundler_jsc/options_jsc.zig").loaderFromJS; - - pub const names = bun.ComptimeStringMap(Loader, .{ - .{ "js", .js }, - .{ "mjs", .js }, - .{ "cjs", .js }, - .{ "cts", .ts }, - .{ "mts", .ts }, - .{ "jsx", .jsx }, - .{ "ts", .ts }, - .{ "tsx", .tsx }, - .{ "css", .css }, - .{ "file", .file }, - .{ "json", .json }, - .{ "jsonc", .jsonc }, - .{ "toml", .toml }, - .{ "yaml", .yaml }, - .{ "json5", .json5 }, - .{ "wasm", .wasm }, - .{ "napi", .napi }, - .{ "node", .napi }, - .{ "dataurl", .dataurl }, - .{ "base64", .base64 }, - .{ "txt", .text }, - .{ "text", .text }, - .{ "sh", .bunsh }, - .{ "sqlite", .sqlite }, - .{ "sqlite_embedded", .sqlite_embedded }, - .{ "html", .html }, - .{ "md", .md }, - .{ "markdown", .md }, - }); - - pub const api_names = bun.ComptimeStringMap(api.Loader, .{ - .{ "js", .js }, - .{ "mjs", .js }, - .{ "cjs", .js }, - .{ "cts", .ts }, - .{ "mts", .ts }, - .{ "jsx", .jsx }, - .{ "ts", .ts }, - .{ "tsx", .tsx }, - .{ "css", .css }, - .{ "file", .file }, - .{ "json", .json }, - .{ "jsonc", .json }, - .{ "toml", .toml }, - .{ "yaml", .yaml }, - .{ "json5", .json5 }, - .{ "wasm", .wasm }, - .{ "node", .napi }, - .{ "dataurl", .dataurl }, - .{ "base64", .base64 }, - .{ "txt", .text }, - .{ "text", .text }, - .{ "sh", .file }, - .{ "sqlite", .sqlite }, - .{ "html", .html }, - .{ "md", .md }, - .{ "markdown", .md }, - }); - - pub fn fromString(slice_: string) ?Loader { - var slice = slice_; - if (slice.len > 0 and slice[0] == '.') { - slice = slice[1..]; - } - - return names.getWithEql(slice, strings.eqlCaseInsensitiveASCIIICheckLength); - } - - pub fn supportsClientEntryPoint(this: Loader) bool { - return switch (this) { - .jsx, .js, .ts, .tsx => true, - else => false, - }; - } - - pub fn toAPI(loader: Loader) api.Loader { - return switch (loader) { - .jsx => .jsx, - .js => .js, - .ts => .ts, - .tsx => .tsx, - .css => .css, - .html => .html, - .file, .bunsh => .file, - .json => .json, - .jsonc => .json, - .toml => .toml, - .yaml => .yaml, - .json5 => .json5, - .wasm => .wasm, - .napi => .napi, - .base64 => .base64, - .dataurl => .dataurl, - .text => .text, - .sqlite_embedded, .sqlite => .sqlite, - .md => .md, - }; - } - - pub fn fromAPI(loader: api.Loader) Loader { - return switch (loader) { - ._none => .file, - .jsx => .jsx, - .js => .js, - .ts => .ts, - .tsx => .tsx, - .css => .css, - .file => .file, - .json => .json, - .jsonc => .jsonc, - .toml => .toml, - .yaml => .yaml, - .json5 => .json5, - .wasm => .wasm, - .napi => .napi, - .base64 => .base64, - .dataurl => .dataurl, - .text => .text, - .bunsh => .bunsh, - .html => .html, - .sqlite => .sqlite, - .sqlite_embedded => .sqlite_embedded, - .md => .md, - _ => .file, - }; - } - - pub fn isJSX(loader: Loader) bool { - return loader == .jsx or loader == .tsx; - } - - pub fn isTypeScript(loader: Loader) bool { - return loader == .tsx or loader == .ts; - } - - pub fn isJavaScriptLike(loader: Loader) bool { - return switch (loader) { - .jsx, .js, .ts, .tsx => true, - else => false, - }; - } - - pub fn isJavaScriptLikeOrJSON(loader: Loader) bool { - return switch (loader) { - .jsx, .js, .ts, .tsx, .json, .jsonc => true, - - // toml, yaml, and json5 are included because we can serialize to the same AST as JSON - .toml, .yaml, .json5 => true, - - else => false, - }; - } - - pub fn forFileName(filename: string, obj: anytype) ?Loader { - const ext = std.fs.path.extension(filename); - if (ext.len == 0 or (ext.len == 1 and ext[0] == '.')) return null; - - return obj.get(ext); - } - - pub fn sideEffects(this: Loader) bun.resolver.SideEffects { - return switch (this) { - .text, .json, .jsonc, .toml, .yaml, .json5, .file, .md => bun.resolver.SideEffects.no_side_effects__pure_data, - else => bun.resolver.SideEffects.has_side_effects, - }; - } - - pub fn fromMimeType(mime_type: bun.http.MimeType) Loader { - if (strings.hasPrefixComptime(mime_type.value, "application/javascript-jsx")) { - return .jsx; - } else if (strings.hasPrefixComptime(mime_type.value, "application/typescript-jsx")) { - return .tsx; - } else if (strings.hasPrefixComptime(mime_type.value, "application/javascript")) { - return .js; - } else if (strings.hasPrefixComptime(mime_type.value, "application/typescript")) { - return .ts; - } else if (strings.hasPrefixComptime(mime_type.value, "application/json5")) { - return .json5; - } else if (strings.hasPrefixComptime(mime_type.value, "application/jsonc")) { - return .jsonc; - } else if (strings.hasPrefixComptime(mime_type.value, "application/json")) { - return .json; - } else if (mime_type.category == .text) { - return .text; - } else { - // Be maximally permissive. - return .tsx; - } - } -}; - -pub fn normalizeSpecifier( - jsc_vm: *bun.jsc.VirtualMachine, - slice_: string, -) struct { string, string, string } { - var slice = slice_; - if (slice.len == 0) return .{ slice, slice, "" }; - - if (strings.hasPrefix(slice, jsc_vm.origin.host)) { - slice = slice[jsc_vm.origin.host.len..]; - } - - if (jsc_vm.origin.path.len > 1) { - if (strings.hasPrefix(slice, jsc_vm.origin.path)) { - slice = slice[jsc_vm.origin.path.len..]; - } - } - - const specifier = slice; - var query: []const u8 = ""; - - if (strings.indexOfChar(slice, '?')) |i| { - query = slice[i..]; - slice = slice[0..i]; - } - - return .{ slice, specifier, query }; -} - -const GetLoaderAndVirtualSourceErr = error{BlobNotFound}; -const LoaderResult = struct { - loader: ?Loader, - virtual_source: ?*logger.Source, - path: Fs.Path, - is_main: bool, - specifier: string, - /// NOTE: This is always `null` for non-js-like loaders since it's not - /// needed for them. - package_json: ?*const PackageJSON, -}; - -pub fn getLoaderAndVirtualSource( - specifier_str: string, - jsc_vm: *jsc.VirtualMachine, - virtual_source_to_use: *?logger.Source, - blob_to_deinit: *?jsc.WebCore.Blob, - type_attribute_str: ?string, -) GetLoaderAndVirtualSourceErr!LoaderResult { - const normalized_file_path_from_specifier, const specifier, const query = normalizeSpecifier( - jsc_vm, - specifier_str, - ); - var path = Fs.Path.init(normalized_file_path_from_specifier); - - var loader: ?Loader = path.loader(&jsc_vm.transpiler.options.loaders); - var virtual_source: ?*logger.Source = null; - - if (jsc_vm.module_loader.eval_source) |eval_source| { - if (strings.endsWithComptime(specifier, bun.pathLiteral("/[eval]"))) { - virtual_source = eval_source; - loader = .tsx; - } - if (strings.endsWithComptime(specifier, bun.pathLiteral("/[stdin]"))) { - virtual_source = eval_source; - loader = .tsx; - } - } - - if (jsc.WebCore.ObjectURLRegistry.isBlobURL(specifier)) { - if (jsc.WebCore.ObjectURLRegistry.singleton().resolveAndDupe(specifier["blob:".len..])) |blob| { - blob_to_deinit.* = blob; - loader = blob.getLoader(jsc_vm); - - // "file:" loader makes no sense for blobs - // so let's default to tsx. - if (blob.getFileName()) |filename| { - const current_path = Fs.Path.init(filename); - - // Only treat it as a file if is a Bun.file() - if (blob.needsToReadFile()) { - path = current_path; - } - } - - if (!blob.needsToReadFile()) { - virtual_source_to_use.* = logger.Source{ - .path = path, - .contents = blob.sharedView(), - }; - virtual_source = &virtual_source_to_use.*.?; - } - } else { - return error.BlobNotFound; - } - } - - if (strings.eqlComptime(query, "?raw")) { - loader = .text; - } - if (type_attribute_str) |attr_str| if (bun.options.Loader.fromString(attr_str)) |attr_loader| { - loader = attr_loader; - }; - - const is_main = strings.eqlLong(specifier, jsc_vm.main, true); - - const dir = path.name.dir; - // NOTE: we cannot trust `path.isFile()` since it's not always correct - // NOTE: assume we may need a package.json when no loader is specified - const is_js_like = if (loader) |l| l.isJSLike() else true; - const package_json: ?*const PackageJSON = if (is_js_like and std.fs.path.isAbsolute(dir)) - if (jsc_vm.transpiler.resolver.readDirInfo(dir) catch null) |dir_info| - dir_info.package_json orelse dir_info.enclosing_package_json - else - null - else - null; - - return .{ - .loader = loader, - .virtual_source = virtual_source, - .path = path, - .is_main = is_main, - .specifier = specifier, - .package_json = package_json, - }; -} - -const default_loaders_posix = .{ - .{ ".jsx", .jsx }, - .{ ".json", .json }, - .{ ".js", .jsx }, - - .{ ".mjs", .js }, - .{ ".cjs", .js }, - - .{ ".css", .css }, - .{ ".ts", .ts }, - .{ ".tsx", .tsx }, - - .{ ".mts", .ts }, - .{ ".cts", .ts }, - - .{ ".toml", .toml }, - .{ ".yaml", .yaml }, - .{ ".yml", .yaml }, - .{ ".wasm", .wasm }, - .{ ".node", .napi }, - .{ ".txt", .text }, - .{ ".text", .text }, - .{ ".html", .html }, - .{ ".jsonc", .jsonc }, - .{ ".json5", .json5 }, - .{ ".md", .md }, - .{ ".markdown", .md }, -}; -const default_loaders_win32 = default_loaders_posix ++ .{ - .{ ".sh", .bunsh }, -}; - -const default_loaders = if (Environment.isWindows) default_loaders_win32 else default_loaders_posix; -pub const defaultLoaders = bun.ComptimeStringMap(Loader, default_loaders); - -// https://webpack.js.org/guides/package-exports/#reference-syntax -pub const ESMConditions = struct { - default: ConditionsMap, - import: ConditionsMap, - require: ConditionsMap, - style: ConditionsMap, - - pub fn init(allocator: std.mem.Allocator, defaults: []const string, allow_addons: bool, conditions: []const string) bun.OOM!ESMConditions { - var default_condition_amp = ConditionsMap.init(allocator); - - var import_condition_map = ConditionsMap.init(allocator); - var require_condition_map = ConditionsMap.init(allocator); - var style_condition_map = ConditionsMap.init(allocator); - - try default_condition_amp.ensureTotalCapacity(defaults.len + 2 + if (allow_addons) 1 else 0 + conditions.len); - try import_condition_map.ensureTotalCapacity(defaults.len + 2 + if (allow_addons) 1 else 0 + conditions.len); - try require_condition_map.ensureTotalCapacity(defaults.len + 2 + if (allow_addons) 1 else 0 + conditions.len); - try style_condition_map.ensureTotalCapacity(defaults.len + 2 + conditions.len); - - import_condition_map.putAssumeCapacity("import", {}); - require_condition_map.putAssumeCapacity("require", {}); - style_condition_map.putAssumeCapacity("style", {}); - - for (conditions) |condition| { - import_condition_map.putAssumeCapacity(condition, {}); - require_condition_map.putAssumeCapacity(condition, {}); - default_condition_amp.putAssumeCapacity(condition, {}); - } - - for (defaults) |default| { - default_condition_amp.putAssumeCapacity(default, {}); - import_condition_map.putAssumeCapacity(default, {}); - require_condition_map.putAssumeCapacity(default, {}); - style_condition_map.putAssumeCapacity(default, {}); - } - - if (allow_addons) { - default_condition_amp.putAssumeCapacity("node-addons", {}); - import_condition_map.putAssumeCapacity("node-addons", {}); - require_condition_map.putAssumeCapacity("node-addons", {}); - - // style is not here because you don't import N-API addons inside css files. - } - - default_condition_amp.putAssumeCapacity("default", {}); - import_condition_map.putAssumeCapacity("default", {}); - require_condition_map.putAssumeCapacity("default", {}); - style_condition_map.putAssumeCapacity("default", {}); - - return .{ - .default = default_condition_amp, - .import = import_condition_map, - .require = require_condition_map, - .style = style_condition_map, - }; - } - - pub fn clone(self: *const ESMConditions) !ESMConditions { - var default = try self.default.clone(); - errdefer default.deinit(); - var import = try self.import.clone(); - errdefer import.deinit(); - var require = try self.require.clone(); - errdefer require.deinit(); - var style = try self.style.clone(); - errdefer style.deinit(); - - return .{ - .default = default, - .import = import, - .require = require, - .style = style, - }; - } - - pub fn appendSlice(self: *ESMConditions, conditions: []const string) bun.OOM!void { - try self.default.ensureUnusedCapacity(conditions.len); - try self.import.ensureUnusedCapacity(conditions.len); - try self.require.ensureUnusedCapacity(conditions.len); - try self.style.ensureUnusedCapacity(conditions.len); - - for (conditions) |condition| { - self.default.putAssumeCapacity(condition, {}); - self.import.putAssumeCapacity(condition, {}); - self.require.putAssumeCapacity(condition, {}); - self.style.putAssumeCapacity(condition, {}); - } - } - - pub fn append(self: *ESMConditions, condition: string) bun.OOM!void { - try self.default.put(condition, {}); - try self.import.put(condition, {}); - try self.require.put(condition, {}); - try self.style.put(condition, {}); - } -}; - -pub const JSX = struct { - const RuntimeDevelopmentPair = struct { - runtime: JSX.Runtime, - development: ?bool, - }; - - pub const RuntimeMap = bun.ComptimeStringMap(RuntimeDevelopmentPair, .{ - .{ "classic", RuntimeDevelopmentPair{ .runtime = .classic, .development = null } }, - .{ "automatic", RuntimeDevelopmentPair{ .runtime = .automatic, .development = true } }, - .{ "react", RuntimeDevelopmentPair{ .runtime = .classic, .development = null } }, - .{ "react-jsx", RuntimeDevelopmentPair{ .runtime = .automatic, .development = true } }, - .{ "react-jsxdev", RuntimeDevelopmentPair{ .runtime = .automatic, .development = true } }, - }); - - pub const Pragma = struct { - // these need to be arrays - factory: []const string = Defaults.Factory, - fragment: []const string = Defaults.Fragment, - runtime: JSX.Runtime = .automatic, - import_source: ImportSource = .{}, - - /// Facilitates automatic JSX importing - /// Set on a per file basis like this: - /// /** @jsxImportSource @emotion/core */ - classic_import_source: string = "react", - package_name: []const u8 = "react", - - /// Configuration Priority: - /// - `--define=process.env.NODE_ENV=...` - /// - `NODE_ENV=...` - /// - tsconfig.json's `compilerOptions.jsx` (`react-jsx` or `react-jsxdev`) - development: bool = true, - parse: bool = true, - side_effects: bool = false, - - pub const ImportSource = struct { - development: string = "react/jsx-dev-runtime", - production: string = "react/jsx-runtime", - }; - - pub fn hashForRuntimeTranspiler(this: *const Pragma, hasher: *std.hash.Wyhash) void { - for (this.factory) |factory| hasher.update(factory); - for (this.fragment) |fragment| hasher.update(fragment); - hasher.update(this.import_source.development); - hasher.update(this.import_source.production); - hasher.update(this.classic_import_source); - hasher.update(this.package_name); - } - - pub fn importSource(this: *const Pragma) string { - return switch (this.development) { - true => this.import_source.development, - false => this.import_source.production, - }; - } - - pub fn parsePackageName(str: string) string { - if (str.len == 0) return str; - if (str[0] == '@') { - if (strings.indexOfChar(str[1..], '/')) |first_slash| { - const remainder = str[1 + first_slash + 1 ..]; - - if (strings.indexOfChar(remainder, '/')) |last_slash| { - return str[0 .. first_slash + 1 + last_slash + 1]; - } - } - } - - if (strings.indexOfChar(str, '/')) |first_slash| { - return str[0..first_slash]; - } - - return str; - } - - pub fn isReactLike(pragma: *const Pragma) bool { - return strings.eqlComptime(pragma.package_name, "react") or - strings.eqlComptime(pragma.package_name, "@emotion/jsx") or - strings.eqlComptime(pragma.package_name, "@emotion/react"); - } - - pub fn setImportSource(pragma: *Pragma, allocator: std.mem.Allocator) void { - strings.concatIfNeeded( - allocator, - &pragma.import_source.development, - &[_]string{ - pragma.package_name, - "/jsx-dev-runtime", - }, - &.{ - Defaults.ImportSourceDev, - }, - ) catch unreachable; - - strings.concatIfNeeded( - allocator, - &pragma.import_source.production, - &[_]string{ - pragma.package_name, - "/jsx-runtime", - }, - &.{ - Defaults.ImportSource, - }, - ) catch unreachable; - } - - pub fn setProduction(pragma: *Pragma, is_production: bool) void { - pragma.development = !is_production; - } - - pub const Defaults = struct { - pub const Factory = &[_]string{ "React", "createElement" }; - pub const Fragment = &[_]string{ "React", "Fragment" }; - pub const ImportSourceDev = "react/jsx-dev-runtime"; - pub const ImportSource = "react/jsx-runtime"; - pub const JSXFunction = "jsx"; - pub const JSXStaticFunction = "jsxs"; - pub const JSXFunctionDev = "jsxDEV"; - }; - - // "React.createElement" => ["React", "createElement"] - // ...unless new is "React.createElement" and original is ["React", "createElement"] - // saves an allocation for the majority case - pub fn memberListToComponentsIfDifferent(allocator: std.mem.Allocator, original: []const string, new: string) ![]const string { - var splitter = std.mem.splitScalar(u8, new, '.'); - const count = strings.countChar(new, '.') + 1; - - var needs_alloc = false; - var current_i: usize = 0; - while (splitter.next()) |str| { - if (str.len == 0) continue; - if (current_i >= original.len) { - needs_alloc = true; - break; - } - - if (!strings.eql(original[current_i], str)) { - needs_alloc = true; - break; - } - current_i += 1; - } - - if (!needs_alloc) { - return original; - } - - var out = try allocator.alloc(string, count); - - splitter = std.mem.splitScalar(u8, new, '.'); - var i: usize = 0; - while (splitter.next()) |str| { - if (str.len == 0) continue; - out[i] = str; - i += 1; - } - return out[0..i]; - } - - pub fn fromApi(jsx: api.Jsx, allocator: std.mem.Allocator) !Pragma { - var pragma = JSX.Pragma{}; - - if (jsx.fragment.len > 0) { - pragma.fragment = try memberListToComponentsIfDifferent(allocator, pragma.fragment, jsx.fragment); - } - - if (jsx.factory.len > 0) { - pragma.factory = try memberListToComponentsIfDifferent(allocator, pragma.factory, jsx.factory); - } - - pragma.runtime = jsx.runtime; - pragma.side_effects = jsx.side_effects; - - if (jsx.import_source.len > 0) { - pragma.package_name = jsx.import_source; - pragma.setImportSource(allocator); - pragma.classic_import_source = pragma.package_name; - } - - pragma.development = jsx.development; - pragma.parse = true; - return pragma; - } - }; - - pub const Runtime = api.JsxRuntime; -}; - -pub const DefaultUserDefines = struct { - // This must be globally scoped so it doesn't disappear - pub const NodeEnv = struct { - pub const Key = "process.env.NODE_ENV"; - pub const Value = "\"development\""; - }; - pub const ProcessBrowserDefine = struct { - pub const Key = "process.browser"; - pub const Value = []string{ "false", "true" }; - }; -}; - -pub fn definesFromTransformOptions( - allocator: std.mem.Allocator, - log: *logger.Log, - maybe_input_define: ?api.StringMap, - target: Target, - env_loader: ?*DotEnv.Loader, - framework_env: ?*const Env, - NODE_ENV: ?string, - drop: []const []const u8, - omit_unused_global_calls: bool, -) !*defines.Define { - const input_user_define = maybe_input_define orelse std.mem.zeroes(api.StringMap); - - var user_defines = try stringHashMapFromArrays( - defines.RawDefines, - allocator, - input_user_define.keys.len + 4, - input_user_define.keys, - input_user_define.values, - ); - defer user_defines.deinit(); - - var environment_defines = defines.UserDefinesArray.init(allocator); - defer environment_defines.deinit(); - - var behavior: api.DotEnvBehavior = .disable; - - load_env: { - const env = env_loader orelse break :load_env; - const framework = framework_env orelse break :load_env; - - if (Environment.allow_assert) { - bun.assert(framework.behavior != ._none); - } - - behavior = framework.behavior; - if (behavior == .load_all_without_inlining or behavior == .disable) - break :load_env; - - try env.copyForDefine( - defines.RawDefines, - &user_defines, - defines.UserDefinesArray, - &environment_defines, - framework.toAPI().defaults, - framework.behavior, - framework.prefix, - allocator, - ); - } - - if (behavior != .load_all_without_inlining) { - const quoted_node_env: string = brk: { - if (NODE_ENV) |node_env| { - if (node_env.len > 0) { - if ((strings.startsWithChar(node_env, '"') and strings.endsWithChar(node_env, '"')) or - (strings.startsWithChar(node_env, '\'') and strings.endsWithChar(node_env, '\''))) - { - break :brk node_env; - } - - // avoid allocating if we can - if (strings.eqlComptime(node_env, "production")) { - break :brk "\"production\""; - } else if (strings.eqlComptime(node_env, "development")) { - break :brk "\"development\""; - } else if (strings.eqlComptime(node_env, "test")) { - break :brk "\"test\""; - } else { - break :brk try std.fmt.allocPrint(allocator, "\"{s}\"", .{node_env}); - } - } - } - break :brk "\"development\""; - }; - - _ = try user_defines.getOrPutValue( - "process.env.NODE_ENV", - quoted_node_env, - ); - _ = try user_defines.getOrPutValue( - "process.env.BUN_ENV", - quoted_node_env, - ); - - // Automatically set `process.browser` to `true` for browsers and false for node+js - // This enables some extra dead code elimination - if (target.processBrowserDefineValue()) |value| { - _ = try user_defines.getOrPutValue(DefaultUserDefines.ProcessBrowserDefine.Key, value); - } - } - - if (target.isBun()) { - if (!user_defines.contains("window")) { - _ = try environment_defines.getOrPutValue("window", .init(.{ - .valueless = true, - .original_name = "window", - .value = .{ .e_undefined = .{} }, - })); - } - } - - const resolved_defines = try defines.DefineData.fromInput(user_defines, drop, log, allocator); - - const drop_debugger = for (drop) |item| { - if (strings.eqlComptime(item, "debugger")) break true; - } else false; - - return try defines.Define.init( - allocator, - resolved_defines, - environment_defines, - drop_debugger, - omit_unused_global_calls, - ); -} - -const default_loader_ext_bun = [_]string{ ".node", ".html" }; -const default_loader_ext = [_]string{ - ".jsx", ".json", - ".js", ".mjs", - ".cjs", ".css", - - // https://devblogs.microsoft.com/typescript/announcing-typescript-4-5-beta/#new-file-extensions - ".ts", ".tsx", - ".mts", ".cts", - - ".toml", ".yaml", - ".yml", ".wasm", - ".txt", ".text", - - ".jsonc", ".json5", -}; - -// Only set it for browsers by default. -const default_loader_ext_browser = [_]string{ - ".html", -}; - -const node_modules_default_loader_ext = [_]string{ - ".jsx", - ".js", - ".cjs", - ".mjs", - ".ts", - ".mts", - ".toml", - ".yaml", - ".yml", - ".txt", - ".json", - ".jsonc", - ".json5", - ".css", - ".tsx", - ".cts", - ".wasm", - ".text", - ".html", -}; - -pub const ResolveFileExtensions = struct { - node_modules: Group = .{ - .esm = &BundleOptions.Defaults.NodeModules.ModuleExtensionOrder, - .default = &BundleOptions.Defaults.NodeModules.ExtensionOrder, - }, - default: Group = .{}, - - inline fn group(this: *const ResolveFileExtensions, is_node_modules: bool) *const Group { - return switch (is_node_modules) { - true => &this.node_modules, - false => &this.default, - }; - } - - pub fn kind(this: *const ResolveFileExtensions, kind_: bun.ImportKind, is_node_modules: bool) []const string { - return switch (kind_) { - .stmt, .entry_point_build, .entry_point_run, .dynamic => this.group(is_node_modules).esm, - else => this.group(is_node_modules).default, - }; - } - - pub const Group = struct { - esm: []const string = &BundleOptions.Defaults.ModuleExtensionOrder, - default: []const string = &BundleOptions.Defaults.ExtensionOrder, - }; -}; - -pub fn loadersFromTransformOptions(allocator: std.mem.Allocator, _loaders: ?api.LoaderMap, target: Target) std.mem.Allocator.Error!bun.StringArrayHashMap(Loader) { - const input_loaders = _loaders orelse std.mem.zeroes(api.LoaderMap); - const loader_values = try allocator.alloc(Loader, input_loaders.loaders.len); - defer allocator.free(loader_values); - - for (loader_values, input_loaders.loaders) |*loader, input| { - loader.* = Loader.fromAPI(input); - } - - var loaders = try stringHashMapFromArrays( - bun.StringArrayHashMap(Loader), - allocator, - input_loaders.extensions.len + - if (target.isBun()) default_loader_ext_bun.len else 0 + - if (target == .browser) default_loader_ext_browser.len else 0 + - default_loader_ext.len, - input_loaders.extensions, - loader_values, - ); - errdefer loaders.deinit(); - - inline for (default_loader_ext) |ext| { - _ = try loaders.getOrPutValue(ext, defaultLoaders.get(ext).?); - } - - if (target.isBun()) { - inline for (default_loader_ext_bun) |ext| { - _ = try loaders.getOrPutValue(ext, defaultLoaders.get(ext).?); - } - } - - if (target == .browser) { - inline for (default_loader_ext_browser) |ext| { - _ = try loaders.getOrPutValue(ext, defaultLoaders.get(ext).?); - } - } - - return loaders; -} - -const Dir = std.fs.Dir; - -pub const SourceMapOption = enum { - none, - @"inline", - external, - linked, - - pub fn fromApi(source_map: ?api.SourceMapMode) SourceMapOption { - return switch (source_map orelse .none) { - .external => .external, - .@"inline" => .@"inline", - .linked => .linked, - else => .none, - }; - } - - pub fn toAPI(source_map: ?SourceMapOption) api.SourceMapMode { - return switch (source_map orelse .none) { - .external => .external, - .@"inline" => .@"inline", - .linked => .linked, - .none => .none, - }; - } - - pub fn hasExternalFiles(mode: SourceMapOption) bool { - return switch (mode) { - .linked, .external => true, - else => false, - }; - } - - pub const Map = bun.ComptimeStringMap(SourceMapOption, .{ - .{ "none", .none }, - .{ "inline", .@"inline" }, - .{ "external", .external }, - .{ "linked", .linked }, - }); -}; - -pub const PackagesOption = enum { - bundle, - external, - - pub fn fromApi(packages: ?api.PackagesMode) PackagesOption { - return switch (packages orelse .bundle) { - .external => .external, - .bundle => .bundle, - else => .bundle, - }; - } - - pub fn toAPI(packages: ?PackagesOption) api.PackagesMode { - return switch (packages orelse .bundle) { - .external => .external, - .bundle => .bundle, - }; - } - - pub const Map = bun.ComptimeStringMap(PackagesOption, .{ - .{ "external", .external }, - .{ "bundle", .bundle }, - }); -}; - -/// BundleOptions is used when ResolveMode is not set to "disable". -/// BundleOptions is effectively webpack + babel -pub const BundleOptions = struct { - footer: string = "", - banner: string = "", - define: *defines.Define, - drop: []const []const u8 = &.{}, - /// Set of enabled feature flags for dead-code elimination via `import { feature } from "bun:bundle"`. - /// Initialized once from the CLI --feature flags. - bundler_feature_flags: *const bun.StringSet = &Runtime.Features.empty_bundler_feature_flags, - loaders: Loader.HashTable, - resolve_dir: string = "/", - jsx: JSX.Pragma = JSX.Pragma{}, - emit_decorator_metadata: bool = false, - experimental_decorators: bool = false, - auto_import_jsx: bool = true, - allow_runtime: bool = true, - - trim_unused_imports: ?bool = null, - mark_builtins_as_external: bool = false, - server_components: bool = false, - hot_module_reloading: bool = false, - react_fast_refresh: bool = false, - inject: ?[]string = null, - origin: URL = URL{}, - output_dir_handle: ?Dir = null, - - output_dir: string = "out", - root_dir: string = "", - node_modules_bundle_url: string = "", - node_modules_bundle_pretty_path: string = "", - - write: bool = false, - preserve_symlinks: bool = false, - preserve_extensions: bool = false, - production: bool = false, - - // only used by bundle_v2 - output_format: Format = .esm, - - append_package_version_in_query_string: bool = false, - - tsconfig_override: ?string = null, - target: Target = Target.browser, - main_fields: []const string = Target.DefaultMainFields.get(Target.browser), - /// TODO: remove this in favor accessing bundler.log - log: *logger.Log, - external: ExternalModules, - allow_unresolved: AllowUnresolved = .all, - entry_points: []const string, - entry_naming: []const u8 = "", - asset_naming: []const u8 = "", - chunk_naming: []const u8 = "", - public_path: []const u8 = "", - extension_order: ResolveFileExtensions = .{}, - main_field_extension_order: []const string = &Defaults.MainFieldExtensionOrder, - /// This list applies to all extension resolution cases. The runtime uses - /// this for implementing `require.extensions` - extra_cjs_extensions: []const []const u8 = &.{}, - out_extensions: bun.StringHashMap(string), - import_path_format: ImportPathFormat = ImportPathFormat.relative, - defines_loaded: bool = false, - env: Env = Env{}, - transform_options: api.TransformOptions, - polyfill_node_globals: bool = false, - transform_only: bool = false, - load_tsconfig_json: bool = true, - load_package_json: bool = true, - - rewrite_jest_for_tests: bool = false, - - macro_remap: MacroRemap = MacroRemap{}, - no_macros: bool = false, - - conditions: ESMConditions = undefined, - tree_shaking: bool = false, - code_splitting: bool = false, - source_map: SourceMapOption = SourceMapOption.none, - packages: PackagesOption = PackagesOption.bundle, - - disable_transpilation: bool = false, - - global_cache: GlobalCache = .disable, - prefer_offline_install: bool = false, - prefer_latest_install: bool = false, - install: ?*api.BunInstall = null, - - inlining: bool = false, - inline_entrypoint_import_meta_main: bool = false, - minify_whitespace: bool = false, - minify_syntax: bool = false, - minify_identifiers: bool = false, - keep_names: bool = false, - dead_code_elimination: bool = true, - /// REPL mode: transforms code for interactive evaluation with vm.runInContext. - /// Hoists declarations as var for persistence, wraps code in IIFE, and - /// captures the last expression in { value: expr } for result extraction. - repl_mode: bool = false, - css_chunking: bool, - - ignore_dce_annotations: bool = false, - emit_dce_annotations: bool = false, - bytecode: bool = false, - - code_coverage: bool = false, - debugger: bool = false, - - compile: bool = false, - compile_to_standalone_html: bool = false, - metafile: bool = false, - /// Path to write JSON metafile (for Bun.build API) - metafile_json_path: []const u8 = "", - /// Path to write markdown metafile (for Bun.build API) - metafile_markdown_path: []const u8 = "", - - /// Set when bake.DevServer is bundling. - dev_server: ?*bun.bake.DevServer = null, - /// Set when Bake is bundling. Affects module resolution. - framework: ?*bun.bake.Framework = null, - - serve_plugins: ?[]const []const u8 = null, - bunfig_path: string = "", - - /// This is a list of packages which even when require() is used, we will - /// instead convert to ESM import statements. - /// - /// This is not normally a safe transformation. - /// - /// So we have a list of packages which we know are safe to do this with. - unwrap_commonjs_packages: []const string = &default_unwrap_commonjs_packages, - - supports_multiple_outputs: bool = true, - - /// This is set by the process environment, which is used to override the - /// JSX configuration. When this is unspecified, the tsconfig.json is used - /// to determine if a development jsx-runtime is used (by going between - /// "react-jsx" or "react-jsx-dev-runtime") - force_node_env: ForceNodeEnv = .unspecified, - - ignore_module_resolution_errors: bool = false, - - /// Package names whose barrel files should be optimized. - /// When set, barrel files from these packages will only load submodules - /// that are actually imported. Also, any file with sideEffects: false - /// in its package.json is automatically a barrel candidate. - optimize_imports: ?*const bun.StringSet = null, - - pub const ForceNodeEnv = enum { - unspecified, - development, - production, - }; - - pub fn isTest(this: *const BundleOptions) bool { - return this.rewrite_jest_for_tests; - } - - pub fn setProduction(this: *BundleOptions, value: bool) void { - if (this.force_node_env == .unspecified) { - this.production = value; - this.jsx.development = !value; - } - } - - pub const default_unwrap_commonjs_packages = [_]string{ - "react", - "react-is", - "react-dom", - "scheduler", - "react-client", - "react-server", - "react-refresh", - }; - - pub inline fn cssImportBehavior(this: *const BundleOptions) api.CssInJsBehavior { - switch (this.target) { - .browser => { - return .auto_onimportcss; - }, - else => return .facade, - } - } - - pub fn areDefinesUnset(this: *const BundleOptions) bool { - return !this.defines_loaded; - } - - pub fn loadDefines(this: *BundleOptions, allocator: std.mem.Allocator, loader_: ?*DotEnv.Loader, env: ?*const Env) !void { - if (this.defines_loaded) { - return; - } - this.define = try definesFromTransformOptions( - allocator, - this.log, - this.transform_options.define, - this.target, - loader_, - env, - node_env: { - if (loader_) |e| - if (e.map.get("BUN_ENV") orelse e.map.get("NODE_ENV")) |env_| break :node_env env_; - - if (this.isTest()) { - break :node_env "\"test\""; - } - - if (this.production) { - break :node_env "\"production\""; - } - - break :node_env "\"development\""; - }, - this.drop, - this.dead_code_elimination and this.minify_syntax, - ); - this.defines_loaded = true; - } - - pub fn deinit(this: *BundleOptions, allocator: std.mem.Allocator) void { - this.define.deinit(); - // Free bundler_feature_flags if it was allocated (not the static empty set) - if (this.bundler_feature_flags != &Runtime.Features.empty_bundler_feature_flags) { - @constCast(this.bundler_feature_flags).deinit(); - allocator.destroy(@constCast(this.bundler_feature_flags)); - } - } - - pub fn loader(this: *const BundleOptions, ext: string) Loader { - return this.loaders.get(ext) orelse .file; - } - - pub const ImportPathFormat = enum { - relative, - absolute_url, - // omit file extension - absolute_path, - package_path, - }; - - pub const Defaults = struct { - pub const ExtensionOrder = [_]string{ - ".tsx", - ".ts", - ".jsx", - ".cts", - ".cjs", - ".js", - ".mjs", - ".mts", - ".json", - }; - - pub const MainFieldExtensionOrder = [_]string{ - ".js", - ".cjs", - ".cts", - ".tsx", - ".ts", - ".jsx", - ".json", - }; - - pub const ModuleExtensionOrder = [_]string{ - ".tsx", - ".jsx", - ".mts", - ".ts", - ".mjs", - ".js", - ".cts", - ".cjs", - ".json", - }; - - pub const CSSExtensionOrder = [_]string{ - ".css", - }; - - pub const NodeModules = struct { - pub const ExtensionOrder = [_]string{ - ".jsx", - ".cjs", - ".js", - ".mjs", - ".mts", - ".tsx", - ".ts", - ".cts", - ".json", - }; - - pub const ModuleExtensionOrder = [_]string{ - ".mjs", - ".jsx", - ".mts", - ".js", - ".cjs", - ".tsx", - ".ts", - ".cts", - ".json", - }; - }; - }; - - pub fn fromApi( - allocator: std.mem.Allocator, - fs: *Fs.FileSystem, - log: *logger.Log, - transform: api.TransformOptions, - ) !BundleOptions { - var opts: BundleOptions = BundleOptions{ - .log = log, - .define = undefined, - .loaders = try loadersFromTransformOptions(allocator, transform.loaders, Target.from(transform.target)), - .output_dir = transform.output_dir orelse "out", - .target = Target.from(transform.target), - .write = transform.write orelse false, - .external = undefined, - .entry_points = transform.entry_points, - .out_extensions = undefined, - .env = Env.init(allocator), - .transform_options = transform, - .css_chunking = false, - .drop = transform.drop, - .bundler_feature_flags = Runtime.Features.initBundlerFeatureFlags(allocator, transform.feature_flags), - }; - - analytics.Features.define += @as(usize, @intFromBool(transform.define != null)); - analytics.Features.loaders += @as(usize, @intFromBool(transform.loaders != null)); - - opts.serve_plugins = transform.serve_plugins; - opts.bunfig_path = transform.bunfig_path; - - if (transform.env_files.len > 0) { - opts.env.files = transform.env_files; - } - - opts.env.disable_default_env_files = transform.disable_default_env_files; - - if (transform.origin) |origin| { - opts.origin = URL.parse(origin); - } - - if (transform.jsx) |jsx| { - opts.jsx = try JSX.Pragma.fromApi(jsx, allocator); - } - - if (transform.extension_order.len > 0) { - opts.extension_order.default.default = transform.extension_order; - } - - if (transform.target) |t| { - opts.target = Target.from(t); - opts.main_fields = Target.DefaultMainFields.get(opts.target); - } - - { - // conditions: - // 1. defaults - // 2. node-addons - // 3. user conditions - opts.conditions = try ESMConditions.init( - allocator, - opts.target.defaultConditions(), - transform.allow_addons orelse true, - transform.conditions, - ); - } - - switch (opts.target) { - .node => { - opts.import_path_format = .relative; - opts.allow_runtime = false; - }, - .bun => { - opts.import_path_format = if (opts.import_path_format == .absolute_url) .absolute_url else .absolute_path; - - opts.env.behavior = .load_all; - if (transform.extension_order.len == 0) { - // we must also support require'ing .node files - opts.extension_order.default.default = comptime Defaults.ExtensionOrder ++ &[_][]const u8{".node"}; - opts.extension_order.node_modules.default = comptime Defaults.NodeModules.ExtensionOrder ++ &[_][]const u8{".node"}; - } - }, - else => {}, - } - - if (transform.main_fields.len > 0) { - opts.main_fields = transform.main_fields; - } - - opts.external = ExternalModules.init(allocator, &fs.fs, fs.top_level_dir, transform.external, log, opts.target); - opts.out_extensions = opts.target.outExtensions(allocator); - - opts.source_map = SourceMapOption.fromApi(transform.source_map orelse .none); - - opts.packages = PackagesOption.fromApi(transform.packages orelse .bundle); - - opts.tree_shaking = opts.target.isBun() or opts.production; - opts.inlining = opts.tree_shaking; - if (opts.inlining) - opts.minify_syntax = true; - - if (opts.origin.isAbsolute()) { - opts.import_path_format = ImportPathFormat.absolute_url; - } - - if (opts.write and opts.output_dir.len > 0) { - opts.output_dir_handle = try openOutputDir(opts.output_dir); - opts.output_dir = try fs.getFdPath(.fromStdDir(opts.output_dir_handle.?)); - } - - opts.polyfill_node_globals = opts.target == .browser; - - if (transform.tsconfig_override) |tsconfig| { - opts.tsconfig_override = tsconfig; - } - - analytics.Features.macros += @as(usize, @intFromBool(opts.target == .bun_macro)); - analytics.Features.external += @as(usize, @intFromBool(transform.external.len > 0)); - return opts; - } -}; - -pub fn openOutputDir(output_dir: string) !std.fs.Dir { - return std.fs.cwd().openDir(output_dir, .{}) catch brk: { - std.fs.cwd().makeDir(output_dir) catch |err| { - Output.printErrorln("error: Unable to mkdir \"{s}\": \"{s}\"", .{ output_dir, @errorName(err) }); - Global.crash(); - }; - - const handle = std.fs.cwd().openDir(output_dir, .{}) catch |err2| { - Output.printErrorln("error: Unable to open \"{s}\": \"{s}\"", .{ output_dir, @errorName(err2) }); - Global.crash(); - }; - break :brk handle; - }; -} - -pub const TransformOptions = struct { - footer: string = "", - banner: string = "", - define: bun.StringHashMap(string), - loader: Loader = Loader.js, - resolve_dir: string = "/", - jsx: ?JSX.Pragma, - react_fast_refresh: bool = false, - inject: ?[]string = null, - origin: string = "", - preserve_symlinks: bool = false, - entry_point: Fs.File, - resolve_paths: bool = false, - tsconfig_override: ?string = null, - - target: Target = Target.browser, - main_fields: []string = Target.DefaultMainFields.get(Target.browser), - - pub fn initUncached(allocator: std.mem.Allocator, entryPointName: string, code: string) !TransformOptions { - assert(entryPointName.len > 0); - - const entryPoint = Fs.File{ - .path = Fs.Path.init(entryPointName), - .contents = code, - }; - - var cwd: string = "/"; - if (Environment.isWasi or Environment.isWindows) { - cwd = try bun.getcwdAlloc(allocator); - } - - var define = bun.StringHashMap(string).init(allocator); - try define.ensureTotalCapacity(1); - - define.putAssumeCapacity("process.env.NODE_ENV", "development"); - - var loader = Loader.file; - if (defaultLoaders.get(entryPoint.path.name.ext)) |defaultLoader| { - loader = defaultLoader; - } - assert(code.len > 0); - - return TransformOptions{ - .entry_point = entryPoint, - .define = define, - .loader = loader, - .resolve_dir = entryPoint.path.name.dir, - .main_fields = Target.DefaultMainFields.get(Target.browser), - .jsx = if (Loader.isJSX(loader)) JSX.Pragma{} else null, - }; - } -}; - -pub const OutputFile = @import("./OutputFile.zig"); - -pub const TransformResult = struct { - errors: []logger.Msg = &([_]logger.Msg{}), - warnings: []logger.Msg = &([_]logger.Msg{}), - output_files: []OutputFile = &([_]OutputFile{}), - outbase: string, - root_dir: ?std.fs.Dir = null, - pub fn init( - outbase: string, - output_files: []OutputFile, - log: *logger.Log, - allocator: std.mem.Allocator, - ) !TransformResult { - var errors = try std.array_list.Managed(logger.Msg).initCapacity(allocator, log.errors); - var warnings = try std.array_list.Managed(logger.Msg).initCapacity(allocator, log.warnings); - for (log.msgs.items) |msg| { - switch (msg.kind) { - logger.Kind.err => { - errors.append(msg) catch unreachable; - }, - logger.Kind.warn => { - warnings.append(msg) catch unreachable; - }, - else => {}, - } - } - - return TransformResult{ - .outbase = outbase, - .output_files = output_files, - .errors = try errors.toOwnedSlice(), - .warnings = try warnings.toOwnedSlice(), - }; - } -}; - -pub const Env = struct { - const Entry = struct { - key: string, - value: string, - }; - const List = std.MultiArrayList(Entry); - - behavior: api.DotEnvBehavior = api.DotEnvBehavior.disable, - prefix: string = "", - defaults: List = List{}, - allocator: std.mem.Allocator = undefined, - - /// List of explicit env files to load (e..g specified by --env-file args) - files: []const []const u8 = &[_][]u8{}, - - /// If true, disable loading of default .env files (from --no-env-file flag or bunfig) - disable_default_env_files: bool = false, - - pub fn init( - allocator: std.mem.Allocator, - ) Env { - return Env{ - .allocator = allocator, - .defaults = List{}, - .prefix = "", - .behavior = api.DotEnvBehavior.disable, - }; - } - - pub fn ensureTotalCapacity(this: *Env, capacity: u64) !void { - try this.defaults.ensureTotalCapacity(this.allocator, capacity); - } - - pub fn setDefaultsMap(this: *Env, defaults: api.StringMap) !void { - this.defaults.shrinkRetainingCapacity(0); - - if (defaults.keys.len == 0) { - return; - } - - try this.defaults.ensureTotalCapacity(this.allocator, defaults.keys.len); - - for (defaults.keys, 0..) |key, i| { - this.defaults.appendAssumeCapacity(.{ .key = key, .value = defaults.values[i] }); - } - } - - // For reading from API - pub fn setFromAPI(this: *Env, config: api.EnvConfig) !void { - this.setBehaviorFromPrefix(config.prefix orelse ""); - - if (config.defaults) |defaults| { - try this.setDefaultsMap(defaults); - } - } - - pub fn setBehaviorFromPrefix(this: *Env, prefix: string) void { - this.behavior = api.DotEnvBehavior.disable; - this.prefix = ""; - - if (strings.eqlComptime(prefix, "*")) { - this.behavior = api.DotEnvBehavior.load_all; - } else if (prefix.len > 0) { - this.behavior = api.DotEnvBehavior.prefix; - this.prefix = prefix; - } - } - - pub fn setFromLoaded(this: *Env, config: api.LoadedEnvConfig, allocator: std.mem.Allocator) !void { - this.allocator = allocator; - this.behavior = switch (config.dotenv) { - api.DotEnvBehavior.prefix => api.DotEnvBehavior.prefix, - api.DotEnvBehavior.load_all => api.DotEnvBehavior.load_all, - else => api.DotEnvBehavior.disable, - }; - - this.prefix = config.prefix; - - try this.setDefaultsMap(config.defaults); - } - - pub fn toAPI(this: *const Env) api.LoadedEnvConfig { - var slice = this.defaults.slice(); - - return api.LoadedEnvConfig{ - .dotenv = this.behavior, - .prefix = this.prefix, - .defaults = .{ .keys = slice.items(.key), .values = slice.items(.value) }, - }; - } - - // For reading from package.json - pub fn getOrPutValue(this: *Env, key: string, value: string) !void { - var slice = this.defaults.slice(); - const keys = slice.items(.key); - for (keys) |_key| { - if (strings.eql(key, _key)) { - return; - } - } - - try this.defaults.append(this.allocator, .{ .key = key, .value = value }); - } -}; - -pub const EntryPoint = struct { - path: string = "", - env: Env = Env{}, - kind: Kind = Kind.disabled, - - pub fn isEnabled(this: *const EntryPoint) bool { - return this.kind != .disabled and this.path.len > 0; - } - - pub const Kind = enum { - client, - server, - fallback, - disabled, - - pub fn toAPI(this: Kind) api.FrameworkEntryPointType { - return switch (this) { - .client => .client, - .server => .server, - .fallback => .fallback, - else => unreachable, - }; - } - }; - - pub fn toAPI(this: *const EntryPoint, allocator: std.mem.Allocator, toplevel_path: string, kind: Kind) !?api.FrameworkEntryPoint { - if (this.kind == .disabled) - return null; - - return api.FrameworkEntryPoint{ .kind = kind.toAPI(), .env = this.env.toAPI(), .path = try this.normalizedPath(allocator, toplevel_path) }; - } - - fn normalizedPath(this: *const EntryPoint, allocator: std.mem.Allocator, toplevel_path: string) !string { - bun.assert(std.fs.path.isAbsolute(this.path)); - var str = this.path; - if (strings.indexOf(str, toplevel_path)) |top| { - str = str[top + toplevel_path.len ..]; - } - - // if it *was* a node_module path, we don't do any allocation, we just keep it as a package path - if (strings.indexOf(str, "node_modules" ++ std.fs.path.sep_str)) |node_module_i| { - return str[node_module_i + "node_modules".len + 1 ..]; - // otherwise, we allocate a new string and copy the path into it with a leading "./" - - } else { - var out = try allocator.alloc(u8, str.len + 2); - out[0] = '.'; - out[1] = '/'; - bun.copy(u8, out[2..], str); - return out; - } - } - - pub fn fromLoaded( - this: *EntryPoint, - framework_entry_point: api.FrameworkEntryPoint, - allocator: std.mem.Allocator, - kind: Kind, - ) !void { - this.path = framework_entry_point.path; - this.kind = kind; - this.env.setFromLoaded(framework_entry_point.env, allocator) catch {}; - } - - pub fn fromAPI( - this: *EntryPoint, - framework_entry_point: api.FrameworkEntryPointMessage, - allocator: std.mem.Allocator, - kind: Kind, - ) !void { - this.path = framework_entry_point.path orelse ""; - this.kind = kind; - - if (this.path.len == 0) { - this.kind = .disabled; - return; - } - - if (framework_entry_point.env) |env| { - this.env.allocator = allocator; - try this.env.setFromAPI(env); - } - } -}; - -pub const RouteConfig = struct { - dir: string = "", - possible_dirs: []const string = &[_]string{}, - - // Frameworks like Next.js (and others) use a special prefix for bundled/transpiled assets - // This is combined with "origin" when printing import paths - asset_prefix_path: string = "", - - // TODO: do we need a separate list for data-only extensions? - // e.g. /foo.json just to get the data for the route, without rendering the html - // I think it's fine to hardcode as .json for now, but if I personally were writing a framework - // I would consider using a custom binary format to minimize request size - // maybe like CBOR - extensions: []const string = &[_]string{}, - routes_enabled: bool = false, - - pub fn toAPI(this: *const RouteConfig) api.LoadedRouteConfig { - return .{ - .asset_prefix = this.asset_prefix_path, - .dir = if (this.routes_enabled) this.dir else "", - .extensions = this.extensions, - .static_dir = if (this.static_dir_enabled) this.static_dir else "", - }; - } - - pub const DefaultDir = "pages"; - pub const DefaultStaticDir: string = "public"; - pub const DefaultExtensions = [_]string{ "tsx", "ts", "mjs", "jsx", "js" }; - pub inline fn zero() RouteConfig { - return RouteConfig{ - .dir = DefaultDir, - .extensions = DefaultExtensions[0..], - .static_dir = DefaultStaticDir, - .routes_enabled = false, - }; - } - - pub fn fromLoadedRoutes(loaded: api.LoadedRouteConfig) RouteConfig { - return RouteConfig{ - .extensions = loaded.extensions, - .dir = loaded.dir, - .asset_prefix_path = loaded.asset_prefix, - .static_dir = loaded.static_dir, - .routes_enabled = loaded.dir.len > 0, - .static_dir_enabled = loaded.static_dir.len > 0, - }; - } - - pub fn fromApi(router_: api.RouteConfig, allocator: std.mem.Allocator) !RouteConfig { - var router = zero(); - - const static_dir: string = std.mem.trimRight(u8, router_.static_dir orelse "", "/\\"); - const asset_prefix: string = std.mem.trimRight(u8, router_.asset_prefix orelse "", "/\\"); - - switch (router_.dir.len) { - 0 => {}, - 1 => { - router.dir = std.mem.trimRight(u8, router_.dir[0], "/\\"); - router.routes_enabled = router.dir.len > 0; - }, - else => { - router.possible_dirs = router_.dir; - for (router_.dir) |dir| { - const trimmed = std.mem.trimRight(u8, dir, "/\\"); - if (trimmed.len > 0) { - router.dir = trimmed; - } - } - - router.routes_enabled = router.dir.len > 0; - }, - } - - if (static_dir.len > 0) { - router.static_dir = static_dir; - } - - if (asset_prefix.len > 0) { - router.asset_prefix_path = asset_prefix; - } - - if (router_.extensions.len > 0) { - var count: usize = 0; - for (router_.extensions) |_ext| { - const ext = std.mem.trimLeft(u8, _ext, "."); - - if (ext.len == 0) { - continue; - } - - count += 1; - } - - const extensions = try allocator.alloc(string, count); - var remainder = extensions; - - for (router_.extensions) |_ext| { - const ext = std.mem.trimLeft(u8, _ext, "."); - - if (ext.len == 0) { - continue; - } - - remainder[0] = ext; - remainder = remainder[1..]; - } - - router.extensions = extensions; - } - - return router; - } -}; - -pub const GlobalCache = @import("../resolver/resolver.zig").GlobalCache; - -pub const PathTemplate = struct { - data: string = "", - placeholder: Placeholder = .{}, - - pub fn needs(this: *const PathTemplate, comptime field: std.meta.FieldEnum(Placeholder)) bool { - return strings.containsComptime(this.data, "[" ++ @tagName(field) ++ "]"); - } - - inline fn writeReplacingSlashesOnWindows(w: anytype, slice: []const u8) !void { - if (Environment.isWindows) { - var remain = slice; - while (strings.indexOfChar(remain, '/')) |i| { - try w.writeAll(remain[0..i]); - try w.writeByte('\\'); - remain = remain[i + 1 ..]; - } - try w.writeAll(remain); - } else { - try w.writeAll(slice); - } - } - - pub fn format(self: PathTemplate, writer: *std.Io.Writer) !void { - var remain = self.data; - while (strings.indexOfChar(remain, '[')) |j| { - try writeReplacingSlashesOnWindows(writer, remain[0..j]); - remain = remain[j + 1 ..]; - if (remain.len == 0) { - // TODO: throw error - try writer.writeAll("["); - break; - } - - var count: isize = 1; - var end_len: usize = remain.len; - for (remain) |*c| { - count += switch (c.*) { - '[' => 1, - ']' => -1, - else => 0, - }; - - if (count == 0) { - end_len = @intFromPtr(c) - @intFromPtr(remain.ptr); - bun.assert(end_len <= remain.len); - break; - } - } - - const placeholder = remain[0..end_len]; - - const field = PathTemplate.Placeholder.map.get(placeholder) orelse { - try writeReplacingSlashesOnWindows(writer, placeholder); - remain = remain[end_len..]; - continue; - }; - - switch (field) { - .dir => try writeReplacingSlashesOnWindows(writer, if (self.placeholder.dir.len > 0) self.placeholder.dir else "."), - .name => try writeReplacingSlashesOnWindows(writer, self.placeholder.name), - .ext => try writeReplacingSlashesOnWindows(writer, self.placeholder.ext), - .hash => { - if (self.placeholder.hash) |hash| { - try writer.print("{f}", .{bun.fmt.truncatedHash32(hash)}); - } - }, - .target => try writeReplacingSlashesOnWindows(writer, self.placeholder.target), - } - remain = remain[end_len + 1 ..]; - } - - try writeReplacingSlashesOnWindows(writer, remain); - } - - pub const Placeholder = struct { - dir: []const u8 = "", - name: []const u8 = "", - ext: []const u8 = "", - hash: ?u64 = null, - target: []const u8 = "", - - pub const map = bun.ComptimeStringMap(std.meta.FieldEnum(Placeholder), .{ - .{ "dir", .dir }, - .{ "name", .name }, - .{ "ext", .ext }, - .{ "hash", .hash }, - .{ "target", .target }, - }); - }; - - pub const chunk = PathTemplate{ - .data = "./chunk-[hash].[ext]", - .placeholder = .{ - .name = "chunk", - .ext = "js", - .dir = "", - }, - }; - - pub const chunkWithTarget = PathTemplate{ - .data = "[dir]/[target]/chunk-[hash].[ext]", - .placeholder = .{ - .name = "chunk", - .ext = "js", - .dir = "", - }, - }; - - pub const file = PathTemplate{ - .data = "[dir]/[name].[ext]", - .placeholder = .{}, - }; - - pub const fileWithTarget = PathTemplate{ - .data = "[dir]/[target]/[name].[ext]", - .placeholder = .{}, - }; - - pub const asset = PathTemplate{ - .data = "./[name]-[hash].[ext]", - .placeholder = .{}, - }; - - pub const assetWithTarget = PathTemplate{ - .data = "[dir]/[target]/[name]-[hash].[ext]", - .placeholder = .{}, - }; -}; - -const string = []const u8; - -const DotEnv = @import("../dotenv/env_loader.zig"); -const Fs = @import("../resolver/fs.zig"); -const resolver = @import("../resolver/resolver.zig"); -const Runtime = @import("../js_parser/runtime.zig").Runtime; -const URL = @import("../url/url.zig").URL; - -const MacroRemap = @import("../resolver/package_json.zig").MacroMap; -const PackageJSON = @import("../resolver/package_json.zig").PackageJSON; -const ConditionsMap = @import("../resolver/package_json.zig").ESModule.ConditionsMap; - -const bun = @import("bun"); -const Environment = bun.Environment; -const Global = bun.Global; -const Output = bun.Output; -const analytics = bun.analytics; -const assert = bun.assert; -const jsc = bun.jsc; -const logger = bun.logger; -const strings = bun.strings; -const api = bun.schema.api; diff --git a/src/bundler/transpiler.zig b/src/bundler/transpiler.zig deleted file mode 100644 index 4368fd159ba8..000000000000 --- a/src/bundler/transpiler.zig +++ /dev/null @@ -1,1461 +0,0 @@ -pub const options = @import("./options.zig"); - -/// Opaque carrier for the macro evaluation context. Aliases through -/// `bundler_jsc/` so this file has no direct JSC type reference. -pub const MacroJSCtx = @import("../bundler_jsc/PluginRunner.zig").MacroJSCtx; - -pub const EntryPoints = @import("./entry_points.zig"); - -pub const ParseResult = struct { - source: logger.Source, - loader: options.Loader, - ast: js_ast.Ast, - already_bundled: AlreadyBundled = .none, - input_fd: ?FD = null, - empty: bool = false, - pending_imports: _resolver.PendingResolution.List = .{}, - - runtime_transpiler_cache: ?*bun.jsc.RuntimeTranspilerCache = null, - - pub const AlreadyBundled = union(enum) { - none: void, - source_code: void, - source_code_cjs: void, - bytecode: []u8, - bytecode_cjs: []u8, - - pub fn bytecodeSlice(this: AlreadyBundled) []u8 { - return switch (this) { - inline .bytecode, .bytecode_cjs => |slice| slice, - else => &.{}, - }; - } - - pub fn isBytecode(this: AlreadyBundled) bool { - return this == .bytecode or this == .bytecode_cjs; - } - - pub fn isCommonJS(this: AlreadyBundled) bool { - return this == .source_code_cjs or this == .bytecode_cjs; - } - }; - - pub fn isPendingImport(this: *const ParseResult, id: u32) bool { - const import_record_ids = this.pending_imports.items(.import_record_id); - - return std.mem.indexOfScalar(u32, import_record_ids, id) != null; - } - - /// **DO NOT CALL THIS UNDER NORMAL CIRCUMSTANCES** - /// Normally, we allocate each AST in an arena and free all at once - /// So this function only should be used when we globally allocate an AST - pub fn deinit(this: *ParseResult) void { - _resolver.PendingResolution.deinitListItems(this.pending_imports, bun.default_allocator); - this.pending_imports.deinit(bun.default_allocator); - this.ast.deinit(); - bun.default_allocator.free(@constCast(this.source.contents)); - } -}; - -pub const PluginRunner = @import("../bundler_jsc/PluginRunner.zig").PluginRunner; - -/// This structure was the JavaScript transpiler before bundle_v2 was written. It now -/// acts mostly as a configuration object, but it also contains stateful logic around -/// logging errors (.log) and module resolution (.resolve_queue) -/// -/// This object is not exclusive to bundle_v2/Bun.build, one of these is stored -/// on every VM so that the options can be used for transpilation. -pub const Transpiler = struct { - options: options.BundleOptions, - log: *logger.Log, - allocator: std.mem.Allocator, - result: options.TransformResult, - resolver: Resolver, - fs: *Fs.FileSystem, - output_files: std.array_list.Managed(options.OutputFile), - resolve_results: *ResolveResults, - resolve_queue: ResolveQueue, - elapsed: u64 = 0, - needs_runtime: bool = false, - router: ?Router = null, - source_map: options.SourceMapOption = .none, - - linker: Linker, - timer: SystemTimer, - env: *DotEnv.Loader, - - macro_context: ?js_ast.Macro.MacroContext = null, - - pub const isCacheEnabled = false; - - pub inline fn getPackageManager(this: *Transpiler) *PackageManager { - return this.resolver.getPackageManager(); - } - - pub fn setLog(this: *Transpiler, log: *logger.Log) void { - this.log = log; - this.linker.log = log; - this.resolver.log = log; - } - - // TODO: remove this method. it does not make sense - pub fn setAllocator(this: *Transpiler, allocator: std.mem.Allocator) void { - this.allocator = allocator; - this.linker.allocator = allocator; - this.resolver.allocator = allocator; - } - - fn _resolveEntryPoint(transpiler: *Transpiler, entry_point: string) !_resolver.Result { - return transpiler.resolver.resolveWithFramework(transpiler.fs.top_level_dir, entry_point, .entry_point_build) catch |err| { - // Relative entry points that were not resolved to a node_modules package are - // interpreted as relative to the current working directory. - if (!std.fs.path.isAbsolute(entry_point) and - !(strings.hasPrefix(entry_point, "./") or strings.hasPrefix(entry_point, ".\\"))) - { - brk: { - return transpiler.resolver.resolve( - transpiler.fs.top_level_dir, - try strings.append(transpiler.allocator, "./", entry_point), - .entry_point_build, - ) catch { - // return the original error - break :brk; - }; - } - } - return err; - }; - } - - pub fn resolveEntryPoint(transpiler: *Transpiler, entry_point: string) !_resolver.Result { - return _resolveEntryPoint(transpiler, entry_point) catch |err| { - var cache_bust_buf: bun.PathBuffer = undefined; - - // Bust directory cache and try again - const buster_name = name: { - if (std.fs.path.isAbsolute(entry_point)) { - if (std.fs.path.dirname(entry_point)) |dir| { - // Normalized with trailing slash - break :name bun.strings.normalizeSlashesOnly(&cache_bust_buf, dir, std.fs.path.sep); - } - } - - var parts = [_]string{ - entry_point, - bun.pathLiteral(".."), - }; - - break :name bun.path.joinAbsStringBufZ( - transpiler.fs.top_level_dir, - &cache_bust_buf, - &parts, - .auto, - ); - }; - - // Only re-query if we previously had something cached. - if (transpiler.resolver.bustDirCache(bun.strings.withoutTrailingSlashWindowsPath(buster_name))) { - if (_resolveEntryPoint(transpiler, entry_point)) |result| - return result - else |_| { - // ignore this error, we will print the original error - } - } - - bun.handleOom(transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} resolving \"{s}\" (entry point)", .{ @errorName(err), entry_point })); - return err; - }; - } - - pub fn init( - allocator: std.mem.Allocator, - log: *logger.Log, - opts: api.TransformOptions, - env_loader_: ?*DotEnv.Loader, - ) !Transpiler { - js_ast.Expr.Data.Store.create(); - js_ast.Stmt.Data.Store.create(); - - const fs = try Fs.FileSystem.init(opts.absolute_working_dir); - const bundle_options = try options.BundleOptions.fromApi( - allocator, - fs, - log, - opts, - ); - - var env_loader: *DotEnv.Loader = env_loader_ orelse DotEnv.instance orelse brk: { - const map = try allocator.create(DotEnv.Map); - map.* = DotEnv.Map.init(allocator); - - const loader = try allocator.create(DotEnv.Loader); - loader.* = DotEnv.Loader.init(map, allocator); - break :brk loader; - }; - - if (DotEnv.instance == null) { - DotEnv.instance = env_loader; - } - - // hide elapsed time when loglevel is warn or error - env_loader.quiet = !log.level.atLeast(.info); - - // var pool = try allocator.create(ThreadPool); - // try pool.init(ThreadPool.InitConfig{ - // .allocator = allocator, - // }); - const resolve_results = try allocator.create(ResolveResults); - resolve_results.* = ResolveResults.init(allocator); - return Transpiler{ - .options = bundle_options, - .fs = fs, - .allocator = allocator, - .timer = SystemTimer.start() catch @panic("Timer fail"), - .resolver = Resolver.init1(allocator, log, fs, bundle_options), - .log = log, - // .thread_pool = pool, - .linker = undefined, - .result = options.TransformResult{ .outbase = bundle_options.output_dir }, - .resolve_results = resolve_results, - .resolve_queue = ResolveQueue.init(allocator), - .output_files = std.array_list.Managed(options.OutputFile).init(allocator), - .env = env_loader, - }; - } - - pub fn deinit(this: *Transpiler) void { - this.options.deinit(this.allocator); - this.log.deinit(); - this.resolver.deinit(); - this.fs.deinit(); - } - - pub fn configureLinkerWithAutoJSX(transpiler: *Transpiler, auto_jsx: bool) void { - transpiler.linker = Linker.init( - transpiler.allocator, - transpiler.log, - &transpiler.resolve_queue, - &transpiler.options, - &transpiler.resolver, - transpiler.resolve_results, - transpiler.fs, - ); - - if (auto_jsx) { - // Most of the time, this will already be cached - if (transpiler.resolver.readDirInfo(transpiler.fs.top_level_dir) catch null) |root_dir| { - if (root_dir.tsconfig_json) |tsconfig| { - // If we don't explicitly pass JSX, try to get it from the root tsconfig - if (transpiler.options.transform_options.jsx == null) { - transpiler.options.jsx = tsconfig.jsx; - } - transpiler.options.emit_decorator_metadata = tsconfig.emit_decorator_metadata; - transpiler.options.experimental_decorators = tsconfig.experimental_decorators; - } - } - } - } - - pub fn configureLinker(transpiler: *Transpiler) void { - transpiler.configureLinkerWithAutoJSX(true); - } - - pub fn runEnvLoader(this: *Transpiler, skip_default_env: bool) !void { - switch (this.options.env.behavior) { - .prefix, .load_all, .load_all_without_inlining => { - // Process always has highest priority. Load process env vars - // unconditionally before attempting directory traversal, so - // that inherited environment variables are always available - // even when a parent directory is not readable. - const was_production = this.options.production; - try this.env.loadProcess(); - const has_production_env = this.env.isProduction(); - if (!was_production and has_production_env) { - this.options.setProduction(true); - this.resolver.opts.setProduction(true); - } - - // Load the project root for .env file discovery. If the cwd - // (or a parent) is unreadable, readDirInfo may return null; - // bail out of .env file loading in that case, but process - // env vars were already loaded above. - const dir_info = this.resolver.readDirInfo(this.fs.top_level_dir) catch return orelse return; - - if (dir_info.tsconfig_json) |tsconfig| { - this.options.jsx = tsconfig.mergeJSX(this.options.jsx); - } - - const dir = dir_info.getEntries(this.resolver.generation) orelse return; - - if (this.options.isTest() or this.env.isTest()) { - try this.env.load(dir, this.options.env.files, .@"test", skip_default_env); - } else if (this.options.production) { - try this.env.load(dir, this.options.env.files, .production, skip_default_env); - } else { - try this.env.load(dir, this.options.env.files, .development, skip_default_env); - } - }, - .disable => { - try this.env.loadProcess(); - if (this.env.isProduction()) { - this.options.setProduction(true); - this.resolver.opts.setProduction(true); - } - }, - else => {}, - } - - if (strings.eqlComptime(this.env.get("BUN_DISABLE_TRANSPILER") orelse "0", "1")) { - this.options.disable_transpilation = true; - } - } - - // This must be run after a framework is configured, if a framework is enabled - pub fn configureDefines(this: *Transpiler) !void { - if (this.options.defines_loaded) { - return; - } - - if (this.options.target == .bun_macro) { - this.options.env.behavior = .prefix; - this.options.env.prefix = "BUN_"; - } - - try this.runEnvLoader(this.options.env.disable_default_env_files); - - var is_production = this.env.isProduction(); - - js_ast.Expr.Data.Store.create(); - js_ast.Stmt.Data.Store.create(); - - defer js_ast.Expr.Data.Store.reset(); - defer js_ast.Stmt.Data.Store.reset(); - - try this.options.loadDefines(this.allocator, this.env, &this.options.env); - - var is_development = false; - if (this.options.define.dots.get("NODE_ENV")) |NODE_ENV| { - if (NODE_ENV.len > 0 and NODE_ENV[0].data.value == .e_string) { - if (NODE_ENV[0].data.value.e_string.eqlComptime("production")) { - is_production = true; - } else if (NODE_ENV[0].data.value.e_string.eqlComptime("development")) { - is_development = true; - } - } - } - - if (is_development) { - this.options.setProduction(false); - this.resolver.opts.setProduction(false); - this.options.force_node_env = .development; - this.resolver.opts.force_node_env = .development; - } else if (is_production) { - this.options.setProduction(true); - this.resolver.opts.setProduction(true); - } - } - - pub fn resetStore(_: *const Transpiler) void { - js_ast.Expr.Data.Store.reset(); - js_ast.Stmt.Data.Store.reset(); - } - - pub noinline fn dumpEnvironmentVariables(transpiler: *const Transpiler) void { - @branchHint(.cold); - const opts = std.json.Stringify.Options{ - .whitespace = .indent_2, - }; - Output.flush(); - var w: std.json.Stringify = .{ .writer = Output.writer(), .options = opts }; - w.write(transpiler.env.map.*) catch unreachable; - Output.flush(); - } - - pub const BuildResolveResultPair = struct { - written: usize, - input_fd: ?FD, - empty: bool = false, - }; - - fn buildWithResolveResultEager( - transpiler: *Transpiler, - resolve_result: _resolver.Result, - comptime import_path_format: options.BundleOptions.ImportPathFormat, - comptime Outstream: type, - outstream: Outstream, - client_entry_point_: ?*EntryPoints.ClientEntryPoint, - ) !?options.OutputFile { - _ = outstream; - - if (resolve_result.flags.is_external) { - return null; - } - - var file_path = (resolve_result.pathConst() orelse return null).*; - - // Step 1. Parse & scan - const loader = transpiler.options.loader(file_path.name.ext); - - if (client_entry_point_) |client_entry_point| { - file_path = client_entry_point.source.path; - } - - file_path.pretty = Linker.relative_paths_list.append(string, transpiler.fs.relativeTo(file_path.text)) catch unreachable; - - var output_file = options.OutputFile{ - .src_path = file_path, - .loader = loader, - .value = undefined, - .side = null, - .entry_point_index = null, - .output_kind = .chunk, - }; - - switch (loader) { - .jsx, .tsx, .js, .ts, .json, .jsonc, .toml, .yaml, .json5, .text, .md => { - var result = transpiler.parse( - ParseOptions{ - .allocator = transpiler.allocator, - .path = file_path, - .loader = loader, - .dirname_fd = resolve_result.dirname_fd, - .file_descriptor = null, - .file_hash = null, - .macro_remappings = transpiler.options.macro_remap, - .jsx = resolve_result.jsx, - .emit_decorator_metadata = resolve_result.flags.emit_decorator_metadata, - .experimental_decorators = resolve_result.flags.experimental_decorators, - }, - client_entry_point_, - ) orelse { - return null; - }; - if (!transpiler.options.transform_only) { - if (!transpiler.options.target.isBun()) - try transpiler.linker.link( - file_path, - &result, - transpiler.options.origin, - import_path_format, - false, - false, - ) - else - try transpiler.linker.link( - file_path, - &result, - transpiler.options.origin, - import_path_format, - false, - true, - ); - } - - const buffer_writer = js_printer.BufferWriter.init(transpiler.allocator); - var writer = js_printer.BufferPrinter.init(buffer_writer); - - output_file.size = switch (transpiler.options.target) { - .browser, .node => try transpiler.print( - result, - *js_printer.BufferPrinter, - &writer, - .esm, - ), - .bun, .bun_macro, .bake_server_components_ssr => try transpiler.print( - result, - *js_printer.BufferPrinter, - &writer, - .esm_ascii, - ), - }; - output_file.value = .{ - .buffer = .{ - .allocator = transpiler.allocator, - .bytes = writer.ctx.written, - }, - }; - }, - .dataurl, .base64 => { - Output.panic("TODO: dataurl, base64", .{}); // TODO - }, - .css => { - const alloc = transpiler.allocator; - - const entry = transpiler.resolver.caches.fs.readFileWithAllocator( - transpiler.allocator, - transpiler.fs, - file_path.text, - resolve_result.dirname_fd, - false, - null, - ) catch |err| { - transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} reading \"{s}\"", .{ @errorName(err), file_path.pretty }) catch {}; - return null; - }; - var opts = bun.css.ParserOptions.default(alloc, transpiler.log); - const css_module_suffix = ".module.css"; - const enable_css_modules = file_path.text.len > css_module_suffix.len and - strings.eqlComptime(file_path.text[file_path.text.len - css_module_suffix.len ..], css_module_suffix); - if (enable_css_modules) { - opts.filename = bun.path.basename(file_path.text); - opts.css_modules = bun.css.CssModuleConfig{}; - } - var sheet, var extra = switch (bun.css.StyleSheet(bun.css.DefaultAtRule).parse( - alloc, - entry.contents, - opts, - null, - // TODO: DO WE EVEN HAVE SOURCE INDEX IN THIS TRANSPILER.ZIG file?? - bun.bundle_v2.Index.invalid, - )) { - .result => |v| v, - .err => |e| { - transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{f} parsing", .{e}) catch unreachable; - return null; - }, - }; - if (sheet.minify(alloc, bun.css.MinifyOptions.default(), &extra).asErr()) |e| { - bun.handleOom(transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{f} while minifying", .{e.kind})); - return null; - } - const symbols = bun.ast.Symbol.Map{}; - const result = switch (sheet.toCss( - alloc, - bun.css.PrinterOptions{ - .targets = bun.css.Targets.forBundlerTarget(transpiler.options.target), - .minify = transpiler.options.minify_whitespace, - }, - null, - null, - &symbols, - )) { - .result => |v| v, - .err => |e| { - bun.handleOom(transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{f} while printing", .{e})); - return null; - }, - }; - output_file.value = .{ .buffer = .{ .allocator = alloc, .bytes = result.code } }; - }, - - .html, .bunsh, .sqlite_embedded, .sqlite, .wasm, .file, .napi => { - const hashed_name = try transpiler.linker.getHashedFilename(file_path, null); - var pathname = try transpiler.allocator.alloc(u8, hashed_name.len + file_path.name.ext.len); - bun.copy(u8, pathname, hashed_name); - bun.copy(u8, pathname[hashed_name.len..], file_path.name.ext); - - output_file.value = .{ - .copy = options.OutputFile.FileOperation{ - .pathname = pathname, - .dir = if (transpiler.options.output_dir_handle) |output_handle| - .fromStdDir(output_handle) - else - .invalid, - .is_outdir = true, - }, - }; - }, - } - - return output_file; - } - - fn printWithSourceMapMaybe( - transpiler: *Transpiler, - ast: js_ast.Ast, - source: *const logger.Source, - comptime Writer: type, - writer: Writer, - comptime format: js_printer.Format, - comptime enable_source_map: bool, - source_map_context: ?js_printer.SourceMapHandler, - runtime_transpiler_cache: ?*bun.jsc.RuntimeTranspilerCache, - module_info: ?*analyze_transpiled_module.ModuleInfo, - ) !usize { - const tracer = if (enable_source_map) - bun.perf.trace("JSPrinter.printWithSourceMap") - else - bun.perf.trace("JSPrinter.print"); - defer tracer.end(); - - const symbols = js_ast.Symbol.NestedList.fromBorrowedSliceDangerous(&.{ast.symbols}); - - return switch (format) { - .cjs => try js_printer.printCommonJS( - Writer, - writer, - ast, - js_ast.Symbol.Map.initList(symbols), - source, - false, - .{ - .bundling = false, - .runtime_imports = ast.runtime_imports, - .require_ref = ast.require_ref, - .css_import_behavior = transpiler.options.cssImportBehavior(), - .source_map_handler = source_map_context, - .minify_whitespace = transpiler.options.minify_whitespace, - .minify_syntax = transpiler.options.minify_syntax, - .minify_identifiers = transpiler.options.minify_identifiers, - .transform_only = transpiler.options.transform_only, - .runtime_transpiler_cache = runtime_transpiler_cache, - .print_dce_annotations = transpiler.options.emit_dce_annotations, - .hmr_ref = ast.wrapper_ref, - .mangled_props = null, - }, - enable_source_map, - ), - - .esm => try js_printer.printAst( - Writer, - writer, - ast, - js_ast.Symbol.Map.initList(symbols), - source, - false, - .{ - .bundling = false, - .runtime_imports = ast.runtime_imports, - .require_ref = ast.require_ref, - .source_map_handler = source_map_context, - .css_import_behavior = transpiler.options.cssImportBehavior(), - .minify_whitespace = transpiler.options.minify_whitespace, - .minify_syntax = transpiler.options.minify_syntax, - .minify_identifiers = transpiler.options.minify_identifiers, - .transform_only = transpiler.options.transform_only, - .import_meta_ref = ast.import_meta_ref, - .runtime_transpiler_cache = runtime_transpiler_cache, - .print_dce_annotations = transpiler.options.emit_dce_annotations, - .hmr_ref = ast.wrapper_ref, - .mangled_props = null, - }, - enable_source_map, - ), - .esm_ascii => switch (transpiler.options.target.isBun()) { - inline else => |is_bun| try js_printer.printAst( - Writer, - writer, - ast, - js_ast.Symbol.Map.initList(symbols), - source, - is_bun, - .{ - .bundling = false, - .runtime_imports = ast.runtime_imports, - .require_ref = ast.require_ref, - .css_import_behavior = transpiler.options.cssImportBehavior(), - .source_map_handler = source_map_context, - .minify_whitespace = transpiler.options.minify_whitespace, - .minify_syntax = transpiler.options.minify_syntax, - .minify_identifiers = transpiler.options.minify_identifiers, - .transform_only = transpiler.options.transform_only, - .module_type = if (is_bun and transpiler.options.transform_only) - // this is for when using `bun build --no-bundle` - // it should copy what was passed for the cli - transpiler.options.output_format - else if (ast.exports_kind == .cjs) - .cjs - else - .esm, - .inline_require_and_import_errors = false, - .import_meta_ref = ast.import_meta_ref, - .runtime_transpiler_cache = runtime_transpiler_cache, - .module_info = module_info, - .target = transpiler.options.target, - .print_dce_annotations = transpiler.options.emit_dce_annotations, - .hmr_ref = ast.wrapper_ref, - .mangled_props = null, - }, - enable_source_map, - ), - }, - else => unreachable, - }; - } - - pub fn print( - transpiler: *Transpiler, - result: ParseResult, - comptime Writer: type, - writer: Writer, - comptime format: js_printer.Format, - ) !usize { - return transpiler.printWithSourceMapMaybe( - result.ast, - &result.source, - Writer, - writer, - format, - false, - null, - null, - null, - ); - } - - pub fn printWithSourceMap( - transpiler: *Transpiler, - result: ParseResult, - comptime Writer: type, - writer: Writer, - comptime format: js_printer.Format, - handler: js_printer.SourceMapHandler, - module_info: ?*analyze_transpiled_module.ModuleInfo, - ) !usize { - if (bun.feature_flag.BUN_FEATURE_FLAG_DISABLE_SOURCE_MAPS.get()) { - return transpiler.printWithSourceMapMaybe( - result.ast, - &result.source, - Writer, - writer, - format, - false, - handler, - result.runtime_transpiler_cache, - module_info, - ); - } - return transpiler.printWithSourceMapMaybe( - result.ast, - &result.source, - Writer, - writer, - format, - true, - handler, - result.runtime_transpiler_cache, - module_info, - ); - } - - pub const ParseOptions = struct { - allocator: std.mem.Allocator, - dirname_fd: FD, - file_descriptor: ?FD = null, - file_hash: ?u32 = null, - - /// On exception, we might still want to watch the file. - file_fd_ptr: ?*FD = null, - - path: Fs.Path, - loader: options.Loader, - jsx: options.JSX.Pragma, - macro_remappings: MacroRemap, - macro_js_ctx: MacroJSCtx = default_macro_js_value, - virtual_source: ?*const logger.Source = null, - replace_exports: runtime.Runtime.Features.ReplaceableExport.Map = .{}, - inject_jest_globals: bool = false, - set_breakpoint_on_first_line: bool = false, - emit_decorator_metadata: bool = false, - experimental_decorators: bool = false, - remove_cjs_module_wrapper: bool = false, - - dont_bundle_twice: bool = false, - allow_commonjs: bool = false, - /// `"type"` from `package.json`. Used to make sure the parser defaults - /// to CommonJS or ESM based on what the package.json says, when it - /// doesn't otherwise know from reading the source code. - /// - /// See: https://nodejs.org/api/packages.html#type - module_type: options.ModuleType = .unknown, - - runtime_transpiler_cache: ?*bun.jsc.RuntimeTranspilerCache = null, - - keep_json_and_toml_as_one_statement: bool = false, - allow_bytecode_cache: bool = false, - }; - - pub fn parse( - transpiler: *Transpiler, - this_parse: ParseOptions, - client_entry_point_: anytype, - ) ?ParseResult { - return parseMaybeReturnFileOnly(transpiler, this_parse, client_entry_point_, false); - } - - pub fn parseMaybeReturnFileOnly( - transpiler: *Transpiler, - this_parse: ParseOptions, - client_entry_point_: anytype, - comptime return_file_only: bool, - ) ?ParseResult { - return parseMaybeReturnFileOnlyAllowSharedBuffer( - transpiler, - this_parse, - client_entry_point_, - return_file_only, - false, - ); - } - - pub fn parseMaybeReturnFileOnlyAllowSharedBuffer( - transpiler: *Transpiler, - this_parse: ParseOptions, - client_entry_point_: anytype, - comptime return_file_only: bool, - comptime use_shared_buffer: bool, - ) ?ParseResult { - var allocator = this_parse.allocator; - const dirname_fd = this_parse.dirname_fd; - const file_descriptor = this_parse.file_descriptor; - const file_hash = this_parse.file_hash; - const path = this_parse.path; - const loader = this_parse.loader; - - var input_fd: ?FD = null; - - const source: *const logger.Source = &brk: { - if (this_parse.virtual_source) |virtual_source| { - break :brk virtual_source.*; - } - - if (client_entry_point_) |client_entry_point| { - if (@hasField(std.meta.Child(@TypeOf(client_entry_point)), "source")) { - break :brk client_entry_point.source; - } - } - - if (strings.eqlComptime(path.namespace, "node")) { - if (NodeFallbackModules.contentsFromPath(path.text)) |code| { - break :brk logger.Source.initPathString(path.text, code); - } - - break :brk logger.Source.initPathString(path.text, ""); - } - - if (strings.startsWith(path.text, "data:")) { - const data_url = DataURL.parseWithoutCheck(path.text) catch |err| { - transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} parsing data url \"{s}\"", .{ @errorName(err), path.text }) catch {}; - return null; - }; - const body = data_url.decodeData(this_parse.allocator) catch |err| { - transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} decoding data \"{s}\"", .{ @errorName(err), path.text }) catch {}; - return null; - }; - break :brk logger.Source.initPathString(path.text, body); - } - - const entry = transpiler.resolver.caches.fs.readFileWithAllocator( - if (use_shared_buffer) bun.default_allocator else this_parse.allocator, - transpiler.fs, - path.text, - dirname_fd, - use_shared_buffer, - file_descriptor, - ) catch |err| { - transpiler.log.addErrorFmt(null, logger.Loc.Empty, transpiler.allocator, "{s} reading \"{s}\"", .{ @errorName(err), path.text }) catch {}; - return null; - }; - input_fd = entry.fd; - if (this_parse.file_fd_ptr) |file_fd_ptr| { - file_fd_ptr.* = entry.fd; - } - break :brk logger.Source.initRecycledFile(.{ .path = path, .contents = entry.contents }, transpiler.allocator) catch return null; - }; - - if (comptime return_file_only) { - return ParseResult{ .source = source.*, .input_fd = input_fd, .loader = loader, .empty = true, .ast = js_ast.Ast.empty }; - } - - if (source.contents.len == 0 or (source.contents.len < 33 and std.mem.trim(u8, source.contents, "\n\r ").len == 0)) { - if (!loader.handlesEmptyFile()) { - return ParseResult{ .source = source.*, .input_fd = input_fd, .loader = loader, .empty = true, .ast = js_ast.Ast.empty }; - } - } - - switch (loader) { - .js, - .jsx, - .ts, - .tsx, - => { - // wasm magic number - if (source.isWebAssembly()) { - return ParseResult{ - .source = source.*, - .input_fd = input_fd, - .loader = .wasm, - .empty = true, - .ast = js_ast.Ast.empty, - }; - } - - const target = transpiler.options.target; - - var jsx = this_parse.jsx; - jsx.parse = loader.isJSX(); - - var opts = js_parser.Parser.Options.init(jsx, loader); - - opts.features.emit_decorator_metadata = this_parse.emit_decorator_metadata; - // emitDecoratorMetadata implies legacy/experimental decorators, as it only - // makes sense with TypeScript's legacy decorator system (reflect-metadata). - // TC39 standard decorators have their own metadata mechanism. - opts.features.standard_decorators = !loader.isTypeScript() or !(this_parse.experimental_decorators or this_parse.emit_decorator_metadata); - opts.features.allow_runtime = transpiler.options.allow_runtime; - opts.features.set_breakpoint_on_first_line = this_parse.set_breakpoint_on_first_line; - opts.features.trim_unused_imports = transpiler.options.trim_unused_imports orelse loader.isTypeScript(); - opts.features.no_macros = transpiler.options.no_macros; - opts.features.runtime_transpiler_cache = this_parse.runtime_transpiler_cache; - opts.transform_only = transpiler.options.transform_only; - - opts.ignore_dce_annotations = transpiler.options.ignore_dce_annotations; - - // @bun annotation - opts.features.dont_bundle_twice = this_parse.dont_bundle_twice; - - opts.features.commonjs_at_runtime = this_parse.allow_commonjs; - opts.module_type = this_parse.module_type; - - opts.tree_shaking = transpiler.options.tree_shaking; - opts.features.inlining = transpiler.options.inlining; - - opts.filepath_hash_for_hmr = file_hash orelse 0; - opts.features.auto_import_jsx = transpiler.options.auto_import_jsx; - opts.warn_about_unbundled_modules = !target.isBun(); - // JavaScriptCore implements `using` / `await using` natively, so - // when targeting Bun there is no need to lower them. - opts.features.lower_using = !target.isBun(); - - opts.features.inject_jest_globals = this_parse.inject_jest_globals; - opts.features.minify_syntax = transpiler.options.minify_syntax; - opts.features.minify_identifiers = transpiler.options.minify_identifiers; - opts.features.dead_code_elimination = transpiler.options.dead_code_elimination; - opts.features.remove_cjs_module_wrapper = this_parse.remove_cjs_module_wrapper; - opts.features.bundler_feature_flags = transpiler.options.bundler_feature_flags; - opts.features.repl_mode = transpiler.options.repl_mode; - opts.repl_mode = transpiler.options.repl_mode; - - if (transpiler.macro_context == null) { - transpiler.macro_context = js_ast.Macro.MacroContext.init(transpiler); - } - - // we'll just always enable top-level await - // this is incorrect for Node.js files which are CommonJS modules - opts.features.top_level_await = true; - - opts.macro_context = &transpiler.macro_context.?; - if (target != .bun_macro) { - opts.macro_context.javascript_object = this_parse.macro_js_ctx; - } - - opts.features.is_macro_runtime = target == .bun_macro; - opts.features.replace_exports = this_parse.replace_exports; - - return switch ((transpiler.resolver.caches.js.parse( - allocator, - opts, - transpiler.options.define, - transpiler.log, - source, - ) catch null) orelse return null) { - .ast => |value| .{ - .ast = value, - .source = source.*, - .loader = loader, - .input_fd = input_fd, - .runtime_transpiler_cache = this_parse.runtime_transpiler_cache, - }, - .cached => .{ - .ast = undefined, - .runtime_transpiler_cache = this_parse.runtime_transpiler_cache, - .source = source.*, - .loader = loader, - .input_fd = input_fd, - }, - .already_bundled => |already_bundled| .{ - .ast = undefined, - .already_bundled = switch (already_bundled) { - .bun => .source_code, - .bun_cjs => .source_code_cjs, - .bytecode_cjs, .bytecode => brk: { - const default_value: ParseResult.AlreadyBundled = if (already_bundled == .bytecode_cjs) .source_code_cjs else .source_code; - if (this_parse.virtual_source == null and this_parse.allow_bytecode_cache) { - var path_buf2: bun.PathBuffer = undefined; - @memcpy(path_buf2[0..path.text.len], path.text); - path_buf2[path.text.len..][0..bun.bytecode_extension.len].* = bun.bytecode_extension.*; - const bytecode = bun.sys.File.toSourceAt(dirname_fd.unwrapValid() orelse bun.FD.cwd(), path_buf2[0 .. path.text.len + bun.bytecode_extension.len], bun.default_allocator, .{}).asValue() orelse break :brk default_value; - if (bytecode.contents.len == 0) { - break :brk default_value; - } - break :brk if (already_bundled == .bytecode_cjs) .{ .bytecode_cjs = @constCast(bytecode.contents) } else .{ .bytecode = @constCast(bytecode.contents) }; - } - break :brk default_value; - }, - }, - .source = source.*, - .loader = loader, - .input_fd = input_fd, - }, - }; - }, - // TODO: use lazy export AST - inline .toml, .yaml, .json, .jsonc, .json5 => |kind| { - var expr = if (kind == .jsonc) - // We allow importing tsconfig.*.json or jsconfig.*.json with comments - // These files implicitly become JSONC files, which aligns with the behavior of text editors. - JSON.parseTSConfig(source, transpiler.log, allocator, false) catch return null - else if (kind == .json) - JSON.parse(source, transpiler.log, allocator, false) catch return null - else if (kind == .toml) - TOML.parse(source, transpiler.log, allocator, false) catch return null - else if (kind == .yaml) - YAML.parse(source, transpiler.log, allocator) catch return null - else if (kind == .json5) - JSON5.parse(source, transpiler.log, allocator) catch return null - else - @compileError("unreachable"); - - var symbols: []js_ast.Symbol = &.{}; - - const parts = brk: { - if (this_parse.keep_json_and_toml_as_one_statement) { - var stmts = allocator.alloc(js_ast.Stmt, 1) catch unreachable; - stmts[0] = js_ast.Stmt.allocate(allocator, js_ast.S.SExpr, js_ast.S.SExpr{ .value = expr }, logger.Loc{ .start = 0 }); - var parts_ = allocator.alloc(js_ast.Part, 1) catch unreachable; - parts_[0] = js_ast.Part{ .stmts = stmts }; - break :brk parts_; - } - - if (expr.data == .e_object) { - const properties: []js_ast.G.Property = expr.data.e_object.properties.slice(); - if (properties.len > 0) { - var stmts = allocator.alloc(js_ast.Stmt, 3) catch return null; - var decls = std.ArrayListUnmanaged(js_ast.G.Decl).initCapacity( - allocator, - properties.len, - ) catch |err| bun.handleOom(err); - decls.expandToCapacity(); - - symbols = allocator.alloc(js_ast.Symbol, properties.len) catch return null; - var export_clauses = allocator.alloc(js_ast.ClauseItem, properties.len) catch return null; - var duplicate_key_checker = bun.StringHashMap(u32).init(allocator); - defer duplicate_key_checker.deinit(); - var count: usize = 0; - for (properties, decls.items, symbols, 0..) |*prop, *decl, *symbol, i| { - const name = prop.key.?.data.e_string.slice(allocator); - // Do not make named exports for "default" exports - if (strings.eqlComptime(name, "default")) - continue; - - const visited = duplicate_key_checker.getOrPut(name) catch continue; - if (visited.found_existing) { - decls.items[visited.value_ptr.*].value = prop.value.?; - continue; - } - visited.value_ptr.* = @truncate(i); - - symbol.* = js_ast.Symbol{ - .original_name = MutableString.ensureValidIdentifier(name, allocator) catch return null, - }; - - const ref = Ref.init(@truncate(i), 0, false); - decl.* = js_ast.G.Decl{ - .binding = js_ast.Binding.alloc(allocator, js_ast.B.Identifier{ - .ref = ref, - }, prop.key.?.loc), - .value = prop.value.?, - }; - export_clauses[i] = js_ast.ClauseItem{ - .name = .{ - .ref = ref, - .loc = prop.key.?.loc, - }, - .alias = name, - .alias_loc = prop.key.?.loc, - }; - prop.value = js_ast.Expr.initIdentifier(ref, prop.value.?.loc); - count += 1; - } - - decls.shrinkRetainingCapacity(count); - stmts[0] = js_ast.Stmt.alloc( - js_ast.S.Local, - js_ast.S.Local{ - .decls = js_ast.G.Decl.List.moveFromList(&decls), - .kind = .k_var, - }, - logger.Loc{ - .start = 0, - }, - ); - stmts[1] = js_ast.Stmt.alloc( - js_ast.S.ExportClause, - js_ast.S.ExportClause{ - .items = export_clauses[0..count], - .is_single_line = false, - }, - logger.Loc{ - .start = 0, - }, - ); - stmts[2] = js_ast.Stmt.alloc( - js_ast.S.ExportDefault, - js_ast.S.ExportDefault{ - .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - .ref = Ref.None, - }, - }, - logger.Loc{ - .start = 0, - }, - ); - - var parts_ = allocator.alloc(js_ast.Part, 1) catch unreachable; - parts_[0] = js_ast.Part{ .stmts = stmts }; - break :brk parts_; - } - } - - { - var stmts = allocator.alloc(js_ast.Stmt, 1) catch unreachable; - stmts[0] = js_ast.Stmt.alloc(js_ast.S.ExportDefault, js_ast.S.ExportDefault{ - .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - .ref = Ref.None, - }, - }, logger.Loc{ .start = 0 }); - - var parts_ = allocator.alloc(js_ast.Part, 1) catch unreachable; - parts_[0] = js_ast.Part{ .stmts = stmts }; - break :brk parts_; - } - }; - var ast = js_ast.Ast.fromParts(parts); - ast.symbols = js_ast.Symbol.List.fromOwnedSlice(symbols); - - return ParseResult{ - .ast = ast, - .source = source.*, - .loader = loader, - .input_fd = input_fd, - }; - }, - // TODO: use lazy export AST - .text => { - const expr = js_ast.Expr.init(js_ast.E.String, js_ast.E.String{ - .data = source.contents, - }, logger.Loc.Empty); - const stmt = js_ast.Stmt.alloc(js_ast.S.ExportDefault, js_ast.S.ExportDefault{ - .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - .ref = Ref.None, - }, - }, logger.Loc{ .start = 0 }); - var stmts = allocator.alloc(js_ast.Stmt, 1) catch unreachable; - stmts[0] = stmt; - var parts = allocator.alloc(js_ast.Part, 1) catch unreachable; - parts[0] = js_ast.Part{ .stmts = stmts }; - - return ParseResult{ - .ast = js_ast.Ast.fromParts(parts), - .source = source.*, - .loader = loader, - .input_fd = input_fd, - }; - }, - .md => { - const html = bun.md.renderToHtml(source.contents, allocator) catch { - transpiler.log.addErrorFmt( - null, - logger.Loc.Empty, - transpiler.allocator, - "Failed to render markdown to HTML", - .{}, - ) catch {}; - return null; - }; - const expr = js_ast.Expr.init(js_ast.E.String, js_ast.E.String{ - .data = html, - }, logger.Loc.Empty); - const stmt = js_ast.Stmt.alloc(js_ast.S.ExportDefault, js_ast.S.ExportDefault{ - .value = js_ast.StmtOrExpr{ .expr = expr }, - .default_name = js_ast.LocRef{ - .loc = logger.Loc{}, - .ref = Ref.None, - }, - }, logger.Loc{ .start = 0 }); - var stmts = allocator.alloc(js_ast.Stmt, 1) catch unreachable; - stmts[0] = stmt; - var parts = allocator.alloc(js_ast.Part, 1) catch unreachable; - parts[0] = js_ast.Part{ .stmts = stmts }; - - return ParseResult{ - .ast = js_ast.Ast.fromParts(parts), - .source = source.*, - .loader = loader, - .input_fd = input_fd, - }; - }, - .wasm => { - if (transpiler.options.target.isBun()) { - if (!source.isWebAssembly()) { - transpiler.log.addErrorFmt( - null, - logger.Loc.Empty, - transpiler.allocator, - "Invalid wasm file \"{s}\" (missing magic header)", - .{path.text}, - ) catch {}; - return null; - } - - return ParseResult{ - .ast = js_ast.Ast.empty, - .source = source.*, - .loader = loader, - .input_fd = input_fd, - }; - } - }, - .css => {}, - else => Output.panic("Unsupported loader {s} for path: {s}", .{ @tagName(loader), source.path.text }), - } - - return null; - } - - fn normalizeEntryPointPath(transpiler: *Transpiler, _entry: string) string { - var paths = [_]string{_entry}; - var entry = transpiler.fs.abs(&paths); - - std.fs.accessAbsolute(entry, .{}) catch - return _entry; - - entry = transpiler.fs.relativeTo(entry); - - if (!strings.startsWith(entry, "./")) { - // Entry point paths without a leading "./" are interpreted as package - // paths. This happens because they go through general path resolution - // like all other import paths so that plugins can run on them. Requiring - // a leading "./" for a relative path simplifies writing plugins because - // entry points aren't a special case. - // - // However, requiring a leading "./" also breaks backward compatibility - // and makes working with the CLI more difficult. So attempt to insert - // "./" automatically when needed. We don't want to unconditionally insert - // a leading "./" because the path may not be a file system path. For - // example, it may be a URL. So only insert a leading "./" when the path - // is an exact match for an existing file. - var __entry = transpiler.allocator.alloc(u8, "./".len + entry.len) catch unreachable; - __entry[0] = '.'; - __entry[1] = '/'; - bun.copy(u8, __entry[2..__entry.len], entry); - entry = __entry; - } - - return entry; - } - - fn enqueueEntryPoints(transpiler: *Transpiler, entry_points: []_resolver.Result, comptime normalize_entry_point: bool) usize { - var entry_point_i: usize = 0; - - for (transpiler.options.entry_points) |_entry| { - const entry: string = if (comptime normalize_entry_point) transpiler.normalizeEntryPointPath(_entry) else _entry; - - defer { - js_ast.Expr.Data.Store.reset(); - js_ast.Stmt.Data.Store.reset(); - } - - const result = transpiler.resolver.resolve(transpiler.fs.top_level_dir, entry, .entry_point_build) catch |err| { - Output.prettyError("Error resolving \"{s}\": {s}\n", .{ entry, @errorName(err) }); - continue; - }; - - if (result.pathConst() == null) { - Output.prettyError("\"{s}\" is disabled due to \"browser\" field in package.json.\n", .{ - entry, - }); - continue; - } - - if (transpiler.linker.enqueueResolveResult(&result) catch unreachable) { - entry_points[entry_point_i] = result; - entry_point_i += 1; - } - } - - return entry_point_i; - } - - pub fn transform( - transpiler: *Transpiler, - allocator: std.mem.Allocator, - log: *logger.Log, - opts: api.TransformOptions, - ) !options.TransformResult { - _ = opts; - var entry_points = try allocator.alloc(_resolver.Result, transpiler.options.entry_points.len); - entry_points = entry_points[0..transpiler.enqueueEntryPoints(entry_points, true)]; - - if (log.level.atLeast(.debug)) { - transpiler.resolver.debug_logs = try DebugLogs.init(allocator); - } - transpiler.options.transform_only = true; - const did_start = false; - - if (transpiler.options.output_dir_handle == null) { - const outstream = bun.sys.File.from(std.fs.File.stdout()); - - if (!did_start) { - try switch (transpiler.options.import_path_format) { - .relative => transpiler.processResolveQueue(.relative, false, @TypeOf(outstream), outstream), - .absolute_url => transpiler.processResolveQueue(.absolute_url, false, @TypeOf(outstream), outstream), - .absolute_path => transpiler.processResolveQueue(.absolute_path, false, @TypeOf(outstream), outstream), - .package_path => transpiler.processResolveQueue(.package_path, false, @TypeOf(outstream), outstream), - }; - } - } else { - const output_dir = transpiler.options.output_dir_handle orelse { - Output.printError("Invalid or missing output directory.", .{}); - Global.crash(); - }; - - if (!did_start) { - try switch (transpiler.options.import_path_format) { - .relative => transpiler.processResolveQueue(.relative, false, std.fs.Dir, output_dir), - .absolute_url => transpiler.processResolveQueue(.absolute_url, false, std.fs.Dir, output_dir), - .absolute_path => transpiler.processResolveQueue(.absolute_path, false, std.fs.Dir, output_dir), - .package_path => transpiler.processResolveQueue(.package_path, false, std.fs.Dir, output_dir), - }; - } - } - - if (FeatureFlags.tracing and transpiler.options.log.level.atLeast(.info)) { - Output.prettyErrorln( - "\n---Tracing---\nResolve time: {d}\nParsing time: {d}\n---Tracing--\n\n", - .{ - transpiler.resolver.elapsed, - transpiler.elapsed, - }, - ); - } - - var final_result = try options.TransformResult.init(try allocator.dupe(u8, transpiler.result.outbase), try transpiler.output_files.toOwnedSlice(), log, allocator); - final_result.root_dir = transpiler.options.output_dir_handle; - return final_result; - } - - fn processResolveQueue( - transpiler: *Transpiler, - comptime import_path_format: options.BundleOptions.ImportPathFormat, - comptime wrap_entry_point: bool, - comptime Outstream: type, - outstream: Outstream, - ) !void { - while (transpiler.resolve_queue.readItem()) |item| { - js_ast.Expr.Data.Store.reset(); - js_ast.Stmt.Data.Store.reset(); - - if (comptime wrap_entry_point) { - const path = item.pathConst() orelse unreachable; - const loader = transpiler.options.loader(path.name.ext); - - if (item.import_kind == .entry_point and loader.supportsClientEntryPoint()) { - var client_entry_point = try transpiler.allocator.create(EntryPoints.ClientEntryPoint); - client_entry_point.* = EntryPoints.ClientEntryPoint{}; - try client_entry_point.generate(Transpiler, transpiler, path.name, transpiler.options.framework.?.client.path); - - const entry_point_output_file = transpiler.buildWithResolveResultEager( - item, - import_path_format, - Outstream, - outstream, - client_entry_point, - ) catch continue orelse continue; - transpiler.output_files.append(entry_point_output_file) catch unreachable; - - js_ast.Expr.Data.Store.reset(); - js_ast.Stmt.Data.Store.reset(); - - // At this point, the entry point will be de-duped. - // So we just immediately build it. - var item_not_entrypointed = item; - item_not_entrypointed.import_kind = .stmt; - const original_output_file = transpiler.buildWithResolveResultEager( - item_not_entrypointed, - import_path_format, - Outstream, - outstream, - null, - ) catch continue orelse continue; - transpiler.output_files.append(original_output_file) catch unreachable; - - continue; - } - } - - const output_file = transpiler.buildWithResolveResultEager( - item, - import_path_format, - Outstream, - outstream, - null, - ) catch continue orelse continue; - transpiler.output_files.append(output_file) catch unreachable; - } - } -}; - -pub const ServeResult = struct { - file: options.OutputFile, - mime_type: MimeType, -}; -pub const ResolveResults = std.AutoHashMap( - u64, - void, -); -pub const ResolveQueue = bun.LinearFifo( - _resolver.Result, - .Dynamic, -); - -const string = []const u8; - -const DotEnv = @import("../dotenv/env_loader.zig"); -const Fs = @import("../resolver/fs.zig"); -const MimeType = @import("../http_types/MimeType.zig"); -const NodeFallbackModules = @import("../resolver/node_fallbacks.zig"); -const Router = @import("../router/router.zig"); -const analyze_transpiled_module = @import("./analyze_transpiled_module.zig"); -const runtime = @import("../js_parser/runtime.zig"); -const std = @import("std"); -const DataURL = @import("../resolver/data_url.zig").DataURL; -const MacroRemap = @import("../resolver/package_json.zig").MacroMap; -const PackageManager = @import("../install/install.zig").PackageManager; -const SystemTimer = @import("../perf/system_timer.zig").Timer; -const URL = @import("../url/url.zig").URL; -const default_macro_js_value = @import("../bundler_jsc/PluginRunner.zig").default_macro_js_value; - -const _resolver = @import("../resolver/resolver.zig"); -const DebugLogs = _resolver.DebugLogs; -const Resolver = _resolver.Resolver; - -const linker = @import("./linker.zig"); -const Linker = linker.Linker; - -const bun = @import("bun"); -const FD = bun.FD; -const FeatureFlags = bun.FeatureFlags; -const Global = bun.Global; -const JSON = bun.json; -const MutableString = bun.MutableString; -const Output = bun.Output; -const default_allocator = bun.default_allocator; -const js_parser = bun.js_parser; -const js_printer = bun.js_printer; -const jsc = bun.jsc; -const logger = bun.logger; -const strings = bun.strings; -const api = bun.schema.api; -const JSON5 = bun.interchange.json5.JSON5Parser; -const TOML = bun.interchange.toml.TOML; -const YAML = bun.interchange.yaml.YAML; - -const js_ast = bun.ast; -const Ref = bun.ast.Ref; diff --git a/src/bundler_jsc/JSBundleCompletionTask.zig b/src/bundler_jsc/JSBundleCompletionTask.zig deleted file mode 100644 index 548c96648e66..000000000000 --- a/src/bundler_jsc/JSBundleCompletionTask.zig +++ /dev/null @@ -1,621 +0,0 @@ -//! `JSBundleCompletionTask` and the JS-facing entrypoints for `Bun.build()`. -//! Moved from inside `BundleV2` so `bundler/` is free of JSC types. Aliased -//! back as `BundleV2.JSBundleCompletionTask` etc. - -pub const BuildResult = bv2.BundleV2.BuildResult; -pub const Result = bv2.BundleV2.Result; - -pub const JSBundleThread = BundleThread(JSBundleCompletionTask); - -pub fn createAndScheduleCompletionTask( - config: bun.jsc.API.JSBundler.Config, - plugins: ?*bun.jsc.API.JSBundler.Plugin, - globalThis: *jsc.JSGlobalObject, - event_loop: *bun.jsc.EventLoop, - _: std.mem.Allocator, -) OOM!*JSBundleCompletionTask { - const completion = bun.new(JSBundleCompletionTask, .{ - .ref_count = .init(), - .config = config, - .jsc_event_loop = event_loop, - .globalThis = globalThis, - .poll_ref = Async.KeepAlive.init(), - .env = globalThis.bunVM().transpiler.env, - .plugins = plugins, - .log = Logger.Log.init(bun.default_allocator), - .task = undefined, - }); - completion.task = JSBundleCompletionTask.TaskCompletion.init(completion); - - if (plugins) |plugin| { - plugin.setConfig(completion); - } - - // Ensure this exists before we spawn the thread to prevent any race - // conditions from creating two - _ = jsc.WorkPool.get(); - - JSBundleThread.singleton.enqueue(completion); - - completion.poll_ref.ref(globalThis.bunVM()); - - return completion; -} - -pub fn generateFromJavaScript( - config: bun.jsc.API.JSBundler.Config, - plugins: ?*bun.jsc.API.JSBundler.Plugin, - globalThis: *jsc.JSGlobalObject, - event_loop: *bun.jsc.EventLoop, - alloc: std.mem.Allocator, -) OOM!bun.jsc.JSValue { - const completion = try createAndScheduleCompletionTask(config, plugins, globalThis, event_loop, alloc); - completion.promise = jsc.JSPromise.Strong.init(globalThis); - return completion.promise.value(); -} - -pub const JSBundleCompletionTask = struct { - pub const RefCount = bun.ptr.ThreadSafeRefCount(@This(), "ref_count", @This().deinit, .{}); - pub const ref = RefCount.ref; - pub const deref = RefCount.deref; - - ref_count: RefCount, - config: bun.jsc.API.JSBundler.Config, - jsc_event_loop: *bun.jsc.EventLoop, - task: bun.jsc.AnyTask, - globalThis: *jsc.JSGlobalObject, - promise: jsc.JSPromise.Strong = .{}, - poll_ref: Async.KeepAlive = Async.KeepAlive.init(), - env: *bun.DotEnv.Loader, - log: Logger.Log, - cancelled: bool = false, - - html_build_task: ?*jsc.API.HTMLBundle.HTMLBundleRoute = null, - - result: Result = .{ .pending = {} }, - - next: ?*JSBundleCompletionTask = null, - transpiler: *BundleV2 = undefined, - plugins: ?*bun.jsc.API.JSBundler.Plugin = null, - started_at_ns: u64 = 0, - - pub fn configureBundler( - completion: *JSBundleCompletionTask, - transpiler: *Transpiler, - alloc: std.mem.Allocator, - ) !void { - const config = &completion.config; - - // JSX config is already in API format - const jsx_api = config.jsx; - - transpiler.* = try bun.Transpiler.init( - alloc, - &completion.log, - api.TransformOptions{ - .define = if (config.define.count() > 0) config.define.toAPI() else null, - .entry_points = config.entry_points.keys(), - .target = config.target.toAPI(), - .absolute_working_dir = if (config.dir.list.items.len > 0) - config.dir.sliceWithSentinel() - else - null, - .inject = &.{}, - .external = config.external.keys(), - .main_fields = &.{}, - .extension_order = &.{}, - .env_files = &.{}, - .conditions = config.conditions.map.keys(), - .ignore_dce_annotations = transpiler.options.ignore_dce_annotations, - .drop = config.drop.map.keys(), - .bunfig_path = transpiler.options.bunfig_path, - .jsx = jsx_api, - }, - completion.env, - ); - transpiler.options.env.behavior = config.env_behavior; - transpiler.options.env.prefix = config.env_prefix.slice(); - // Use the StringSet directly instead of the slice passed through TransformOptions - transpiler.options.bundler_feature_flags = &config.features; - if (config.force_node_env != .unspecified) { - transpiler.options.force_node_env = config.force_node_env; - } - - transpiler.options.entry_points = config.entry_points.keys(); - // Convert API JSX config back to options.JSX.Pragma - transpiler.options.jsx = options.JSX.Pragma{ - .factory = if (config.jsx.factory.len > 0) - try options.JSX.Pragma.memberListToComponentsIfDifferent(alloc, &.{}, config.jsx.factory) - else - options.JSX.Pragma.Defaults.Factory, - .fragment = if (config.jsx.fragment.len > 0) - try options.JSX.Pragma.memberListToComponentsIfDifferent(alloc, &.{}, config.jsx.fragment) - else - options.JSX.Pragma.Defaults.Fragment, - .runtime = config.jsx.runtime, - .development = config.jsx.development, - .package_name = if (config.jsx.import_source.len > 0) config.jsx.import_source else "react", - .classic_import_source = if (config.jsx.import_source.len > 0) config.jsx.import_source else "react", - .side_effects = config.jsx.side_effects, - .parse = true, - .import_source = .{ - .development = if (config.jsx.import_source.len > 0) - try std.fmt.allocPrint(alloc, "{s}/jsx-dev-runtime", .{config.jsx.import_source}) - else - "react/jsx-dev-runtime", - .production = if (config.jsx.import_source.len > 0) - try std.fmt.allocPrint(alloc, "{s}/jsx-runtime", .{config.jsx.import_source}) - else - "react/jsx-runtime", - }, - }; - transpiler.options.no_macros = config.no_macros; - transpiler.options.loaders = try options.loadersFromTransformOptions(alloc, config.loaders, config.target); - transpiler.options.entry_naming = config.names.entry_point.data; - transpiler.options.chunk_naming = config.names.chunk.data; - transpiler.options.asset_naming = config.names.asset.data; - - transpiler.options.output_format = config.format; - transpiler.options.bytecode = config.bytecode; - transpiler.options.compile = config.compile != null; - - // For compile mode, set the public_path to the target-specific base path - // This ensures embedded resources like yoga.wasm are correctly found - if (config.compile) |compile_opts| { - const base_public_path = bun.StandaloneModuleGraph.targetBasePublicPath(compile_opts.compile_target.os, "root/"); - transpiler.options.public_path = base_public_path; - } else { - transpiler.options.public_path = config.public_path.list.items; - } - - transpiler.options.output_dir = config.outdir.slice(); - transpiler.options.root_dir = config.rootdir.slice(); - transpiler.options.minify_syntax = config.minify.syntax; - transpiler.options.minify_whitespace = config.minify.whitespace; - transpiler.options.minify_identifiers = config.minify.identifiers; - transpiler.options.keep_names = config.minify.keep_names; - transpiler.options.inlining = config.minify.syntax; - transpiler.options.source_map = config.source_map; - transpiler.options.packages = config.packages; - transpiler.options.allow_unresolved = if (config.allow_unresolved) |*a| options.AllowUnresolved.fromStrings(a.keys()) else .all; - transpiler.options.code_splitting = config.code_splitting; - transpiler.options.emit_dce_annotations = config.emit_dce_annotations orelse !config.minify.whitespace; - transpiler.options.ignore_dce_annotations = config.ignore_dce_annotations; - transpiler.options.css_chunking = config.css_chunking; - transpiler.options.compile_to_standalone_html = brk: { - if (config.compile == null or config.target != .browser) break :brk false; - // Only activate standalone HTML when all entrypoints are HTML files - for (config.entry_points.keys()) |ep| { - if (!bun.strings.hasSuffixComptime(ep, ".html")) break :brk false; - } - break :brk config.entry_points.count() > 0; - }; - // When compiling to standalone HTML, don't use the bun executable compile path - if (transpiler.options.compile_to_standalone_html) { - transpiler.options.compile = false; - config.compile = null; - } - transpiler.options.banner = config.banner.slice(); - transpiler.options.footer = config.footer.slice(); - transpiler.options.react_fast_refresh = config.react_fast_refresh; - transpiler.options.metafile = config.metafile; - transpiler.options.metafile_json_path = config.metafile_json_path.slice(); - transpiler.options.metafile_markdown_path = config.metafile_markdown_path.slice(); - if (config.optimize_imports.count() > 0) { - transpiler.options.optimize_imports = &config.optimize_imports; - } - - if (transpiler.options.compile) { - // Emitting DCE annotations is nonsensical in --compile. - transpiler.options.emit_dce_annotations = false; - } - - transpiler.configureLinker(); - try transpiler.configureDefines(); - - if (!transpiler.options.production) { - try transpiler.options.conditions.appendSlice(&.{"development"}); - } - transpiler.resolver.env_loader = transpiler.env; - transpiler.resolver.opts = transpiler.options; - } - - pub fn completeOnBundleThread(completion: *JSBundleCompletionTask) void { - completion.jsc_event_loop.enqueueTaskConcurrent(jsc.ConcurrentTask.create(completion.task.task())); - } - - pub const TaskCompletion = bun.jsc.AnyTask.New(JSBundleCompletionTask, onComplete); - - fn deinit(this: *JSBundleCompletionTask) void { - this.result.deinit(); - this.log.deinit(); - this.poll_ref.disable(); - if (this.plugins) |plugin| { - plugin.deinit(); - } - this.config.deinit(bun.default_allocator); - this.promise.deinit(); - bun.destroy(this); - } - - fn doCompilation(this: *JSBundleCompletionTask, output_files: *std.array_list.Managed(options.OutputFile)) bun.StandaloneModuleGraph.CompileResult { - const compile_options = &(this.config.compile orelse @panic("Unexpected: No compile options provided")); - - const entry_point_index: usize = brk: { - for (output_files.items, 0..) |*output_file, i| { - if (output_file.output_kind == .@"entry-point" and (output_file.side orelse .server) == .server) { - break :brk i; - } - } - return bun.StandaloneModuleGraph.CompileResult.fail(.no_entry_point); - }; - - const output_file = &output_files.items[entry_point_index]; - const outbuf = bun.path_buffer_pool.get(); - defer bun.path_buffer_pool.put(outbuf); - - // Always get an absolute path for the outfile to ensure it works correctly with PE metadata operations - var full_outfile_path = if (this.config.outdir.slice().len > 0) brk: { - const outdir_slice = this.config.outdir.slice(); - const top_level_dir = bun.fs.FileSystem.instance.top_level_dir; - break :brk bun.path.joinAbsStringBuf(top_level_dir, outbuf, &[_][]const u8{ outdir_slice, compile_options.outfile.slice() }, .auto); - } else if (std.fs.path.isAbsolute(compile_options.outfile.slice())) - compile_options.outfile.slice() - else brk: { - // For relative paths, ensure we make them absolute relative to the current working directory - const top_level_dir = bun.fs.FileSystem.instance.top_level_dir; - break :brk bun.path.joinAbsStringBuf(top_level_dir, outbuf, &[_][]const u8{compile_options.outfile.slice()}, .auto); - }; - - // Add .exe extension for Windows targets if not already present - if (compile_options.compile_target.os == .windows and !strings.hasSuffixComptime(full_outfile_path, ".exe")) { - full_outfile_path = std.fmt.allocPrint(bun.default_allocator, "{s}.exe", .{full_outfile_path}) catch |err| bun.handleOom(err); - } else { - full_outfile_path = bun.handleOom(bun.default_allocator.dupe(u8, full_outfile_path)); - } - - const dirname = std.fs.path.dirname(full_outfile_path) orelse "."; - const basename = std.fs.path.basename(full_outfile_path); - - var root_dir = bun.FD.cwd().stdDir(); - defer { - if (bun.FD.fromStdDir(root_dir) != bun.FD.cwd()) { - root_dir.close(); - } - } - - // On Windows, don't change root_dir, just pass the full relative path - // On POSIX, change root_dir to the target directory and pass basename - const outfile_for_executable = if (Environment.isWindows) full_outfile_path else basename; - - if (Environment.isPosix and !(dirname.len == 0 or strings.eqlComptime(dirname, "."))) { - // On POSIX, makeOpenPath and change root_dir - root_dir = root_dir.makeOpenPath(dirname, .{}) catch |err| { - return bun.StandaloneModuleGraph.CompileResult.failFmt("Failed to open output directory {s}: {s}", .{ dirname, @errorName(err) }); - }; - } else if (Environment.isWindows and !(dirname.len == 0 or strings.eqlComptime(dirname, "."))) { - // On Windows, ensure directories exist but don't change root_dir - _ = bun.makePath(root_dir, dirname) catch |err| { - return bun.StandaloneModuleGraph.CompileResult.failFmt("Failed to create output directory {s}: {s}", .{ dirname, @errorName(err) }); - }; - } - - // Use the target-specific base path for compile mode, not the user-configured public_path - const module_prefix = bun.StandaloneModuleGraph.targetBasePublicPath(compile_options.compile_target.os, "root/"); - - const result = bun.StandaloneModuleGraph.toExecutable( - &compile_options.compile_target, - bun.default_allocator, - output_files.items, - root_dir, - module_prefix, - outfile_for_executable, - this.env, - this.config.format, - .{ - .hide_console = compile_options.windows_hide_console, - .icon = if (compile_options.windows_icon_path.slice().len > 0) - compile_options.windows_icon_path.slice() - else - null, - .title = if (compile_options.windows_title.slice().len > 0) - compile_options.windows_title.slice() - else - null, - .publisher = if (compile_options.windows_publisher.slice().len > 0) - compile_options.windows_publisher.slice() - else - null, - .version = if (compile_options.windows_version.slice().len > 0) - compile_options.windows_version.slice() - else - null, - .description = if (compile_options.windows_description.slice().len > 0) - compile_options.windows_description.slice() - else - null, - .copyright = if (compile_options.windows_copyright.slice().len > 0) - compile_options.windows_copyright.slice() - else - null, - }, - compile_options.exec_argv.slice(), - if (compile_options.executable_path.slice().len > 0) - compile_options.executable_path.slice() - else - null, - .{ - .disable_default_env_files = !compile_options.autoload_dotenv, - .disable_autoload_bunfig = !compile_options.autoload_bunfig, - .disable_autoload_tsconfig = !compile_options.autoload_tsconfig, - .disable_autoload_package_json = !compile_options.autoload_package_json, - }, - ) catch |err| { - return bun.StandaloneModuleGraph.CompileResult.failFmt("{s}", .{@errorName(err)}); - }; - - if (result == .success) { - output_file.dest_path = full_outfile_path; - output_file.is_executable = true; - } - - // Write external sourcemap files next to the compiled executable and - // keep them in the output array. Destroy all other non-entry-point files. - // With --splitting, there can be multiple sourcemap files (one per chunk). - var kept: usize = 0; - for (output_files.items, 0..) |*current, i| { - if (i == entry_point_index) { - output_files.items[kept] = current.*; - kept += 1; - } else if (result == .success and current.output_kind == .sourcemap and current.value == .buffer) { - const sourcemap_bytes = current.value.buffer.bytes; - if (sourcemap_bytes.len > 0) { - // Derive the .map filename from the sourcemap's own dest_path, - // placed in the same directory as the compiled executable. - const map_basename = if (current.dest_path.len > 0) - bun.path.basename(current.dest_path) - else - bun.path.basename(bun.handleOom(std.fmt.allocPrint(bun.default_allocator, "{s}.map", .{full_outfile_path}))); - - const sourcemap_full_path = if (dirname.len == 0 or strings.eqlComptime(dirname, ".")) - bun.handleOom(bun.default_allocator.dupe(u8, map_basename)) - else - bun.handleOom(std.fmt.allocPrint(bun.default_allocator, "{s}{c}{s}", .{ dirname, std.fs.path.sep, map_basename })); - - // Write the sourcemap file to disk next to the executable - var pathbuf: bun.PathBuffer = undefined; - const write_path = if (Environment.isWindows) sourcemap_full_path else map_basename; - switch (bun.jsc.Node.fs.NodeFS.writeFileWithPathBuffer( - &pathbuf, - .{ - .data = .{ .buffer = .{ - .buffer = .{ - .ptr = @constCast(sourcemap_bytes.ptr), - .len = @as(u32, @truncate(sourcemap_bytes.len)), - .byte_len = @as(u32, @truncate(sourcemap_bytes.len)), - }, - } }, - .encoding = .buffer, - .dirfd = .fromStdDir(root_dir), - .file = .{ .path = .{ - .string = bun.PathString.init(write_path), - } }, - }, - )) { - .err => |err| { - bun.Output.err(err, "failed to write sourcemap file '{s}'", .{write_path}); - current.deinit(); - }, - .result => { - current.dest_path = sourcemap_full_path; - output_files.items[kept] = current.*; - kept += 1; - }, - } - } else { - current.deinit(); - } - } else { - current.deinit(); - } - } - output_files.items.len = kept; - - return result; - } - - /// Returns true if the promises were handled and resolved from BundlePlugin.ts, returns false if the caller should imediately resolve - fn runOnEndCallbacks(globalThis: *jsc.JSGlobalObject, plugin: *bun.jsc.API.JSBundler.Plugin, promise: *jsc.JSPromise, build_result: jsc.JSValue, rejection: bun.JSError!jsc.JSValue) bun.JSError!bool { - const value = try plugin.runOnEndCallbacks(globalThis, promise, build_result, rejection); - return value != .js_undefined; - } - - fn toJSError(this: *JSBundleCompletionTask, promise: *jsc.JSPromise, globalThis: *jsc.JSGlobalObject) bun.JSTerminated!void { - const throw_on_error = this.config.throw_on_error; - - const build_result = jsc.JSValue.createEmptyObject(globalThis, 3); - build_result.put(globalThis, jsc.ZigString.static("outputs"), jsc.JSValue.createEmptyArray(globalThis, 0) catch return promise.reject(globalThis, error.JSError)); - build_result.put( - globalThis, - jsc.ZigString.static("success"), - .false, - ); - build_result.put( - globalThis, - jsc.ZigString.static("logs"), - this.log.toJSArray(globalThis, bun.default_allocator) catch |err| { - return promise.reject(globalThis, err); - }, - ); - - const didHandleCallbacks = if (this.plugins) |plugin| blk: { - if (throw_on_error) { - const aggregate_error = this.log.toJSAggregateError(globalThis, bun.String.static("Bundle failed")); - break :blk runOnEndCallbacks(globalThis, plugin, promise, build_result, aggregate_error) catch |err| { - return promise.reject(globalThis, err); - }; - } else { - break :blk runOnEndCallbacks(globalThis, plugin, promise, build_result, .js_undefined) catch |err| { - return promise.reject(globalThis, err); - }; - } - } else false; - - if (!didHandleCallbacks) { - if (throw_on_error) { - const aggregate_error = this.log.toJSAggregateError(globalThis, bun.String.static("Bundle failed")); - return promise.reject(globalThis, aggregate_error); - } else { - return promise.resolve(globalThis, build_result); - } - } - } - - pub fn onComplete(this: *JSBundleCompletionTask) bun.JSTerminated!void { - var globalThis = this.globalThis; - defer this.deref(); - - this.poll_ref.unref(globalThis.bunVM()); - if (this.cancelled) { - return; - } - - if (this.html_build_task) |html_build_task| { - this.plugins = null; - html_build_task.onComplete(this); - return; - } - - const promise = this.promise.swap(); - - if (this.result == .value) { - if (this.config.compile != null) { - var compile_result = this.doCompilation(&this.result.value.output_files); - defer compile_result.deinit(); - - if (compile_result != .success) { - bun.handleOom(this.log.addError(null, Logger.Loc.Empty, bun.handleOom(this.log.msgs.allocator.dupe(u8, compile_result.err.slice())))); - this.result.value.deinit(); - this.result = .{ .err = error.CompilationFailed }; - } - } - } - - switch (this.result) { - .pending => unreachable, - .err => try this.toJSError(promise, globalThis), - .value => |*build| { - const output_files = build.output_files.items; - const output_files_js = jsc.JSValue.createEmptyArray(globalThis, output_files.len) catch return promise.reject(globalThis, error.JSError); - if (output_files_js == .zero) { - @panic("Unexpected pending JavaScript exception in JSBundleCompletionTask.onComplete. This is a bug in Bun."); - } - - var to_assign_on_sourcemap: jsc.JSValue = .zero; - for (output_files, 0..) |*output_file, i| { - const result = output_file.toJS( - if (!this.config.outdir.isEmpty()) - if (std.fs.path.isAbsolute(this.config.outdir.list.items)) - bun.default_allocator.dupe( - u8, - bun.path.joinAbsString( - this.config.outdir.slice(), - &[_]string{output_file.dest_path}, - .auto, - ), - ) catch unreachable - else - bun.default_allocator.dupe( - u8, - bun.path.joinAbsString( - bun.fs.FileSystem.instance.top_level_dir, - &[_]string{ this.config.dir.slice(), this.config.outdir.slice(), output_file.dest_path }, - .auto, - ), - ) catch unreachable - else - bun.default_allocator.dupe( - u8, - output_file.dest_path, - ) catch unreachable, - globalThis, - ); - if (to_assign_on_sourcemap != .zero) { - jsc.Codegen.JSBuildArtifact.sourcemapSetCached(to_assign_on_sourcemap, globalThis, result); - if (to_assign_on_sourcemap.as(jsc.API.BuildArtifact)) |to_assign_on_sourcemap_artifact| { - to_assign_on_sourcemap_artifact.sourcemap.set(globalThis, result); - } - to_assign_on_sourcemap = .zero; - } - - if (output_file.source_map_index != std.math.maxInt(u32)) { - to_assign_on_sourcemap = result; - } - - output_files_js.putIndex(globalThis, @as(u32, @intCast(i)), result) catch |err| { - return promise.reject(globalThis, err); - }; - } - const build_output = jsc.JSValue.createEmptyObject(globalThis, 4); - build_output.put(globalThis, jsc.ZigString.static("outputs"), output_files_js); - build_output.put(globalThis, jsc.ZigString.static("success"), .true); - build_output.put( - globalThis, - jsc.ZigString.static("logs"), - this.log.toJSArray(globalThis, bun.default_allocator) catch |err| { - return promise.reject(globalThis, err); - }, - ); - - // Add metafile if it was generated - // metafile: { json: , markdown?: string } - if (build.metafile) |metafile| { - const metafile_js_str = bun.String.createUTF8ForJS(globalThis, metafile) catch |err| { - return promise.reject(globalThis, err); - }; - const metafile_md_str: jsc.JSValue = if (build.metafile_markdown) |md| - (bun.String.createUTF8ForJS(globalThis, md) catch |err| { - return promise.reject(globalThis, err); - }) - else - .js_undefined; - // Set up metafile object with json (lazy) and markdown (if present) - Bun__setupLazyMetafile(globalThis, build_output, metafile_js_str, metafile_md_str); - } - - const didHandleCallbacks = if (this.plugins) |plugin| runOnEndCallbacks(globalThis, plugin, promise, build_output, .js_undefined) catch |err| { - return promise.reject(globalThis, err); - } else false; - - if (!didHandleCallbacks) { - return promise.resolve(globalThis, build_output); - } - }, - } - } -}; - -extern "C" fn Bun__setupLazyMetafile(globalThis: *jsc.JSGlobalObject, buildOutput: jsc.JSValue, metafileJsonString: jsc.JSValue, metafileMarkdownString: jsc.JSValue) callconv(jsc.conv) void; - -const string = []const u8; - -const std = @import("std"); - -const bv2 = @import("../bundler/bundle_v2.zig"); -const BundleThread = bv2.BundleThread; -const BundleV2 = bv2.BundleV2; - -const bun = @import("bun"); -const Async = bun.Async; -const Environment = bun.Environment; -const Logger = bun.logger; -const OOM = bun.OOM; -const StandaloneModuleGraph = bun.StandaloneModuleGraph; -const String = bun.String; -const jsc = bun.jsc; -const logger = bun.logger; -const options = bun.options; -const sourcemap = bun.sourcemap; -const strings = bun.strings; -const Transpiler = bun.transpiler.Transpiler; -const api = bun.schema.api; diff --git a/src/bundler_jsc/PluginRunner.zig b/src/bundler_jsc/PluginRunner.zig deleted file mode 100644 index 83829bbe8a39..000000000000 --- a/src/bundler_jsc/PluginRunner.zig +++ /dev/null @@ -1,241 +0,0 @@ -//! Runtime plugin host (JS-side `Bun.plugin()` resolve hooks). Moved from -//! `bundler/transpiler.zig` so `bundler/` is free of `JSValue`/`JSGlobalObject`. - -pub const MacroJSCtx = jsc.JSValue; -pub const default_macro_js_value = jsc.JSValue.zero; - -pub const PluginRunner = struct { - global_object: *jsc.JSGlobalObject, - allocator: std.mem.Allocator, - - pub fn extractNamespace(specifier: string) string { - const colon = strings.indexOfChar(specifier, ':') orelse return ""; - if (Environment.isWindows and - colon == 1 and - specifier.len > 3 and - bun.path.isSepAny(specifier[2]) and - ((specifier[0] > 'a' and specifier[0] < 'z') or (specifier[0] > 'A' and specifier[0] < 'Z'))) - return ""; - return specifier[0..colon]; - } - - pub fn couldBePlugin(specifier: string) bool { - if (strings.lastIndexOfChar(specifier, '.')) |last_dor| { - const ext = specifier[last_dor + 1 ..]; - // '.' followed by either a letter or a non-ascii character - // maybe there are non-ascii file extensions? - // we mostly want to cheaply rule out "../" and ".." and "./" - if (ext.len > 0 and ((ext[0] >= 'a' and ext[0] <= 'z') or (ext[0] >= 'A' and ext[0] <= 'Z') or ext[0] > 127)) - return true; - } - return (!std.fs.path.isAbsolute(specifier) and strings.containsChar(specifier, ':')); - } - - pub fn onResolve( - this: *PluginRunner, - specifier: []const u8, - importer: []const u8, - log: *logger.Log, - loc: logger.Loc, - target: jsc.JSGlobalObject.BunPluginTarget, - ) bun.JSError!?Fs.Path { - var global = this.global_object; - const namespace_slice = extractNamespace(specifier); - const namespace = if (namespace_slice.len > 0 and !strings.eqlComptime(namespace_slice, "file")) - bun.String.init(namespace_slice) - else - bun.String.empty; - const on_resolve_plugin = try global.runOnResolvePlugins( - namespace, - bun.String.init(specifier).substring(if (namespace.length() > 0) namespace.length() + 1 else 0), - bun.String.init(importer), - target, - ) orelse return null; - const path_value = try on_resolve_plugin.get(global, "path") orelse return null; - if (path_value.isEmptyOrUndefinedOrNull()) return null; - if (!path_value.isString()) { - log.addError(null, loc, "Expected \"path\" to be a string") catch unreachable; - return null; - } - - const file_path = try path_value.toBunString(global); - defer file_path.deref(); - - if (file_path.length() == 0) { - log.addError( - null, - loc, - "Expected \"path\" to be a non-empty string in onResolve plugin", - ) catch unreachable; - return null; - } else if - // TODO: validate this better - (file_path.eqlComptime(".") or - file_path.eqlComptime("..") or - file_path.eqlComptime("...") or - file_path.eqlComptime(" ")) - { - log.addError( - null, - loc, - "Invalid file path from onResolve plugin", - ) catch unreachable; - return null; - } - var static_namespace = true; - const user_namespace: bun.String = brk: { - if (try on_resolve_plugin.get(global, "namespace")) |namespace_value| { - if (!namespace_value.isString()) { - log.addError(null, loc, "Expected \"namespace\" to be a string") catch unreachable; - return null; - } - - const namespace_str = try namespace_value.toBunString(global); - if (namespace_str.length() == 0) { - namespace_str.deref(); - break :brk bun.String.init("file"); - } - - if (namespace_str.eqlComptime("file")) { - namespace_str.deref(); - break :brk bun.String.init("file"); - } - - if (namespace_str.eqlComptime("bun")) { - namespace_str.deref(); - break :brk bun.String.init("bun"); - } - - if (namespace_str.eqlComptime("node")) { - namespace_str.deref(); - break :brk bun.String.init("node"); - } - - static_namespace = false; - - break :brk namespace_str; - } - - break :brk bun.String.init("file"); - }; - defer user_namespace.deref(); - - if (static_namespace) { - return Fs.Path.initWithNamespace( - std.fmt.allocPrint(this.allocator, "{f}", .{file_path}) catch unreachable, - user_namespace.byteSlice(), - ); - } else { - return Fs.Path.initWithNamespace( - std.fmt.allocPrint(this.allocator, "{f}", .{file_path}) catch unreachable, - std.fmt.allocPrint(this.allocator, "{f}", .{user_namespace}) catch unreachable, - ); - } - } - - pub fn onResolveJSC(this: *const PluginRunner, namespace: bun.String, specifier: bun.String, importer: bun.String, target: jsc.JSGlobalObject.BunPluginTarget) bun.JSError!?jsc.ErrorableString { - var global = this.global_object; - const on_resolve_plugin = try global.runOnResolvePlugins( - if (namespace.length() > 0 and !namespace.eqlComptime("file")) - namespace - else - bun.String.static(""), - specifier, - importer, - target, - ) orelse return null; - if (!on_resolve_plugin.isObject()) return null; - const path_value = try on_resolve_plugin.get(global, "path") orelse return null; - if (path_value.isEmptyOrUndefinedOrNull()) return null; - if (!path_value.isString()) { - return jsc.ErrorableString.err( - error.JSErrorObject, - bun.String.static("Expected \"path\" to be a string in onResolve plugin").toErrorInstance(this.global_object), - ); - } - - const file_path = try path_value.toBunString(global); - - if (file_path.length() == 0) { - return jsc.ErrorableString.err( - error.JSErrorObject, - bun.String.static("Expected \"path\" to be a non-empty string in onResolve plugin").toErrorInstance(this.global_object), - ); - } else if - // TODO: validate this better - (file_path.eqlComptime(".") or - file_path.eqlComptime("..") or - file_path.eqlComptime("...") or - file_path.eqlComptime(" ")) - { - return jsc.ErrorableString.err( - error.JSErrorObject, - bun.String.static("\"path\" is invalid in onResolve plugin").toErrorInstance(this.global_object), - ); - } - var static_namespace = true; - const user_namespace: bun.String = brk: { - if (try on_resolve_plugin.get(global, "namespace")) |namespace_value| { - if (!namespace_value.isString()) { - return jsc.ErrorableString.err( - error.JSErrorObject, - bun.String.static("Expected \"namespace\" to be a string").toErrorInstance(this.global_object), - ); - } - - const namespace_str = try namespace_value.toBunString(global); - if (namespace_str.length() == 0) { - break :brk bun.String.static("file"); - } - - if (namespace_str.eqlComptime("file")) { - defer namespace_str.deref(); - break :brk bun.String.static("file"); - } - - if (namespace_str.eqlComptime("bun")) { - defer namespace_str.deref(); - break :brk bun.String.static("bun"); - } - - if (namespace_str.eqlComptime("node")) { - defer namespace_str.deref(); - break :brk bun.String.static("node"); - } - - static_namespace = false; - - break :brk namespace_str; - } - - break :brk bun.String.static("file"); - }; - defer user_namespace.deref(); - - // Our super slow way of cloning the string into memory owned by jsc - const combined_string = std.fmt.allocPrint(this.allocator, "{f}:{f}", .{ user_namespace, file_path }) catch unreachable; - var out_ = bun.String.init(combined_string); - defer out_.deref(); - const jsval = out_.toJS(this.global_object) catch |err| { - this.allocator.free(combined_string); - return jsc.ErrorableString.err(err, this.global_object.tryTakeException() orelse .js_undefined); - }; - const out = jsval.toBunString(this.global_object) catch |err| { - this.allocator.free(combined_string); - return jsc.ErrorableString.err(err, this.global_object.tryTakeException() orelse .js_undefined); - }; - this.allocator.free(combined_string); - return jsc.ErrorableString.ok(out); - } -}; - -const string = []const u8; - -const std = @import("std"); - -const bun = @import("bun"); -const Environment = bun.Environment; -const Fs = bun.fs; -const jsc = bun.jsc; -const logger = bun.logger; -const strings = bun.strings; diff --git a/src/bundler_jsc/analyze_jsc.zig b/src/bundler_jsc/analyze_jsc.zig deleted file mode 100644 index 3764f35aa182..000000000000 --- a/src/bundler_jsc/analyze_jsc.zig +++ /dev/null @@ -1,148 +0,0 @@ -//! JSC bridge for analyze_transpiled_module.zig — converts the parsed -//! `ModuleInfoDeserialized` into a `JSC::JSModuleRecord`. Aliased back so the -//! `export fn` symbol names are still discoverable from C++. - -export fn zig__renderDiff(expected_ptr: [*:0]const u8, expected_len: usize, received_ptr: [*:0]const u8, received_len: usize, globalThis: *bun.jsc.JSGlobalObject) void { - const formatter = DiffFormatter{ - .received_string = received_ptr[0..received_len], - .expected_string = expected_ptr[0..expected_len], - .globalThis = globalThis, - }; - bun.Output.errorWriter().print("DIFF:\n{any}\n", .{formatter}) catch {}; -} - -export fn zig__ModuleInfoDeserialized__toJSModuleRecord( - globalObject: *bun.jsc.JSGlobalObject, - vm: *bun.jsc.VM, - module_key: *const IdentifierArray, - source_code: *const SourceCode, - declared_variables: *VariableEnvironment, - lexical_variables: *VariableEnvironment, - res: *ModuleInfoDeserialized, -) ?*JSModuleRecord { - // Ownership of `res` stays with the caller; this function only reads it. - // The caller (BunAnalyzeTranspiledModule.cpp) decides whether to free - // immediately or keep it alive on the SourceProvider for the isolation - // SourceProvider cache. - - var identifiers = IdentifierArray.create(res.strings_lens.len); - defer identifiers.destroy(); - var offset: usize = 0; - for (0.., res.strings_lens) |index, len| { - if (res.strings_buf.len < offset + len) return null; // error! - const sub = res.strings_buf[offset..][0..len]; - identifiers.setFromUtf8(index, vm, sub); - offset += len; - } - - { - var i: usize = 0; - for (res.record_kinds) |k| { - if (i + (k.len() catch 0) > res.buffer.len) return null; - switch (k) { - .declared_variable => declared_variables.add(vm, identifiers, res.buffer[i]), - .lexical_variable => lexical_variables.add(vm, identifiers, res.buffer[i]), - .import_info_single, .import_info_single_type_script, .import_info_namespace, .export_info_indirect, .export_info_local, .export_info_namespace, .export_info_star => {}, - else => return null, - } - i += k.len() catch unreachable; // handled above - } - } - - const module_record = JSModuleRecord.create(globalObject, vm, module_key, source_code, declared_variables, lexical_variables, res.flags.contains_import_meta, res.flags.is_typescript, res.flags.has_tla); - - for (res.requested_modules_keys, res.requested_modules_values) |reqk, reqv| { - switch (reqv) { - .none => module_record.addRequestedModuleNullAttributesPtr(identifiers, reqk), - .javascript => module_record.addRequestedModuleJavaScript(identifiers, reqk), - .webassembly => module_record.addRequestedModuleWebAssembly(identifiers, reqk), - .json => module_record.addRequestedModuleJSON(identifiers, reqk), - else => |uv| module_record.addRequestedModuleHostDefined(identifiers, reqk, @enumFromInt(@intFromEnum(uv))), - } - } - - { - var i: usize = 0; - for (res.record_kinds) |k| { - if (i + (k.len() catch unreachable) > res.buffer.len) unreachable; // handled above - switch (k) { - .declared_variable, .lexical_variable => {}, - .import_info_single => module_record.addImportEntrySingle(identifiers, res.buffer[i + 1], res.buffer[i + 2], res.buffer[i]), - .import_info_single_type_script => module_record.addImportEntrySingleTypeScript(identifiers, res.buffer[i + 1], res.buffer[i + 2], res.buffer[i]), - .import_info_namespace => module_record.addImportEntryNamespace(identifiers, res.buffer[i + 1], res.buffer[i + 2], res.buffer[i]), - .export_info_indirect => if (res.buffer[i + 1] == .star_namespace) - module_record.addNamespaceExport(identifiers, res.buffer[i + 0], res.buffer[i + 2]) - else - module_record.addIndirectExport(identifiers, res.buffer[i + 0], res.buffer[i + 1], res.buffer[i + 2]), - .export_info_local => module_record.addLocalExport(identifiers, res.buffer[i], res.buffer[i + 1]), - .export_info_namespace => module_record.addNamespaceExport(identifiers, res.buffer[i], res.buffer[i + 1]), - .export_info_star => module_record.addStarExport(identifiers, res.buffer[i]), - else => unreachable, // handled above - } - i += k.len() catch unreachable; // handled above - } - } - - return module_record; -} - -const VariableEnvironment = opaque { - extern fn JSC__VariableEnvironment__add(environment: *VariableEnvironment, vm: *bun.jsc.VM, identifier_array: *IdentifierArray, identifier_index: StringID) void; - pub const add = JSC__VariableEnvironment__add; -}; -const IdentifierArray = opaque { - extern fn JSC__IdentifierArray__create(len: usize) *IdentifierArray; - pub const create = JSC__IdentifierArray__create; - - extern fn JSC__IdentifierArray__destroy(identifier_array: *IdentifierArray) void; - pub const destroy = JSC__IdentifierArray__destroy; - - extern fn JSC__IdentifierArray__setFromUtf8(identifier_array: *IdentifierArray, n: usize, vm: *bun.jsc.VM, str: [*]const u8, len: usize) void; - pub fn setFromUtf8(self: *IdentifierArray, n: usize, vm: *bun.jsc.VM, str: []const u8) void { - JSC__IdentifierArray__setFromUtf8(self, n, vm, str.ptr, str.len); - } -}; -const SourceCode = opaque {}; -const JSModuleRecord = opaque { - extern fn JSC_JSModuleRecord__create(global_object: *bun.jsc.JSGlobalObject, vm: *bun.jsc.VM, module_key: *const IdentifierArray, source_code: *const SourceCode, declared_variables: *VariableEnvironment, lexical_variables: *VariableEnvironment, has_import_meta: bool, is_typescript: bool, has_tla: bool) *JSModuleRecord; - pub const create = JSC_JSModuleRecord__create; - - extern fn JSC_JSModuleRecord__declaredVariables(module_record: *JSModuleRecord) *VariableEnvironment; - pub const declaredVariables = JSC_JSModuleRecord__declaredVariables; - extern fn JSC_JSModuleRecord__lexicalVariables(module_record: *JSModuleRecord) *VariableEnvironment; - pub const lexicalVariables = JSC_JSModuleRecord__lexicalVariables; - - extern fn JSC_JSModuleRecord__addIndirectExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, export_name: StringID, import_name: StringID, module_name: StringID) void; - pub const addIndirectExport = JSC_JSModuleRecord__addIndirectExport; - extern fn JSC_JSModuleRecord__addLocalExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, export_name: StringID, local_name: StringID) void; - pub const addLocalExport = JSC_JSModuleRecord__addLocalExport; - extern fn JSC_JSModuleRecord__addNamespaceExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, export_name: StringID, module_name: StringID) void; - pub const addNamespaceExport = JSC_JSModuleRecord__addNamespaceExport; - extern fn JSC_JSModuleRecord__addStarExport(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void; - pub const addStarExport = JSC_JSModuleRecord__addStarExport; - - extern fn JSC_JSModuleRecord__addRequestedModuleNullAttributesPtr(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void; - pub const addRequestedModuleNullAttributesPtr = JSC_JSModuleRecord__addRequestedModuleNullAttributesPtr; - extern fn JSC_JSModuleRecord__addRequestedModuleJavaScript(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void; - pub const addRequestedModuleJavaScript = JSC_JSModuleRecord__addRequestedModuleJavaScript; - extern fn JSC_JSModuleRecord__addRequestedModuleWebAssembly(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void; - pub const addRequestedModuleWebAssembly = JSC_JSModuleRecord__addRequestedModuleWebAssembly; - extern fn JSC_JSModuleRecord__addRequestedModuleJSON(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID) void; - pub const addRequestedModuleJSON = JSC_JSModuleRecord__addRequestedModuleJSON; - extern fn JSC_JSModuleRecord__addRequestedModuleHostDefined(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, module_name: StringID, host_defined_import_type: StringID) void; - pub const addRequestedModuleHostDefined = JSC_JSModuleRecord__addRequestedModuleHostDefined; - - extern fn JSC_JSModuleRecord__addImportEntrySingle(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, import_name: StringID, local_name: StringID, module_name: StringID) void; - pub const addImportEntrySingle = JSC_JSModuleRecord__addImportEntrySingle; - extern fn JSC_JSModuleRecord__addImportEntrySingleTypeScript(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, import_name: StringID, local_name: StringID, module_name: StringID) void; - pub const addImportEntrySingleTypeScript = JSC_JSModuleRecord__addImportEntrySingleTypeScript; - extern fn JSC_JSModuleRecord__addImportEntryNamespace(module_record: *JSModuleRecord, identifier_array: *IdentifierArray, import_name: StringID, local_name: StringID, module_name: StringID) void; - pub const addImportEntryNamespace = JSC_JSModuleRecord__addImportEntryNamespace; -}; - -const bun = @import("bun"); -const DiffFormatter = @import("../runtime/test_runner/diff_format.zig").DiffFormatter; - -const analyze = @import("../bundler/analyze_transpiled_module.zig"); -const ModuleInfoDeserialized = analyze.ModuleInfoDeserialized; -const StringID = analyze.StringID; diff --git a/src/bundler_jsc/options_jsc.zig b/src/bundler_jsc/options_jsc.zig deleted file mode 100644 index 08706d527003..000000000000 --- a/src/bundler_jsc/options_jsc.zig +++ /dev/null @@ -1,70 +0,0 @@ -//! `fromJS` bridges for `bun.options.{Target,Format,Loader}` and `CompileTarget`. -//! Keeps `src/bundler/` free of `JSValue`/`JSGlobalObject` references. - -pub fn targetFromJS(global: *jsc.JSGlobalObject, value: jsc.JSValue) bun.JSError!?options.Target { - if (!value.isString()) { - return global.throwInvalidArguments("target must be a string", .{}); - } - return options.Target.Map.fromJS(global, value); -} - -pub fn formatFromJS(global: *jsc.JSGlobalObject, format: jsc.JSValue) bun.JSError!?options.Format { - if (format.isUndefinedOrNull()) return null; - - if (!format.isString()) { - return global.throwInvalidArguments("format must be a string", .{}); - } - - return try options.Format.Map.fromJS(global, format) orelse { - return global.throwInvalidArguments("Invalid format - must be esm, cjs, or iife", .{}); - }; -} - -pub fn loaderFromJS(global: *jsc.JSGlobalObject, loader: jsc.JSValue) bun.JSError!?options.Loader { - if (loader.isUndefinedOrNull()) return null; - - if (!loader.isString()) { - return global.throwInvalidArguments("loader must be a string", .{}); - } - - var zig_str = jsc.ZigString.init(""); - try loader.toZigString(&zig_str, global); - if (zig_str.len == 0) return null; - - const slice = zig_str.toSlice(bun.default_allocator); - defer slice.deinit(); - - return options.Loader.fromString(slice.slice()) orelse { - return global.throwInvalidArguments("invalid loader - must be js, jsx, tsx, ts, css, file, toml, yaml, wasm, bunsh, json, or md", .{}); - }; -} - -// ── CompileTarget ────────────────────────────────────────────────────────── -pub fn compileTargetFromJS(global: *jsc.JSGlobalObject, value: jsc.JSValue) bun.JSError!CompileTarget { - const slice = try value.toSlice(global, bun.default_allocator); - defer slice.deinit(); - if (!strings.hasPrefixComptime(slice.slice(), "bun-")) { - return global.throwInvalidArguments("Expected compile target to start with 'bun-', got {s}", .{slice.slice()}); - } - - return compileTargetFromSlice(global, slice.slice()); -} - -pub fn compileTargetFromSlice(global: *jsc.JSGlobalObject, slice_with_bun_prefix: []const u8) bun.JSError!CompileTarget { - const slice = slice_with_bun_prefix["bun-".len..]; - const target_parsed = CompileTarget.tryFrom(slice) catch { - return global.throwInvalidArguments("Unknown compile target: {s}", .{slice_with_bun_prefix}); - }; - if (!target_parsed.isSupported()) { - return global.throwInvalidArguments("Unsupported compile target: {s}", .{slice_with_bun_prefix}); - } - - return target_parsed; -} - -const CompileTarget = @import("../options_types/CompileTarget.zig"); - -const bun = @import("bun"); -const jsc = bun.jsc; -const options = bun.options; -const strings = bun.strings; diff --git a/src/bundler_jsc/output_file_jsc.zig b/src/bundler_jsc/output_file_jsc.zig deleted file mode 100644 index 597b41461ccf..000000000000 --- a/src/bundler_jsc/output_file_jsc.zig +++ /dev/null @@ -1,214 +0,0 @@ -//! `toJS`/`toBlob` bridges for `bundler/OutputFile.zig`. Aliased back so -//! call sites stay `output.toJS(global)`. - -pub const SavedFile = struct { - pub fn toJS( - globalThis: *jsc.JSGlobalObject, - path: []const u8, - byte_size: usize, - ) jsc.JSValue { - const mime_type = globalThis.bunVM().mimeType(path); - const store = jsc.WebCore.Blob.Store.initFile( - jsc.Node.PathOrFileDescriptor{ - .path = jsc.Node.PathLike{ - .string = bun.PathString.init(path), - }, - }, - mime_type, - bun.default_allocator, - ) catch unreachable; - - var blob = bun.default_allocator.create(jsc.WebCore.Blob) catch unreachable; - blob.* = jsc.WebCore.Blob.initWithStore(store, globalThis); - if (mime_type) |mime| { - blob.content_type = mime.value; - } - blob.size = @as(jsc.WebCore.Blob.SizeType, @truncate(byte_size)); - blob.allocator = bun.default_allocator; - return blob.toJS(globalThis); - } -}; - -pub fn toJS( - this: *OutputFile, - owned_pathname: ?[]const u8, - globalObject: *jsc.JSGlobalObject, -) bun.jsc.JSValue { - return switch (this.value) { - .move, .pending => @panic("Unexpected pending output file"), - .noop => .js_undefined, - .copy => |copy| brk: { - const file_blob = jsc.WebCore.Blob.Store.initFile( - if (copy.fd.isValid()) - jsc.Node.PathOrFileDescriptor{ - .fd = copy.fd, - } - else - jsc.Node.PathOrFileDescriptor{ - .path = jsc.Node.PathLike{ .string = bun.PathString.init(globalObject.allocator().dupe(u8, copy.pathname) catch unreachable) }, - }, - this.loader.toMimeType(&.{owned_pathname orelse ""}), - globalObject.allocator(), - ) catch |err| { - Output.panic("error: Unable to create file blob: \"{s}\"", .{@errorName(err)}); - }; - - var build_output = bun.new(jsc.API.BuildArtifact, .{ - .blob = jsc.WebCore.Blob.initWithStore(file_blob, globalObject), - .hash = this.hash, - .loader = this.input_loader, - .output_kind = this.output_kind, - .path = bun.default_allocator.dupe(u8, copy.pathname) catch @panic("Failed to allocate path"), - }); - - this.value = .{ - .buffer = .{ - .allocator = bun.default_allocator, - .bytes = &.{}, - }, - }; - - break :brk build_output.toJS(globalObject); - }, - .saved => brk: { - var build_output = bun.default_allocator.create(jsc.API.BuildArtifact) catch @panic("Unable to allocate Artifact"); - const path_to_use = owned_pathname orelse this.src_path.text; - - const file_blob = jsc.WebCore.Blob.Store.initFile( - jsc.Node.PathOrFileDescriptor{ - .path = jsc.Node.PathLike{ .string = bun.PathString.init(owned_pathname orelse (bun.default_allocator.dupe(u8, this.src_path.text) catch unreachable)) }, - }, - this.loader.toMimeType(&.{owned_pathname orelse ""}), - globalObject.allocator(), - ) catch |err| { - Output.panic("error: Unable to create file blob: \"{s}\"", .{@errorName(err)}); - }; - - this.value = .{ - .buffer = .{ - .allocator = bun.default_allocator, - .bytes = &.{}, - }, - }; - - build_output.* = jsc.API.BuildArtifact{ - .blob = jsc.WebCore.Blob.initWithStore(file_blob, globalObject), - .hash = this.hash, - .loader = this.input_loader, - .output_kind = this.output_kind, - .path = bun.default_allocator.dupe(u8, path_to_use) catch @panic("Failed to allocate path"), - }; - - break :brk build_output.toJS(globalObject); - }, - .buffer => |buffer| brk: { - var blob = jsc.WebCore.Blob.init(@constCast(buffer.bytes), buffer.allocator, globalObject); - if (blob.store) |store| { - store.mime_type = this.loader.toMimeType(&.{owned_pathname orelse ""}); - blob.content_type = store.mime_type.value; - } else { - blob.content_type = this.loader.toMimeType(&.{owned_pathname orelse ""}).value; - } - - blob.size = @as(jsc.WebCore.Blob.SizeType, @truncate(buffer.bytes.len)); - - var build_output = bun.default_allocator.create(jsc.API.BuildArtifact) catch @panic("Unable to allocate Artifact"); - build_output.* = jsc.API.BuildArtifact{ - .blob = blob, - .hash = this.hash, - .loader = this.input_loader, - .output_kind = this.output_kind, - .path = owned_pathname orelse bun.default_allocator.dupe(u8, this.src_path.text) catch unreachable, - }; - - this.value = .{ - .buffer = .{ - .allocator = bun.default_allocator, - .bytes = &.{}, - }, - }; - - break :brk build_output.toJS(globalObject); - }, - }; -} - -pub fn toBlob( - this: *OutputFile, - allocator: std.mem.Allocator, - globalThis: *jsc.JSGlobalObject, -) !jsc.WebCore.Blob { - return switch (this.value) { - .move, .pending => @panic("Unexpected pending output file"), - .noop => @panic("Cannot convert noop output file to blob"), - .copy => |copy| brk: { - const file_blob = try jsc.WebCore.Blob.Store.initFile( - if (copy.fd.isValid()) - jsc.Node.PathOrFileDescriptor{ - .fd = copy.fd, - } - else - jsc.Node.PathOrFileDescriptor{ - .path = jsc.Node.PathLike{ .string = bun.PathString.init(allocator.dupe(u8, copy.pathname) catch unreachable) }, - }, - this.loader.toMimeType(&.{ this.dest_path, this.src_path.text }), - allocator, - ); - - this.value = .{ - .buffer = .{ - .allocator = bun.default_allocator, - .bytes = &.{}, - }, - }; - - break :brk jsc.WebCore.Blob.initWithStore(file_blob, globalThis); - }, - .saved => brk: { - const file_blob = try jsc.WebCore.Blob.Store.initFile( - jsc.Node.PathOrFileDescriptor{ - .path = jsc.Node.PathLike{ .string = bun.PathString.init(allocator.dupe(u8, this.src_path.text) catch unreachable) }, - }, - this.loader.toMimeType(&.{ this.dest_path, this.src_path.text }), - allocator, - ); - - this.value = .{ - .buffer = .{ - .allocator = bun.default_allocator, - .bytes = &.{}, - }, - }; - - break :brk jsc.WebCore.Blob.initWithStore(file_blob, globalThis); - }, - .buffer => |buffer| brk: { - var blob = jsc.WebCore.Blob.init(@constCast(buffer.bytes), buffer.allocator, globalThis); - if (blob.store) |store| { - store.mime_type = this.loader.toMimeType(&.{ this.dest_path, this.src_path.text }); - blob.content_type = store.mime_type.value; - } else { - blob.content_type = this.loader.toMimeType(&.{ this.dest_path, this.src_path.text }).value; - } - - this.value = .{ - .buffer = .{ - .allocator = bun.default_allocator, - .bytes = &.{}, - }, - }; - - blob.size = @as(jsc.WebCore.Blob.SizeType, @truncate(buffer.bytes.len)); - break :brk blob; - }, - }; -} - -const string = []const u8; - -const OutputFile = @import("../bundler/OutputFile.zig"); -const std = @import("std"); - -const bun = @import("bun"); -const Output = bun.Output; -const jsc = bun.jsc; diff --git a/src/bundler_jsc/source_map_mode_jsc.zig b/src/bundler_jsc/source_map_mode_jsc.zig deleted file mode 100644 index c8f83a773fca..000000000000 --- a/src/bundler_jsc/source_map_mode_jsc.zig +++ /dev/null @@ -1,27 +0,0 @@ -//! `fromJS` for `bun.schema.api.SourceMapMode` — kept out of -//! `options_types/schema.zig` so that file has no `JSGlobalObject`/`JSValue` -//! references. - -pub fn sourceMapModeFromJS(global: *bun.jsc.JSGlobalObject, value: bun.jsc.JSValue) bun.JSError!?SourceMapMode { - if (value.isString()) { - const str = try value.toSliceOrNull(global); - defer str.deinit(); - const utf8 = str.slice(); - if (bun.strings.eqlComptime(utf8, "none")) { - return .none; - } - if (bun.strings.eqlComptime(utf8, "inline")) { - return .@"inline"; - } - if (bun.strings.eqlComptime(utf8, "external")) { - return .external; - } - if (bun.strings.eqlComptime(utf8, "linked")) { - return .linked; - } - } - return null; -} - -const bun = @import("bun"); -const SourceMapMode = bun.schema.api.SourceMapMode; diff --git a/src/c-headers-for-zig.h b/src/c-headers-for-zig.h deleted file mode 100644 index 29d0b1fb6c20..000000000000 --- a/src/c-headers-for-zig.h +++ /dev/null @@ -1,74 +0,0 @@ -// Aggregated C includes for automatic translation into bindings. -// Prefer adding includes -// to this file instead of manually porting struct definitions. -// By using automatic translation, differences -// between platforms and subtle mistakes can be avoided. -// -// When this file is translated, these macros are defined: -// - WINDOWS -// - DARWIN -// - LINUX -// - FREEBSD -// - POSIX - -// For `POSIX_SPAWN_SETSID` and some other non-POSIX extensions in glibc -#if LINUX -#define _GNU_SOURCE -#endif - -// OnBeforeParseResult, etc... -#include "../packages/bun-native-bundler-plugin-api/bundler_plugin.h" - -#if POSIX -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#if DARWIN -#include -#include -#include -#include -#include -#include -#include -#include -#include -#elif LINUX -#include -#include -#include -#elif FREEBSD -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#if WINDOWS -#include -#include -#endif - -#undef lstat -#undef fstat -#undef stat - -#include -#include diff --git a/src/cares_sys/c_ares.zig b/src/cares_sys/c_ares.zig deleted file mode 100644 index 83936f493dcf..000000000000 --- a/src/cares_sys/c_ares.zig +++ /dev/null @@ -1,1553 +0,0 @@ -pub const socklen_t = c.socklen_t; -pub const ares_ssize_t = isize; -pub const ares_socket_t = if (bun.Environment.isWindows) std.os.windows.ws2_32.SOCKET else c_int; -pub const ares_sock_state_cb = ?*const fn (?*anyopaque, ares_socket_t, c_int, c_int) callconv(.c) void; -pub const struct_apattern = opaque {}; - -pub const AF = std.posix.AF; - -pub const NSClass = enum(c_int) { - /// Cookie. - ns_c_invalid = 0, - /// Internet. - ns_c_in = 1, - /// unallocated/unsupported. - ns_c_2 = 2, - /// MIT Chaos-net. - ns_c_chaos = 3, - /// MIT Hesiod. - ns_c_hs = 4, - /// Query class values which do not appear in resource records - /// for prereq. sections in update requests - ns_c_none = 254, - /// Wildcard match. - ns_c_any = 255, - ns_c_max = 65536, -}; - -pub const NSType = enum(c_int) { - /// Cookie. - ns_t_invalid = 0, - /// Host address. - ns_t_a = 1, - /// Authoritative server. - ns_t_ns = 2, - /// Mail destination. - ns_t_md = 3, - /// Mail forwarder. - ns_t_mf = 4, - /// Canonical name. - ns_t_cname = 5, - /// Start of authority zone. - ns_t_soa = 6, - /// Mailbox domain name. - ns_t_mb = 7, - /// Mail group member. - ns_t_mg = 8, - /// Mail rename name. - ns_t_mr = 9, - /// Null resource record. - ns_t_null = 10, - /// Well known service. - ns_t_wks = 11, - /// Domain name pointer. - ns_t_ptr = 12, - /// Host information. - ns_t_hinfo = 13, - /// Mailbox information. - ns_t_minfo = 14, - /// Mail routing information. - ns_t_mx = 15, - /// Text strings. - ns_t_txt = 16, - /// Responsible person. - ns_t_rp = 17, - /// AFS cell database. - ns_t_afsdb = 18, - /// X_25 calling address. - ns_t_x25 = 19, - /// ISDN calling address. - ns_t_isdn = 20, - /// Router. - ns_t_rt = 21, - /// NSAP address. - ns_t_nsap = 22, - /// Reverse NSAP lookup (deprecated). - ns_t_nsap_ptr = 23, - /// Security signature. - ns_t_sig = 24, - /// Security key. - ns_t_key = 25, - /// X.400 mail mapping. - ns_t_px = 26, - /// Geographical position (withdrawn). - ns_t_gpos = 27, - /// Ip6 Address. - ns_t_aaaa = 28, - /// Location Information. - ns_t_loc = 29, - /// Next domain (security). - ns_t_nxt = 30, - /// Endpoint identifier. - ns_t_eid = 31, - /// Nimrod Locator. - ns_t_nimloc = 32, - /// Server Selection. - ns_t_srv = 33, - /// ATM Address - ns_t_atma = 34, - /// Naming Authority PoinTeR - ns_t_naptr = 35, - /// Key Exchange - ns_t_kx = 36, - /// Certification record - ns_t_cert = 37, - /// IPv6 address (deprecates AAAA) - ns_t_a6 = 38, - /// Non-terminal DNAME (for IPv6) - ns_t_dname = 39, - /// Kitchen sink (experimentatl) - ns_t_sink = 40, - /// EDNS0 option (meta-RR) - ns_t_opt = 41, - /// Address prefix list (RFC3123) - ns_t_apl = 42, - /// Delegation Signer (RFC4034) - ns_t_ds = 43, - /// SSH Key Fingerprint (RFC4255) - ns_t_sshfp = 44, - /// Resource Record Signature (RFC4034) - ns_t_rrsig = 46, - /// Next Secure (RFC4034) - ns_t_nsec = 47, - /// DNS Public Key (RFC4034) - ns_t_dnskey = 48, - /// Transaction key - ns_t_tkey = 249, - /// Transaction signature. - ns_t_tsig = 250, - /// Incremental zone transfer. - ns_t_ixfr = 251, - /// Transfer zone of authority. - ns_t_axfr = 252, - /// Transfer mailbox records. - ns_t_mailb = 253, - /// Transfer mail agent records. - ns_t_maila = 254, - /// Wildcard match. - ns_t_any = 255, - /// Uniform Resource Identifier (RFC7553) - ns_t_uri = 256, - /// Certification Authority Authorization. - ns_t_caa = 257, - ns_t_max = 65536, - _, -}; -pub const struct_ares_server_failover_options = extern struct { - retry_chance: c_ushort = 0, - retry_delay: usize = 0, -}; -const ARES_EVSYS_DEFAULT: c_int = 0; -const ARES_EVSYS_WIN32: c_int = 1; -const ARES_EVSYS_EPOLL: c_int = 2; -const ARES_EVSYS_KQUEUE: c_int = 3; -const ARES_EVSYS_POLL: c_int = 4; -const ARES_EVSYS_SELECT: c_int = 5; -const ares_evsys_t = c_uint; -pub const Options = extern struct { - flags: c_int = 0, - timeout: c_int = 0, - tries: c_int = 0, - ndots: c_int = 0, - udp_port: c_ushort = 0, - tcp_port: c_ushort = 0, - socket_send_buffer_size: c_int = 0, - socket_receive_buffer_size: c_int = 0, - servers: [*c]struct_in_addr = null, - nservers: c_int = 0, - domains: ?[*][*:0]u8 = null, - ndomains: c_int = 0, - lookups: ?[*:0]u8 = null, - sock_state_cb: ares_sock_state_cb = null, - sock_state_cb_data: ?*anyopaque = null, - sortlist: ?*struct_apattern = null, - nsort: c_int = 0, - ednspsz: c_int = 0, - resolvconf_path: ?[*:0]u8 = null, - hosts_path: ?[*:0]u8 = null, - udp_max_queries: c_int = 0, - maxtimeout: c_int = 0, - qcache_max_ttl: c_uint = 0, - evsys: ares_evsys_t = 0, - server_failover_opts: struct_ares_server_failover_options = @import("std").mem.zeroes(struct_ares_server_failover_options), -}; - -pub const struct_hostent = extern struct { - h_name: ?[*:0]u8, - h_aliases: ?[*:null]?[*:0]u8, - h_addrtype: hostent_int, - h_length: hostent_int, - h_addr_list: ?[*:null]?[*:0]u8, - - // hostent in glibc uses int for h_addrtype and h_length, whereas hostent in winsock2.h uses short. - const hostent_int = if (bun.Environment.isWindows) c_short else c_int; - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").hostentToJSResponse; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_hostent) void; - } - - pub fn hostCallbackWrapper( - comptime Type: type, - comptime function: Callback(Type), - ) ares_host_callback { - return &struct { - pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, hostent: ?*struct_hostent) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - function(this, null, timeouts, hostent); - } - }.handle; - } - - pub fn callbackWrapper( - comptime lookup_name: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var start: [*c]struct_hostent = undefined; - if (comptime strings.eqlComptime(lookup_name, "cname")) { - var addrttls: [256]struct_ares_addrttl = undefined; - var naddrttls: i32 = 256; - - const result = ares_parse_a_reply(buffer, buffer_length, &start, &addrttls, &naddrttls); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, start); - } else if (comptime strings.eqlComptime(lookup_name, "ns")) { - const result = ares_parse_ns_reply(buffer, buffer_length, &start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, start); - } else if (comptime strings.eqlComptime(lookup_name, "ptr")) { - const result = ares_parse_ptr_reply(buffer, buffer_length, null, 0, AF.INET, &start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, start); - } else { - @compileError(std.fmt.comptimePrint("Unsupported struct_hostent record type: {s}", .{lookup_name})); - } - } - }.handle; - } - - pub fn deinit(this: *struct_hostent) void { - ares_free_hostent(this); - } -}; - -pub const hostent_with_ttls = struct { - hostent: *struct_hostent, - ttls: [256]c_int = [_]c_int{-1} ** 256, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").hostentWithTtlsToJSResponse; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*hostent_with_ttls) void; - } - - pub fn hostCallbackWrapper( - comptime Type: type, - comptime function: Callback(Type), - ) ares_host_callback { - return &struct { - pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, hostent: ?*hostent_with_ttls) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - function(this, null, timeouts, hostent); - } - }.handle; - } - - pub fn callbackWrapper( - comptime lookup_name: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - switch (parse(lookup_name, buffer, buffer_length)) { - .result => |result| function(this, null, timeouts, result), - .err => |err| function(this, err, timeouts, null), - } - } - }.handle; - } - - pub fn parse(comptime lookup_name: []const u8, buffer: [*c]u8, buffer_length: c_int) jsc.Node.Maybe(*hostent_with_ttls, Error) { - var start: ?*struct_hostent = null; - - if (comptime strings.eqlComptime(lookup_name, "a")) { - var addrttls: [256]struct_ares_addrttl = undefined; - var naddrttls: c_int = 256; - - const result = ares_parse_a_reply(buffer, buffer_length, &start, &addrttls, &naddrttls); - if (result != ARES_SUCCESS) { - return .{ .err = Error.get(result).? }; - } - var with_ttls = bun.handleOom(bun.default_allocator.create(hostent_with_ttls)); - with_ttls.hostent = start.?; - for (addrttls[0..@intCast(naddrttls)], 0..) |ttl, i| { - with_ttls.ttls[i] = ttl.ttl; - } - return .{ .result = with_ttls }; - } - - if (comptime strings.eqlComptime(lookup_name, "aaaa")) { - var addr6ttls: [256]struct_ares_addr6ttl = undefined; - var naddr6ttls: c_int = 256; - - const result = ares_parse_aaaa_reply(buffer, buffer_length, &start, &addr6ttls, &naddr6ttls); - if (result != ARES_SUCCESS) { - return .{ .err = Error.get(result).? }; - } - var with_ttls = bun.handleOom(bun.default_allocator.create(hostent_with_ttls)); - with_ttls.hostent = start.?; - for (addr6ttls[0..@intCast(naddr6ttls)], 0..) |ttl, i| { - with_ttls.ttls[i] = ttl.ttl; - } - return .{ .result = with_ttls }; - } - - @compileError(std.fmt.comptimePrint("Unsupported hostent_with_ttls record type: {s}", .{lookup_name})); - } - - pub fn deinit(this: *hostent_with_ttls) void { - this.hostent.deinit(); - bun.default_allocator.destroy(this); - } -}; - -pub const struct_nameinfo = extern struct { - node: [*c]u8, - service: [*c]u8, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").nameinfoToJSResponse; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, node: ?struct_nameinfo) void; - } - - pub fn CallbackWrapper( - comptime Type: type, - comptime function: Callback(Type), - ) ares_nameinfo_callback { - return &struct { - pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, node: [*c]u8, service: [*c]u8) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - function(this, null, timeouts, .{ .node = node, .service = service }); - return; - } - }.handle; - } -}; - -pub const struct_timeval = std.posix.timeval; -pub const struct_Channeldata = opaque {}; -pub const AddrInfo_cname = extern struct { - ttl: c_int, - alias: [*c]u8, - name: [*c]u8, - next: [*c]AddrInfo_cname, -}; -pub const AddrInfo_node = extern struct { - ttl: c_int = 0, - flags: c_int = 0, - family: c_int = 0, - socktype: c_int = 0, - protocol: c_int = 0, - addrlen: ares_socklen_t, - addr: ?*struct_sockaddr = null, - next: ?*AddrInfo_node = null, - - pub fn count(this: *AddrInfo_node) u32 { - var len: u32 = 0; - var node: ?*AddrInfo_node = this; - while (node != null) : (node = node.?.next) { - len += 1; - } - return len; - } -}; - -pub const AddrInfo = extern struct { - cnames_: [*c]AddrInfo_cname = null, - node: ?*AddrInfo_node = null, - name_: ?[*:0]u8 = null, - - pub const toJSArray = @import("../runtime/dns_jsc/cares_jsc.zig").addrInfoToJSArray; - - pub inline fn name(this: *const AddrInfo) []const u8 { - const name_ = this.name_ orelse return ""; - return bun.span(name_); - } - - pub inline fn cnames(this: *const AddrInfo) []const AddrInfo_node { - const cnames_ = this.cnames_ orelse return &.{}; - return bun.span(cnames_); - } - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*AddrInfo) void; - } - - pub fn callbackWrapper( - comptime Type: type, - comptime function: Callback(Type), - ) ares_addrinfo_callback { - return &struct { - pub fn handleAddrInfo(ctx: ?*anyopaque, status: c_int, timeouts: c_int, addr_info: ?*AddrInfo) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - - function(this, Error.get(status), timeouts, addr_info); - } - }.handleAddrInfo; - } - - pub fn deinit(this: *AddrInfo) void { - ares_freeaddrinfo(this); - } -}; -pub const AddrInfo_hints = extern struct { - ai_flags: c_int = 0, - ai_family: c_int = 0, - ai_socktype: c_int = 0, - ai_protocol: c_int = 0, - - pub fn isEmpty(this: AddrInfo_hints) bool { - return this.ai_flags == 0 and this.ai_family == 0 and this.ai_socktype == 0 and this.ai_protocol == 0; - } -}; - -pub const ChannelOptions = struct { - timeout: ?i32 = null, - tries: ?i32 = null, -}; - -pub const Channel = opaque { - pub fn init(comptime Container: type, this: *Container, options: ChannelOptions) ?Error { - var channel: *Channel = undefined; - - libraryInit(); - - const SockStateWrap = struct { - pub fn onSockState(ctx: ?*anyopaque, socket: ares_socket_t, readable: c_int, writable: c_int) callconv(.c) void { - const container = bun.cast(*Container, ctx.?); - Container.onDNSSocketState(container, socket, readable != 0, writable != 0); - } - }; - - var opts = bun.zero(Options); - - // Android note: c-ares can't auto-discover servers (no /etc/resolv.conf, - // no JNI), so it falls back to 127.0.0.1 and queries time out. We do - // NOT set ARES_FLAG_NO_DFLT_SVR here — that makes init fail with - // ENOSERVER, which breaks dns.setServers() (it needs an initialized - // channel to call ares_set_servers_ports). Letting the 127.0.0.1 - // default stand means setServers() works as the documented workaround. - opts.flags = ARES_FLAG_NOCHECKRESP; - opts.sock_state_cb = &SockStateWrap.onSockState; - opts.sock_state_cb_data = @as(*anyopaque, @ptrCast(this)); - opts.timeout = options.timeout orelse -1; - opts.tries = options.tries orelse 4; - - const optmask: c_int = - ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | - ARES_OPT_SOCK_STATE_CB | ARES_OPT_TRIES; - - if (Error.get(ares_init_options(&channel, &opts, optmask))) |err| { - ares_library_cleanup(); - return err; - } - - this.channel = channel; - return null; - } - - pub fn deinit(this: *Channel) void { - ares_destroy(this); - } - - /// - ///The ares_getaddrinfo function initiates a host query by name on the name service channel identified by channel. The name and service parameters give the hostname and service as NULL-terminated C strings. The hints parameter is an ares_addrinfo_hints structure: - /// - ///struct ares_addrinfo_hints { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; }; - /// - ///ai_family Specifies desired address family. AF_UNSPEC means return both AF_INET and AF_INET6. - /// - ///ai_socktype Specifies desired socket type, for example SOCK_STREAM or SOCK_DGRAM. Setting this to 0 means any type. - /// - ///ai_protocol Setting this to 0 means any protocol. - /// - ///ai_flags Specifies additional options, see below. - /// - ///ARES_AI_NUMERICSERV If this option is set service field will be treated as a numeric value. - /// - ///ARES_AI_CANONNAME The ares_addrinfo structure will return a canonical names list. - /// - ///ARES_AI_NOSORT Result addresses will not be sorted and no connections to resolved addresses will be attempted. - /// - ///ARES_AI_ENVHOSTS Read hosts file path from the environment variable CARES_HOSTS . - /// - ///When the query is complete or has failed, the ares library will invoke callback. Completion or failure of the query may happen immediately, or may happen during a later call to ares_process, ares_destroy or ares_cancel. - /// - ///The callback argument arg is copied from the ares_getaddrinfo argument arg. The callback argument status indicates whether the query succeeded and, if not, how it failed. It may have any of the following values: - /// - ///ARES_SUCCESS The host lookup completed successfully. - /// - ///ARES_ENOTIMP The ares library does not know how to find addresses of type family. - /// - ///ARES_ENOTFOUND The name was not found. - /// - ///ARES_ENOMEM Memory was exhausted. - /// - ///ARES_ECANCELLED The query was cancelled. - /// - ///ARES_EDESTRUCTION The name service channel channel is being destroyed; the query will not be completed. - /// - ///On successful completion of the query, the callback argument result points to a struct ares_addrinfo which contains two linked lists, one with resolved addresses and another with canonical names. Also included is the official name of the host (analogous to gethostbyname() h_name). - /// - ///struct ares_addrinfo { struct ares_addrinfo_cname *cnames; struct ares_addrinfo_node *nodes; char *name; }; - /// - ///ares_addrinfo_node structure is similar to RFC 3493 addrinfo, but without canonname and with extra ttl field. - /// - ///struct ares_addrinfo_node { int ai_ttl; int ai_flags; int ai_family; int ai_socktype; int ai_protocol; ares_socklen_t ai_addrlen; struct sockaddr *ai_addr; struct ares_addrinfo_node *ai_next; }; - /// - ///ares_addrinfo_cname structure is a linked list of CNAME records where ttl is a time to live alias is a label of the resource record and name is a value (canonical name) of the resource record. See RFC 2181 10.1.1. CNAME terminology. - /// - ///struct ares_addrinfo_cname { int ttl; char *alias; char *name; struct ares_addrinfo_cname *next; }; - /// - ///The reserved memory has to be deleted by ares_freeaddrinfo. - /// - ///The result is sorted according to RFC 6724 except: - Rule 3 (Avoid deprecated addresses) - Rule 4 (Prefer home addresses) - Rule 7 (Prefer native transport) - /// - ///Please note that the function will attempt a connection on each of the resolved addresses as per RFC 6724. - /// - pub fn getAddrInfo(this: *Channel, host: []const u8, port: u16, hints: []const AddrInfo_hints, comptime Type: type, ctx: *Type, comptime callback: AddrInfo.Callback(Type)) void { - var host_buf: [1024]u8 = undefined; - var port_buf: [52]u8 = undefined; - const host_ptr: ?[*:0]const u8 = brk: { - const len = @min(host.len, host_buf.len - 1); - @memcpy(host_buf[0..len], host[0..len]); - host_buf[len] = 0; - break :brk host_buf[0..len :0].ptr; - }; - - const port_ptr: ?[*:0]const u8 = brk: { - if (port == 0) { - break :brk null; - } - - break :brk (std.fmt.bufPrintZ(&port_buf, "{d}", .{port}) catch unreachable).ptr; - }; - - var hints_buf: [3]AddrInfo_hints = bun.zero([3]AddrInfo_hints); - for (hints[0..@min(hints.len, 2)], 0..) |hint, i| { - hints_buf[i] = hint; - } - const hints_: [*c]const AddrInfo_hints = if (hints.len > 0) &hints_buf else null; - ares_getaddrinfo(this, host_ptr, port_ptr, hints_, AddrInfo.callbackWrapper(Type, callback), ctx); - } - - pub fn resolve(this: *Channel, name: []const u8, comptime lookup_name: []const u8, comptime Type: type, ctx: *Type, comptime cares_type: type, comptime callback: cares_type.Callback(Type)) void { - if (name.len >= 1023 or (name.len == 0 and !(bun.strings.eqlComptime(lookup_name, "ns") or bun.strings.eqlComptime(lookup_name, "soa")))) { - return cares_type.callbackWrapper(lookup_name, Type, callback).?(ctx, ARES_EBADNAME, 0, null, 0); - } - - var name_buf: [1024]u8 = undefined; - const name_ptr: [*:0]const u8 = brk: { - const len = @min(name.len, name_buf.len - 1); - @memcpy(name_buf[0..len], name[0..len]); - - name_buf[len] = 0; - break :brk name_buf[0..len :0]; - }; - - const field_name = comptime std.fmt.comptimePrint("ns_t_{s}", .{lookup_name}); - ares_query(this, name_ptr, NSClass.ns_c_in, @field(NSType, field_name), cares_type.callbackWrapper(lookup_name, Type, callback), ctx); - } - - pub fn getHostByAddr(this: *Channel, ip_addr: []const u8, comptime Type: type, ctx: *Type, comptime callback: struct_hostent.Callback(Type)) void { - // "0000:0000:0000:0000:0000:ffff:192.168.100.228".length = 45 - const buf_size = 46; - var addr_buf: [buf_size]u8 = undefined; - const addr_ptr: ?[*:0]const u8 = brk: { - if (ip_addr.len == 0 or ip_addr.len >= buf_size) { - break :brk null; - } - const len = @min(ip_addr.len, addr_buf.len - 1); - @memcpy(addr_buf[0..len], ip_addr[0..len]); - - addr_buf[len] = 0; - break :brk addr_buf[0..len :0]; - }; - - // https://c-ares.org/ares_inet_pton.html - // https://github.com/c-ares/c-ares/blob/7f3262312f246556d8c1bdd8ccc1844847f42787/src/lib/ares_gethostbyaddr.c#L71-L72 - // `ares_inet_pton` allows passing raw bytes as `dst`, - // which can avoid the use of `struct_in_addr` to reduce extra bytes. - var addr: [16]u8 = undefined; - if (addr_ptr != null) { - if (ares_inet_pton(AF.INET, addr_ptr, &addr) > 0) { - ares_gethostbyaddr(this, &addr, 4, AF.INET, struct_hostent.hostCallbackWrapper(Type, callback), ctx); - return; - } else if (ares_inet_pton(AF.INET6, addr_ptr, &addr) > 0) { - return ares_gethostbyaddr(this, &addr, 16, AF.INET6, struct_hostent.hostCallbackWrapper(Type, callback), ctx); - } - } - struct_hostent.hostCallbackWrapper(Type, callback).?(ctx, ARES_ENOTIMP, 0, null); - } - - // https://c-ares.org/ares_getnameinfo.html - pub fn getNameInfo(this: *Channel, sa: *std.posix.sockaddr, comptime Type: type, ctx: *Type, comptime callback: struct_nameinfo.Callback(Type)) void { - return ares_getnameinfo( - this, - sa, - if (sa.*.family == AF.INET) @sizeOf(std.posix.sockaddr.in) else @sizeOf(std.posix.sockaddr.in6), - // node returns ENOTFOUND for addresses like 255.255.255.255:80 - // So, it requires setting the ARES_NI_NAMEREQD flag - ARES_NI_NAMEREQD | ARES_NI_LOOKUPHOST | ARES_NI_LOOKUPSERVICE, - struct_nameinfo.CallbackWrapper(Type, callback), - ctx, - ); - } - - pub inline fn process(this: *Channel, fd: ares_socket_t, readable: bool, writable: bool) void { - ares_process_fd( - this, - if (readable) fd else ARES_SOCKET_BAD, - if (writable) fd else ARES_SOCKET_BAD, - ); - } -}; - -var ares_has_loaded = std.atomic.Value(bool).init(false); -fn libraryInit() void { - if (ares_has_loaded.swap(true, .monotonic)) - return; - - const rc = ares_library_init_mem( - ARES_LIB_INIT_ALL, - bun.mimalloc.mi_malloc, - bun.mimalloc.mi_free, - bun.mimalloc.mi_realloc, - ); - if (rc != ARES_SUCCESS) { - std.debug.panic("ares_library_init_mem failed: {d}", .{rc}); - unreachable; - } -} - -pub const ares_callback = ?*const fn (?*anyopaque, c_int, c_int, [*c]u8, c_int) callconv(.c) void; -pub const ares_host_callback = ?*const fn (?*anyopaque, c_int, c_int, ?*struct_hostent) callconv(.c) void; -pub const ares_nameinfo_callback = ?*const fn (?*anyopaque, c_int, c_int, [*c]u8, [*c]u8) callconv(.c) void; -pub const ares_sock_create_callback = ?*const fn (ares_socket_t, c_int, ?*anyopaque) callconv(.c) c_int; -pub const ares_sock_config_callback = ?*const fn (ares_socket_t, c_int, ?*anyopaque) callconv(.c) c_int; -pub const ares_addrinfo_callback = *const fn (?*anyopaque, c_int, c_int, ?*AddrInfo) callconv(.c) void; -pub extern fn ares_library_init(flags: c_int) c_int; -pub extern fn ares_library_init_mem(flags: c_int, amalloc: ?*const fn (usize) callconv(.c) ?*anyopaque, afree: ?*const fn (?*anyopaque) callconv(.c) void, arealloc: ?*const fn (?*anyopaque, usize) callconv(.c) ?*anyopaque) c_int; -pub extern fn ares_library_initialized() c_int; -pub extern fn ares_library_cleanup() void; -pub extern fn ares_version(version: [*c]c_int) [*c]const u8; -pub extern fn ares_init(channelptr: **Channel) c_int; -pub extern fn ares_init_options(channelptr: **Channel, options: ?*Options, optmask: c_int) c_int; -pub extern fn ares_save_options(channel: *Channel, options: ?*Options, optmask: *c_int) c_int; -pub extern fn ares_destroy_options(options: *Options) void; -pub extern fn ares_dup(dest: ?*Channel, src: *Channel) c_int; -pub extern fn ares_destroy(channel: *Channel) void; -pub extern fn ares_cancel(channel: *Channel) void; -pub extern fn ares_set_local_ip4(channel: *Channel, local_ip: c_uint) void; -pub extern fn ares_set_local_ip6(channel: *Channel, local_ip6: [*c]const u8) void; -pub extern fn ares_set_local_dev(channel: *Channel, local_dev_name: [*c]const u8) void; -pub extern fn ares_set_socket_callback(channel: *Channel, callback: ares_sock_create_callback, user_data: ?*anyopaque) void; -pub extern fn ares_set_socket_configure_callback(channel: *Channel, callback: ares_sock_config_callback, user_data: ?*anyopaque) void; -pub extern fn ares_set_sortlist(channel: *Channel, sortstr: [*c]const u8) c_int; -pub extern fn ares_getaddrinfo(channel: *Channel, node: ?[*:0]const u8, service: ?[*:0]const u8, hints: [*c]const AddrInfo_hints, callback: ares_addrinfo_callback, arg: ?*anyopaque) void; -pub extern fn ares_freeaddrinfo(ai: *AddrInfo) void; -pub const ares_socket_functions = extern struct { - socket: ?*const fn (c_int, c_int, c_int, ?*anyopaque) callconv(.c) ares_socket_t = null, - close: ?*const fn (ares_socket_t, ?*anyopaque) callconv(.c) c_int = null, - connect: ?*const fn (ares_socket_t, [*c]const struct_sockaddr, ares_socklen_t, ?*anyopaque) callconv(.c) c_int = null, - recvfrom: ?*const fn (ares_socket_t, ?*anyopaque, usize, c_int, [*c]struct_sockaddr, [*c]ares_socklen_t, ?*anyopaque) callconv(.c) ares_ssize_t = null, - sendv: ?*const fn (ares_socket_t, [*c]const iovec, c_int, ?*anyopaque) callconv(.c) ares_ssize_t = null, -}; -pub extern fn ares_set_socket_functions(channel: *Channel, funcs: ?*const ares_socket_functions, user_data: ?*anyopaque) void; -pub extern fn ares_send(channel: *Channel, qbuf: [*c]const u8, qlen: c_int, callback: ares_callback, arg: ?*anyopaque) void; -pub extern fn ares_query(channel: *Channel, name: [*c]const u8, dnsclass: NSClass, @"type": NSType, callback: ares_callback, arg: ?*anyopaque) void; -pub extern fn ares_search(channel: *Channel, name: [*c]const u8, dnsclass: c_int, @"type": c_int, callback: ares_callback, arg: ?*anyopaque) void; -pub extern fn ares_gethostbyname(channel: *Channel, name: [*c]const u8, family: c_int, callback: ares_host_callback, arg: ?*anyopaque) void; -pub extern fn ares_gethostbyname_file(channel: *Channel, name: [*c]const u8, family: c_int, host: [*:null]?*struct_hostent) c_int; -pub extern fn ares_gethostbyaddr(channel: *Channel, addr: ?*const anyopaque, addrlen: c_int, family: c_int, callback: ares_host_callback, arg: ?*anyopaque) void; -pub extern fn ares_getnameinfo(channel: *Channel, sa: [*c]const struct_sockaddr, salen: ares_socklen_t, flags: c_int, callback: ares_nameinfo_callback, arg: ?*anyopaque) void; -// pub extern fn ares_fds(channel: *Channel, read_fds: *fd_set, write_fds: *fd_set) c_int; -pub extern fn ares_getsock(channel: *Channel, socks: [*c]ares_socket_t, numsocks: c_int) c_int; -pub extern fn ares_timeout(channel: *Channel, maxtv: ?*struct_timeval, tv: ?*struct_timeval) ?*struct_timeval; -// pub extern fn ares_process(channel: *Channel, read_fds: *fd_set, write_fds: *fd_set) void; -pub extern fn ares_process_fd(channel: *Channel, read_fd: ares_socket_t, write_fd: ares_socket_t) void; -pub extern fn ares_create_query(name: [*c]const u8, dnsclass: c_int, @"type": c_int, id: c_ushort, rd: c_int, buf: [*c][*c]u8, buflen: [*c]c_int, max_udp_size: c_int) c_int; -pub extern fn ares_mkquery(name: [*c]const u8, dnsclass: c_int, @"type": c_int, id: c_ushort, rd: c_int, buf: [*c][*c]u8, buflen: [*c]c_int) c_int; -pub extern fn ares_expand_name(encoded: [*c]const u8, abuf: [*c]const u8, alen: c_int, s: [*c][*c]u8, enclen: [*c]c_long) c_int; -pub extern fn ares_expand_string(encoded: [*c]const u8, abuf: [*c]const u8, alen: c_int, s: [*c][*c]u8, enclen: [*c]c_long) c_int; -pub extern fn ares_queue_active_queries(channel: *const Channel) usize; -const union_unnamed_2 = extern union { - _S6_u8: [16]u8, -}; -pub const struct_ares_in6_addr = extern struct { - _S6_un: union_unnamed_2, -}; -pub const struct_ares_addrttl = extern struct { - ipaddr: u32, - ttl: c_int, -}; -pub const struct_ares_addr6ttl = extern struct { - ip6addr: struct_ares_in6_addr, - ttl: c_int, -}; -pub const struct_ares_caa_reply = extern struct { - next: ?*struct_ares_caa_reply, - critical: c_int, - property: [*c]u8, - plength: usize, - value: [*c]u8, - length: usize, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").caaReplyToJSResponse; - - pub const toJS = @import("../runtime/dns_jsc/cares_jsc.zig").caaReplyToJS; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_caa_reply) void; - } - - pub fn callbackWrapper( - comptime _: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var start: [*c]struct_ares_caa_reply = undefined; - const result = ares_parse_caa_reply(buffer, buffer_length, &start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, start); - } - }.handle; - } - - pub fn deinit(this: *struct_ares_caa_reply) void { - ares_free_data(this); - } -}; -pub const struct_ares_srv_reply = extern struct { - next: ?*struct_ares_srv_reply, - host: [*c]u8, - priority: c_ushort, - weight: c_ushort, - port: c_ushort, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").srvReplyToJSResponse; - - pub const toJS = @import("../runtime/dns_jsc/cares_jsc.zig").srvReplyToJS; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_srv_reply) void; - } - - pub fn callbackWrapper( - comptime _: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handleSrv(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var srv_start: [*c]struct_ares_srv_reply = undefined; - const result = ares_parse_srv_reply(buffer, buffer_length, &srv_start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, srv_start); - } - }.handleSrv; - } - - pub fn deinit(this: *struct_ares_srv_reply) void { - ares_free_data(this); - } -}; -pub const struct_ares_mx_reply = extern struct { - next: ?*struct_ares_mx_reply, - host: [*c]u8, - priority: c_ushort, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").mxReplyToJSResponse; - - pub const toJS = @import("../runtime/dns_jsc/cares_jsc.zig").mxReplyToJS; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_mx_reply) void; - } - - pub fn callbackWrapper( - comptime _: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handle(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var start: [*c]struct_ares_mx_reply = undefined; - const result = ares_parse_mx_reply(buffer, buffer_length, &start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, start); - } - }.handle; - } - - pub fn deinit(this: *struct_ares_mx_reply) void { - ares_free_data(this); - } -}; -pub const struct_ares_txt_reply = extern struct { - next: ?*struct_ares_txt_reply, - txt: [*c]u8, - length: usize, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").txtReplyToJSResponse; - - pub const toJS = @import("../runtime/dns_jsc/cares_jsc.zig").txtReplyToJS; - - pub const toJSForAny = @import("../runtime/dns_jsc/cares_jsc.zig").txtReplyToJSForAny; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_txt_reply) void; - } - - pub fn callbackWrapper( - comptime _: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handleTxt(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var srv_start: [*c]struct_ares_txt_reply = undefined; - const result = ares_parse_txt_reply(buffer, buffer_length, &srv_start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, srv_start); - } - }.handleTxt; - } - - pub fn deinit(this: *struct_ares_txt_reply) void { - ares_free_data(this); - } -}; -pub const struct_ares_txt_ext = extern struct { - next: [*c]struct_ares_txt_ext, - txt: [*c]u8, - length: usize, - record_start: u8, -}; -pub const struct_ares_naptr_reply = extern struct { - next: ?*struct_ares_naptr_reply, - flags: [*c]u8, - service: [*c]u8, - regexp: [*c]u8, - replacement: [*c]u8, - order: c_ushort, - preference: c_ushort, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").naptrReplyToJSResponse; - - pub const toJS = @import("../runtime/dns_jsc/cares_jsc.zig").naptrReplyToJS; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_naptr_reply) void; - } - - pub fn callbackWrapper( - comptime _: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handleNaptr(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var naptr_start: [*c]struct_ares_naptr_reply = undefined; - const result = ares_parse_naptr_reply(buffer, buffer_length, &naptr_start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, naptr_start); - } - }.handleNaptr; - } - - pub fn deinit(this: *struct_ares_naptr_reply) void { - ares_free_data(this); - } -}; -pub const struct_ares_soa_reply = extern struct { - nsname: [*c]u8, - hostmaster: [*c]u8, - serial: c_uint, - refresh: c_uint, - retry: c_uint, - expire: c_uint, - minttl: c_uint, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").soaReplyToJSResponse; - - pub const toJS = @import("../runtime/dns_jsc/cares_jsc.zig").soaReplyToJS; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_ares_soa_reply) void; - } - - pub fn callbackWrapper( - comptime _: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handleSoa(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var soa_start: [*c]struct_ares_soa_reply = undefined; - const result = ares_parse_soa_reply(buffer, buffer_length, &soa_start); - if (result != ARES_SUCCESS) { - function(this, Error.get(result), timeouts, null); - return; - } - function(this, null, timeouts, soa_start); - } - }.handleSoa; - } - - pub fn deinit(this: *struct_ares_soa_reply) void { - ares_free_data(this); - } -}; - -pub const struct_ares_uri_reply = extern struct { - next: [*c]struct_ares_uri_reply, - priority: c_ushort, - weight: c_ushort, - uri: [*c]u8, - ttl: c_int, -}; - -pub const struct_any_reply = struct { - a_reply: ?*hostent_with_ttls = null, - aaaa_reply: ?*hostent_with_ttls = null, - mx_reply: ?*struct_ares_mx_reply = null, - ns_reply: ?*struct_hostent = null, - txt_reply: ?*struct_ares_txt_reply = null, - srv_reply: ?*struct_ares_srv_reply = null, - ptr_reply: ?*struct_hostent = null, - naptr_reply: ?*struct_ares_naptr_reply = null, - soa_reply: ?*struct_ares_soa_reply = null, - caa_reply: ?*struct_ares_caa_reply = null, - - pub const toJSResponse = @import("../runtime/dns_jsc/cares_jsc.zig").anyReplyToJSResponse; - - pub const toJS = @import("../runtime/dns_jsc/cares_jsc.zig").anyReplyToJS; - - pub fn Callback(comptime Type: type) type { - return fn (*Type, status: ?Error, timeouts: i32, results: ?*struct_any_reply) void; - } - - pub fn callbackWrapper( - comptime _: []const u8, - comptime Type: type, - comptime function: Callback(Type), - ) ares_callback { - return &struct { - pub fn handleAny(ctx: ?*anyopaque, status: c_int, timeouts: c_int, buffer: [*c]u8, buffer_length: c_int) callconv(.c) void { - const this = bun.cast(*Type, ctx.?); - if (status != ARES_SUCCESS) { - function(this, Error.get(status), timeouts, null); - return; - } - - var any_success = false; - var last_error: ?c_int = null; - var reply = bun.handleOom(bun.default_allocator.create(struct_any_reply)); - reply.* = .{}; - - switch (hostent_with_ttls.parse("a", buffer, buffer_length)) { - .result => |result| { - reply.a_reply = result; - any_success = true; - }, - .err => |err| last_error = @intFromEnum(err), - } - - switch (hostent_with_ttls.parse("aaaa", buffer, buffer_length)) { - .result => |result| { - reply.aaaa_reply = result; - any_success = true; - }, - .err => |err| last_error = @intFromEnum(err), - } - - var result = ares_parse_mx_reply(buffer, buffer_length, &reply.mx_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - result = ares_parse_ns_reply(buffer, buffer_length, &reply.ns_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - result = ares_parse_txt_reply(buffer, buffer_length, &reply.txt_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - result = ares_parse_srv_reply(buffer, buffer_length, &reply.srv_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - result = ares_parse_ptr_reply(buffer, buffer_length, null, 0, AF.INET, &reply.ptr_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - result = ares_parse_naptr_reply(buffer, buffer_length, &reply.naptr_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - result = ares_parse_soa_reply(buffer, buffer_length, &reply.soa_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - result = ares_parse_caa_reply(buffer, buffer_length, &reply.caa_reply); - if (result == ARES_SUCCESS) { - any_success = true; - } else { - last_error = result; - } - - if (!any_success) { - reply.deinit(); - function(this, Error.get(last_error.?), timeouts, null); - return; - } - - function(this, null, timeouts, reply); - } - }.handleAny; - } - - pub fn deinit(this: *struct_any_reply) void { - inline for (@typeInfo(struct_any_reply).@"struct".fields) |field| { - if (comptime std.mem.endsWith(u8, field.name, "_reply")) { - if (@field(this, field.name)) |reply| { - reply.deinit(); - } - } - } - - bun.default_allocator.destroy(this); - } -}; -pub extern fn ares_parse_a_reply(abuf: [*c]const u8, alen: c_int, host: [*c]?*struct_hostent, addrttls: [*c]struct_ares_addrttl, naddrttls: [*c]c_int) c_int; -pub extern fn ares_parse_aaaa_reply(abuf: [*c]const u8, alen: c_int, host: [*c]?*struct_hostent, addrttls: [*c]struct_ares_addr6ttl, naddrttls: [*c]c_int) c_int; -pub extern fn ares_parse_caa_reply(abuf: [*c]const u8, alen: c_int, caa_out: [*c][*c]struct_ares_caa_reply) c_int; -pub extern fn ares_parse_ptr_reply(abuf: [*c]const u8, alen: c_int, addr: ?*const anyopaque, addrlen: c_int, family: c_int, host: [*c]?*struct_hostent) c_int; -pub extern fn ares_parse_ns_reply(abuf: [*c]const u8, alen: c_int, host: [*c]?*struct_hostent) c_int; -pub extern fn ares_parse_srv_reply(abuf: [*c]const u8, alen: c_int, srv_out: [*c][*c]struct_ares_srv_reply) c_int; -pub extern fn ares_parse_mx_reply(abuf: [*c]const u8, alen: c_int, mx_out: [*c][*c]struct_ares_mx_reply) c_int; -pub extern fn ares_parse_txt_reply(abuf: [*c]const u8, alen: c_int, txt_out: [*c][*c]struct_ares_txt_reply) c_int; -pub extern fn ares_parse_txt_reply_ext(abuf: [*c]const u8, alen: c_int, txt_out: [*c][*c]struct_ares_txt_ext) c_int; -pub extern fn ares_parse_naptr_reply(abuf: [*c]const u8, alen: c_int, naptr_out: [*c][*c]struct_ares_naptr_reply) c_int; -pub extern fn ares_parse_soa_reply(abuf: [*c]const u8, alen: c_int, soa_out: [*c][*c]struct_ares_soa_reply) c_int; -pub extern fn ares_parse_uri_reply(abuf: [*c]const u8, alen: c_int, uri_out: [*c][*c]struct_ares_uri_reply) c_int; -pub extern fn ares_free_string(str: ?*anyopaque) void; -pub extern fn ares_free_hostent(host: ?*struct_hostent) void; -pub extern fn ares_free_data(dataptr: ?*anyopaque) void; -pub extern fn ares_strerror(code: c_int) [*c]const u8; -const union_unnamed_3 = extern union { - addr4: struct_in_addr, - addr6: struct_ares_in6_addr, -}; -pub const struct_ares_addr_node = extern struct { - next: ?*struct_ares_addr_node, - family: c_int, - addr: union_unnamed_3, -}; -const union_unnamed_4 = extern union { - addr4: struct_in_addr, - addr6: struct_ares_in6_addr, -}; -pub const struct_ares_addr_port_node = extern struct { - next: ?*struct_ares_addr_port_node, - family: c_int, - addr: union_unnamed_4, - udp_port: c_int, - tcp_port: c_int, -}; -pub extern fn ares_set_servers(channel: *Channel, servers: [*c]struct_ares_addr_node) c_int; -pub extern fn ares_set_servers_ports(channel: *Channel, servers: [*c]struct_ares_addr_port_node) c_int; -pub extern fn ares_set_servers_csv(channel: *Channel, servers: [*c]const u8) c_int; -pub extern fn ares_set_servers_ports_csv(channel: *Channel, servers: [*c]const u8) c_int; -pub extern fn ares_get_servers(channel: *Channel, servers: *?*struct_ares_addr_port_node) c_int; -pub extern fn ares_get_servers_ports(channel: *Channel, servers: *?*struct_ares_addr_port_node) c_int; -/// https://c-ares.org/docs/ares_inet_ntop.html -pub extern fn ares_inet_ntop(af: c_int, src: ?*const anyopaque, dst: [*]u8, size: ares_socklen_t) ?[*:0]const u8; -/// https://c-ares.org/docs/ares_inet_pton.html -/// -/// ## Returns -/// - `1` if `src` was valid for the specified address family -/// - `0` if `src` was not parseable in the specified address family -/// - `-1` if some system error occurred. `errno` will have been set. -pub extern fn ares_inet_pton(af: c_int, src: [*c]const u8, dst: ?*anyopaque) c_int; -pub const ARES_SUCCESS = 0; -pub const ARES_ENODATA = 1; -pub const ARES_EFORMERR = 2; -pub const ARES_ESERVFAIL = 3; -pub const ARES_ENOTFOUND = 4; -pub const ARES_ENOTIMP = 5; -pub const ARES_EREFUSED = 6; -pub const ARES_EBADQUERY = 7; -pub const ARES_EBADNAME = 8; -pub const ARES_EBADFAMILY = 9; -pub const ARES_EBADRESP = 10; -pub const ARES_ECONNREFUSED = 11; -pub const ARES_ETIMEOUT = 12; -pub const ARES_EOF = 13; -pub const ARES_EFILE = 14; -pub const ARES_ENOMEM = 15; -pub const ARES_EDESTRUCTION = 16; -pub const ARES_EBADSTR = 17; -pub const ARES_EBADFLAGS = 18; -pub const ARES_ENONAME = 19; -pub const ARES_EBADHINTS = 20; -pub const ARES_ENOTINITIALIZED = 21; -pub const ARES_ELOADIPHLPAPI = 22; -pub const ARES_EADDRGETNETWORKPARAMS = 23; -pub const ARES_ECANCELLED = 24; -pub const ARES_ESERVICE = 25; -pub const ARES_ENOSERVER = 26; - -pub const Error = enum(i32) { - ENODATA = ARES_ENODATA, - EFORMERR = ARES_EFORMERR, - ESERVFAIL = ARES_ESERVFAIL, - ENOTFOUND = ARES_ENOTFOUND, - ENOTIMP = ARES_ENOTIMP, - EREFUSED = ARES_EREFUSED, - EBADQUERY = ARES_EBADQUERY, - EBADNAME = ARES_EBADNAME, - EBADFAMILY = ARES_EBADFAMILY, - EBADRESP = ARES_EBADRESP, - ECONNREFUSED = ARES_ECONNREFUSED, - ETIMEOUT = ARES_ETIMEOUT, - EOF = ARES_EOF, - EFILE = ARES_EFILE, - ENOMEM = ARES_ENOMEM, - EDESTRUCTION = ARES_EDESTRUCTION, - EBADSTR = ARES_EBADSTR, - EBADFLAGS = ARES_EBADFLAGS, - ENONAME = ARES_ENONAME, - EBADHINTS = ARES_EBADHINTS, - ENOTINITIALIZED = ARES_ENOTINITIALIZED, - ELOADIPHLPAPI = ARES_ELOADIPHLPAPI, - EADDRGETNETWORKPARAMS = ARES_EADDRGETNETWORKPARAMS, - ECANCELLED = ARES_ECANCELLED, - ESERVICE = ARES_ESERVICE, - ENOSERVER = ARES_ENOSERVER, - - pub const Deferred = @import("../runtime/dns_jsc/cares_jsc.zig").ErrorDeferred; - pub const toDeferred = @import("../runtime/dns_jsc/cares_jsc.zig").errorToDeferred; - pub const toJSWithSyscall = @import("../runtime/dns_jsc/cares_jsc.zig").errorToJSWithSyscall; - pub const toJSWithSyscallAndHostname = @import("../runtime/dns_jsc/cares_jsc.zig").errorToJSWithSyscallAndHostname; - - pub fn initEAI(rc: i32) ?Error { - if (comptime bun.Environment.isWindows) { - // https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/lib/internal/errors.js#L807-L815 - if (rc == libuv.UV_EAI_NODATA or rc == libuv.UV_EAI_NONAME) { - return Error.ENOTFOUND; - } - - // TODO: revisit this - return switch (rc) { - 0 => null, - libuv.UV_EAI_AGAIN => Error.ETIMEOUT, - libuv.UV_EAI_ADDRFAMILY => Error.EBADFAMILY, - libuv.UV_EAI_BADFLAGS => Error.EBADFLAGS, - libuv.UV_EAI_BADHINTS => Error.EBADHINTS, - libuv.UV_EAI_CANCELED => Error.ECANCELLED, - libuv.UV_EAI_FAIL => Error.ENOTFOUND, - libuv.UV_EAI_FAMILY => Error.EBADFAMILY, - libuv.UV_EAI_MEMORY => Error.ENOMEM, - libuv.UV_EAI_NODATA => Error.ENODATA, - libuv.UV_EAI_NONAME => Error.ENONAME, - libuv.UV_EAI_OVERFLOW => Error.ENOMEM, - libuv.UV_EAI_PROTOCOL => Error.EBADQUERY, - libuv.UV_EAI_SERVICE => Error.ESERVICE, - libuv.UV_EAI_SOCKTYPE => Error.ECONNREFUSED, - else => Error.ENOTFOUND, //UV_ENOENT and non documented errors - }; - } - - const eai: std.posix.system.EAI = @enumFromInt(rc); - - // https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/lib/internal/errors.js#L807-L815 - if (eai == .NODATA or eai == .NONAME) { - return Error.ENOTFOUND; - } - - if (comptime bun.Environment.isLinux) { - if (eai == .SOCKTYPE) return Error.ECONNREFUSED; - } - if (comptime bun.Environment.isGlibc) { - // glibc-only async getaddrinfo_a / IDN extensions; absent on - // musl and bionic. - switch (eai) { - .IDN_ENCODE => return Error.EBADSTR, - .ALLDONE => return Error.ENOTFOUND, - .INPROGRESS => return Error.ETIMEOUT, - .CANCELED => return Error.ECANCELLED, - .NOTCANCELED => return Error.ECANCELLED, - else => {}, - } - } - - return switch (eai) { - @as(std.posix.system.EAI, @enumFromInt(0)) => return null, - .ADDRFAMILY => Error.EBADFAMILY, - .BADFLAGS => Error.EBADFLAGS, // Invalid hints - .FAIL => Error.EBADRESP, - .FAMILY => Error.EBADFAMILY, - .MEMORY => Error.ENOMEM, - .SERVICE => Error.ESERVICE, - .SYSTEM => Error.ESERVFAIL, - else => bun.todo(@src(), Error.ENOTIMP), - }; - } - - pub const code = bun.enumMap(Error, .{ - .{ .ENODATA, "DNS_ENODATA" }, - .{ .EFORMERR, "DNS_EFORMERR" }, - .{ .ESERVFAIL, "DNS_ESERVFAIL" }, - .{ .ENOTFOUND, "DNS_ENOTFOUND" }, - .{ .ENOTIMP, "DNS_ENOTIMP" }, - .{ .EREFUSED, "DNS_EREFUSED" }, - .{ .EBADQUERY, "DNS_EBADQUERY" }, - .{ .EBADNAME, "DNS_ENOTFOUND" }, - .{ .EBADFAMILY, "DNS_EBADFAMILY" }, - .{ .EBADRESP, "DNS_EBADRESP" }, - .{ .ECONNREFUSED, "DNS_ECONNREFUSED" }, - .{ .ETIMEOUT, "DNS_ETIMEOUT" }, - .{ .EOF, "DNS_EOF" }, - .{ .EFILE, "DNS_EFILE" }, - .{ .ENOMEM, "DNS_ENOMEM" }, - .{ .EDESTRUCTION, "DNS_EDESTRUCTION" }, - .{ .EBADSTR, "DNS_EBADSTR" }, - .{ .EBADFLAGS, "DNS_EBADFLAGS" }, - .{ .ENONAME, "DNS_ENOTFOUND" }, - .{ .EBADHINTS, "DNS_EBADHINTS" }, - .{ .ENOTINITIALIZED, "DNS_ENOTINITIALIZED" }, - .{ .ELOADIPHLPAPI, "DNS_ELOADIPHLPAPI" }, - .{ .EADDRGETNETWORKPARAMS, "DNS_EADDRGETNETWORKPARAMS" }, - .{ .ECANCELLED, "DNS_ECANCELLED" }, - .{ .ESERVICE, "DNS_ESERVICE" }, - .{ .ENOSERVER, "DNS_ENOSERVER" }, - }); - - pub const label = bun.enumMap(Error, .{ - .{ .ENODATA, "No data record of requested type" }, - .{ .EFORMERR, "Malformed DNS query" }, - .{ .ESERVFAIL, "Server failed to complete the DNS operation" }, - .{ .ENOTFOUND, "Domain name not found" }, - .{ .ENOTIMP, "DNS resolver does not implement requested operation" }, - .{ .EREFUSED, "DNS operation refused" }, - .{ .EBADQUERY, "Misformatted DNS query" }, - .{ .EBADNAME, "Misformatted domain name" }, - .{ .EBADFAMILY, "Misformatted DNS query (family)" }, - .{ .EBADRESP, "Misformatted DNS reply" }, - .{ .ECONNREFUSED, "Could not contact DNS servers" }, - .{ .ETIMEOUT, "Timeout while contacting DNS servers" }, - .{ .EOF, "End of file" }, - .{ .EFILE, "Error reading file" }, - .{ .ENOMEM, "Out of memory" }, - .{ .EDESTRUCTION, "Channel is being destroyed" }, - .{ .EBADSTR, "Misformatted string" }, - .{ .EBADFLAGS, "Illegal flags specified" }, - .{ .ENONAME, "Given hostname is not numeric" }, - .{ .EBADHINTS, "Illegal hints flags specified" }, - .{ .ENOTINITIALIZED, "Library initialization not yet performed" }, - .{ .ELOADIPHLPAPI, "ELOADIPHLPAPI TODO WHAT DOES THIS MEAN" }, - .{ .EADDRGETNETWORKPARAMS, "EADDRGETNETWORKPARAMS" }, - .{ .ECANCELLED, "DNS query cancelled" }, - .{ .ESERVICE, "Service not available" }, - .{ .ENOSERVER, "No DNS servers were configured" }, - }); - - pub fn get(rc: i32) ?Error { - // https://github.com/nodejs/node/blob/2eff28fb7a93d3f672f80b582f664a7c701569fb/lib/internal/errors.js#L807-L815 - if (rc == ARES_ENODATA or rc == ARES_ENONAME) { - return get(ARES_ENOTFOUND); - } - - return switch (rc) { - 0 => null, - 1...ARES_ENOSERVER => @as(Error, @enumFromInt(rc)), - -ARES_ENOSERVER...-1 => @as(Error, @enumFromInt(-rc)), - else => unreachable, - }; - } -}; - -pub const ARES_FLAG_USEVC = @as(c_int, 1) << @as(c_int, 0); -pub const ARES_FLAG_PRIMARY = @as(c_int, 1) << @as(c_int, 1); -pub const ARES_FLAG_IGNTC = @as(c_int, 1) << @as(c_int, 2); -pub const ARES_FLAG_NORECURSE = @as(c_int, 1) << @as(c_int, 3); -pub const ARES_FLAG_STAYOPEN = @as(c_int, 1) << @as(c_int, 4); -pub const ARES_FLAG_NOSEARCH = @as(c_int, 1) << @as(c_int, 5); -pub const ARES_FLAG_NOALIASES = @as(c_int, 1) << @as(c_int, 6); -pub const ARES_FLAG_NOCHECKRESP = @as(c_int, 1) << @as(c_int, 7); -pub const ARES_FLAG_NO_DFLT_SVR = @as(c_int, 1) << @as(c_int, 9); -pub const ARES_FLAG_EDNS = @as(c_int, 1) << @as(c_int, 8); -pub const ARES_OPT_FLAGS = @as(c_int, 1) << @as(c_int, 0); -pub const ARES_OPT_TIMEOUT = @as(c_int, 1) << @as(c_int, 1); -pub const ARES_OPT_TRIES = @as(c_int, 1) << @as(c_int, 2); -pub const ARES_OPT_NDOTS = @as(c_int, 1) << @as(c_int, 3); -pub const ARES_OPT_UDP_PORT = @as(c_int, 1) << @as(c_int, 4); -pub const ARES_OPT_TCP_PORT = @as(c_int, 1) << @as(c_int, 5); -pub const ARES_OPT_SERVERS = @as(c_int, 1) << @as(c_int, 6); -pub const ARES_OPT_DOMAINS = @as(c_int, 1) << @as(c_int, 7); -pub const ARES_OPT_LOOKUPS = @as(c_int, 1) << @as(c_int, 8); -pub const ARES_OPT_SOCK_STATE_CB = @as(c_int, 1) << @as(c_int, 9); -pub const ARES_OPT_SORTLIST = @as(c_int, 1) << @as(c_int, 10); -pub const ARES_OPT_SOCK_SNDBUF = @as(c_int, 1) << @as(c_int, 11); -pub const ARES_OPT_SOCK_RCVBUF = @as(c_int, 1) << @as(c_int, 12); -pub const ARES_OPT_TIMEOUTMS = @as(c_int, 1) << @as(c_int, 13); -pub const ARES_OPT_ROTATE = @as(c_int, 1) << @as(c_int, 14); -pub const ARES_OPT_EDNSPSZ = @as(c_int, 1) << @as(c_int, 15); -pub const ARES_OPT_NOROTATE = @as(c_int, 1) << @as(c_int, 16); -pub const ARES_OPT_RESOLVCONF = @as(c_int, 1) << @as(c_int, 17); -pub const ARES_OPT_HOSTS_FILE = @as(c_int, 1) << @as(c_int, 18); -pub const ARES_NI_NOFQDN = @as(c_int, 1) << @as(c_int, 0); -pub const ARES_NI_NUMERICHOST = @as(c_int, 1) << @as(c_int, 1); -pub const ARES_NI_NAMEREQD = @as(c_int, 1) << @as(c_int, 2); -pub const ARES_NI_NUMERICSERV = @as(c_int, 1) << @as(c_int, 3); -pub const ARES_NI_DGRAM = @as(c_int, 1) << @as(c_int, 4); -pub const ARES_NI_TCP = @as(c_int, 0); -pub const ARES_NI_UDP = ARES_NI_DGRAM; -pub const ARES_NI_SCTP = @as(c_int, 1) << @as(c_int, 5); -pub const ARES_NI_DCCP = @as(c_int, 1) << @as(c_int, 6); -pub const ARES_NI_NUMERICSCOPE = @as(c_int, 1) << @as(c_int, 7); -pub const ARES_NI_LOOKUPHOST = @as(c_int, 1) << @as(c_int, 8); -pub const ARES_NI_LOOKUPSERVICE = @as(c_int, 1) << @as(c_int, 9); -pub const ARES_NI_IDN = @as(c_int, 1) << @as(c_int, 10); -pub const ARES_NI_IDN_ALLOW_UNASSIGNED = @as(c_int, 1) << @as(c_int, 11); -pub const ARES_NI_IDN_USE_STD3_ASCII_RULES = @as(c_int, 1) << @as(c_int, 12); -pub const ARES_AI_CANONNAME = @as(c_int, 1) << @as(c_int, 0); -pub const ARES_AI_NUMERICHOST = @as(c_int, 1) << @as(c_int, 1); -pub const ARES_AI_PASSIVE = @as(c_int, 1) << @as(c_int, 2); -pub const ARES_AI_NUMERICSERV = @as(c_int, 1) << @as(c_int, 3); -pub const ARES_AI_V4MAPPED = @as(c_int, 1) << @as(c_int, 4); -pub const ARES_AI_ALL = @as(c_int, 1) << @as(c_int, 5); -pub const ARES_AI_ADDRCONFIG = @as(c_int, 1) << @as(c_int, 6); -pub const ARES_AI_NOSORT = @as(c_int, 1) << @as(c_int, 7); -pub const ARES_AI_ENVHOSTS = @as(c_int, 1) << @as(c_int, 8); -pub const ARES_AI_IDN = @as(c_int, 1) << @as(c_int, 10); -pub const ARES_AI_IDN_ALLOW_UNASSIGNED = @as(c_int, 1) << @as(c_int, 11); -pub const ARES_AI_IDN_USE_STD3_ASCII_RULES = @as(c_int, 1) << @as(c_int, 12); -pub const ARES_AI_CANONIDN = @as(c_int, 1) << @as(c_int, 13); -pub const ARES_AI_MASK = (((((ARES_AI_CANONNAME | ARES_AI_NUMERICHOST) | ARES_AI_PASSIVE) | ARES_AI_NUMERICSERV) | ARES_AI_V4MAPPED) | ARES_AI_ALL) | ARES_AI_ADDRCONFIG; -pub const ARES_GETSOCK_MAXNUM = @as(c_int, 16); -pub inline fn ARES_GETSOCK_READABLE(bits: anytype, num: anytype) @TypeOf(bits & (@as(c_int, 1) << num)) { - return bits & (@as(c_int, 1) << num); -} -pub inline fn ARES_GETSOCK_WRITABLE(bits: anytype, num: anytype) @TypeOf(bits & (@as(c_int, 1) << (num + ARES_GETSOCK_MAXNUM))) { - return bits & (@as(c_int, 1) << (num + ARES_GETSOCK_MAXNUM)); -} -pub const ARES_LIB_INIT_NONE = @as(c_int, 0); -pub const ARES_LIB_INIT_WIN32 = @as(c_int, 1) << @as(c_int, 0); -pub const ARES_LIB_INIT_ALL = ARES_LIB_INIT_WIN32; -pub const ARES_SOCKET_BAD = if (bun.Environment.isWindows) std.os.windows.ws2_32.INVALID_SOCKET else -@as(c_int, 1); -pub const ares_socket_typedef = ""; -pub const ares_addrinfo_cname = AddrInfo_cname; -pub const ares_addrinfo_node = AddrInfo_node; -pub const ares_addrinfo = AddrInfo; -pub const ares_addrinfo_hints = AddrInfo_hints; -pub const ares_in6_addr = struct_ares_in6_addr; -pub const ares_addrttl = struct_ares_addrttl; -pub const ares_addr6ttl = struct_ares_addr6ttl; -pub const ares_caa_reply = struct_ares_caa_reply; -pub const ares_srv_reply = struct_ares_srv_reply; -pub const ares_mx_reply = struct_ares_mx_reply; -pub const ares_txt_reply = struct_ares_txt_reply; -pub const ares_txt_ext = struct_ares_txt_ext; -pub const ares_naptr_reply = struct_ares_naptr_reply; -pub const ares_soa_reply = struct_ares_soa_reply; -pub const ares_uri_reply = struct_ares_uri_reply; -pub const ares_addr_node = struct_ares_addr_node; -pub const ares_addr_port_node = struct_ares_addr_port_node; - -// Bun__canonicalizeIP_ host fn: see src/runtime/dns_jsc/cares_jsc.zig - -/// Creates a sockaddr structure from an address, port. -/// -/// # Parameters -/// - `addr`: A byte slice representing the IP address. -/// - `port`: A 16-bit unsigned integer representing the port number. -/// - `sa`: A pointer to a sockaddr structure where the result will be stored. -/// -/// # Returns -/// -/// This function returns 0 on success. -pub fn getSockaddr(addr: []const u8, port: u16, sa: *std.posix.sockaddr) c_int { - const buf_size = 128; - - var buf: [buf_size]u8 = undefined; - const addr_ptr: [*:0]const u8 = brk: { - if (addr.len == 0 or addr.len >= buf_size) { - return -1; - } - const len = @min(addr.len, buf.len - 1); - @memcpy(buf[0..len], addr[0..len]); - - buf[len] = 0; - break :brk buf[0..len :0]; - }; - - { - const in: *std.posix.sockaddr.in = @ptrCast(@alignCast(sa)); - if (ares_inet_pton(AF.INET, addr_ptr, &in.addr) == 1) { - in.*.family = AF.INET; - in.*.port = std.mem.nativeToBig(u16, port); - return 0; - } - } - { - const in6: *std.posix.sockaddr.in6 = @ptrCast(@alignCast(sa)); - if (ares_inet_pton(AF.INET6, addr_ptr, &in6.addr) == 1) { - in6.*.family = AF.INET6; - in6.*.port = std.mem.nativeToBig(u16, port); - return 0; - } - } - - return -1; -} - -const std = @import("std"); -const iovec = @import("std").os.iovec; - -const bun = @import("bun"); -const jsc = bun.jsc; -const strings = bun.strings; -const libuv = bun.windows.libuv; - -const c = @import("std").c; -const ares_socklen_t = c.socklen_t; -const fd_set = c.fd_set; - -const struct_sockaddr = std.posix.sockaddr; -const struct_in_addr = std.posix.sockaddr.in; diff --git a/src/clap/args.zig b/src/clap/args.zig deleted file mode 100644 index 0518bc794458..000000000000 --- a/src/clap/args.zig +++ /dev/null @@ -1,348 +0,0 @@ -/// An example of what methods should be implemented on an arg iterator. -pub const ExampleArgIterator = struct { - const Error = error{}; - - pub fn next(_: *ExampleArgIterator) Error!?[]const u8 { - return "2"; - } -}; - -/// An argument iterator which iterates over a slice of arguments. -/// This implementation does not allocate. -pub const SliceIterator = struct { - const Error = error{}; - - remain: []const []const u8, - - pub fn init(args: []const []const u8) SliceIterator { - return .{ - .remain = args, - }; - } - - pub fn next(iter: *SliceIterator) ?[]const u8 { - if (iter.remain.len > 0) { - const res = iter.remain[0]; - iter.remain = iter.remain[1..]; - return res; - } - return null; - } -}; - -test "SliceIterator" { - const args = &[_][]const u8{ "A", "BB", "CCC" }; - var iter = SliceIterator{ .args = args }; - - for (args) |a| { - const b = try iter.next(); - debug.assert(mem.eql(u8, a, b.?)); - } -} - -/// An argument iterator which wraps the ArgIterator in ::std. -/// On windows, this iterator allocates. -pub const OsIterator = struct { - const Error = process.ArgIterator.InitError; - - arena: bun.ArenaAllocator, - remain: [][:0]const u8, - - /// The executable path (this is the first argument passed to the program) - /// TODO: Is it the right choice for this to be null? Maybe `init` should - /// return an error when we have no exe. - exe_arg: ?[:0]const u8, - - pub fn init(allocator: mem.Allocator) OsIterator { - var res = OsIterator{ - .arena = bun.ArenaAllocator.init(allocator), - .exe_arg = undefined, - .remain = bun.argv, - }; - res.exe_arg = res.next(); - return res; - } - - pub fn deinit(iter: *OsIterator) void { - iter.arena.deinit(); - } - - pub fn next(iter: *OsIterator) ?[:0]const u8 { - if (iter.remain.len > 0) { - const res = iter.remain[0]; - iter.remain = iter.remain[1..]; - return res; - } - - return null; - } -}; - -/// An argument iterator that takes a string and parses it into arguments, simulating -/// how shells split arguments. -pub const ShellIterator = struct { - const Error = error{ - DanglingEscape, - QuoteNotClosed, - } || mem.Allocator.Error; - - arena: bun.ArenaAllocator, - str: []const u8, - - pub fn init(allocator: mem.Allocator, str: []const u8) ShellIterator { - return .{ - .arena = bun.ArenaAllocator.init(allocator), - .str = str, - }; - } - - pub fn deinit(iter: *ShellIterator) void { - iter.arena.deinit(); - } - - pub fn next(iter: *ShellIterator) Error!?[]const u8 { - // Whenever possible, this iterator will return slices into `str` instead of - // allocating. Sometimes this is not possible, for example, escaped characters - // have be be unescape, so we need to allocate in this case. - var list = std.array_list.Managed(u8).init(&iter.arena.allocator); - var start: usize = 0; - var state: enum { - skip_whitespace, - no_quote, - no_quote_escape, - single_quote, - double_quote, - double_quote_escape, - after_quote, - } = .skip_whitespace; - - for (iter.str, 0..) |c, i| { - switch (state) { - // The state that skips the initial whitespace. - .skip_whitespace => switch (c) { - ' ', '\t', '\n' => {}, - '\'' => { - start = i + 1; - state = .single_quote; - }, - '"' => { - start = i + 1; - state = .double_quote; - }, - '\\' => { - start = i + 1; - state = .no_quote_escape; - }, - else => { - start = i; - state = .no_quote; - }, - }, - - // The state that parses the none quoted part of a argument. - .no_quote => switch (c) { - // We're done parsing a none quoted argument when we hit a - // whitespace. - ' ', '\t', '\n' => { - defer iter.str = iter.str[i..]; - return iter.result(start, i, &list); - }, - - // Slicing is not possible if a quote starts while parsing none - // quoted args. - // Example: - // ab'cd' -> abcd - '\'' => { - try list.appendSlice(iter.str[start..i]); - start = i + 1; - state = .single_quote; - }, - '"' => { - try list.appendSlice(iter.str[start..i]); - start = i + 1; - state = .double_quote; - }, - - // Slicing is not possible if we need to escape a character. - // Example: - // ab\"d -> ab"d - '\\' => { - try list.appendSlice(iter.str[start..i]); - start = i + 1; - state = .no_quote_escape; - }, - else => {}, - }, - - // We're in this state after having parsed the quoted part of an - // argument. This state works mostly the same as .no_quote, but - // is aware, that the last character seen was a quote, which should - // not be part of the argument. This is why you will see `i - 1` here - // instead of just `i` when `iter.str` is sliced. - .after_quote => switch (c) { - ' ', '\t', '\n' => { - defer iter.str = iter.str[i..]; - return iter.result(start, i - 1, &list); - }, - '\'' => { - try list.appendSlice(iter.str[start .. i - 1]); - start = i + 1; - state = .single_quote; - }, - '"' => { - try list.appendSlice(iter.str[start .. i - 1]); - start = i + 1; - state = .double_quote; - }, - '\\' => { - try list.appendSlice(iter.str[start .. i - 1]); - start = i + 1; - state = .no_quote_escape; - }, - else => { - try list.appendSlice(iter.str[start .. i - 1]); - start = i; - state = .no_quote; - }, - }, - - // The states that parse the quoted part of arguments. The only differnece - // between single and double quoted arguments is that single quoted - // arguments ignore escape sequences, while double quoted arguments - // does escaping. - .single_quote => switch (c) { - '\'' => state = .after_quote, - else => {}, - }, - .double_quote => switch (c) { - '"' => state = .after_quote, - '\\' => { - try list.appendSlice(iter.str[start..i]); - start = i + 1; - state = .double_quote_escape; - }, - else => {}, - }, - - // The state we end up when after the escape character (`\`). All these - // states do is transition back into the previous state. - // TODO: Are there any escape sequences that does transform the second - // character into something else? For example, in Zig, `\n` is - // transformed into the line feed ascii character. - .no_quote_escape => switch (c) { - else => state = .no_quote, - }, - .double_quote_escape => switch (c) { - else => state = .double_quote, - }, - } - } - - defer iter.str = iter.str[iter.str.len..]; - switch (state) { - .skip_whitespace => return null, - .no_quote => return iter.result(start, iter.str.len, &list), - .after_quote => return iter.result(start, iter.str.len - 1, &list), - .no_quote_escape => return Error.DanglingEscape, - .single_quote, - .double_quote, - .double_quote_escape, - => return Error.QuoteNotClosed, - } - } - - fn result(iter: *ShellIterator, start: usize, end: usize, list: *std.array_list.Managed(u8)) Error!?[]const u8 { - const res = iter.str[start..end]; - - // If we already have something in `list` that means that we could not - // parse the argument without allocation. We therefor need to just append - // the rest we have to the list and return that. - if (list.items.len != 0) { - try list.appendSlice(res); - return try list.toOwnedSlice(); - } - return res; - } -}; - -fn testShellIteratorOk(str: []const u8, allocations: usize, expect: []const []const u8) void { - var allocator = testing.FailingAllocator.init(testing.allocator, allocations); - var it = ShellIterator.init(&allocator.allocator, str); - defer it.deinit(); - - for (expect) |e| { - if (it.next()) |actual| { - testing.expect(actual != null); - testing.expectEqualStrings(e, actual.?); - } else |err| testing.expectEqual(@as(anyerror![]const u8, e), err); - } - - if (it.next()) |actual| { - testing.expectEqual(@as(?[]const u8, null), actual); - testing.expectEqual(allocations, allocator.allocations); - } else |err| testing.expectEqual(@as(anyerror!void, {}), err); -} - -fn testShellIteratorErr(str: []const u8, expect: anyerror) void { - var it = ShellIterator.init(testing.allocator, str); - defer it.deinit(); - - while (it.next() catch |err| { - testing.expectError(expect, @as(anyerror!void, err)); - return; - }) |_| {} - - testing.expectError(expect, @as(anyerror!void, {})); -} - -test "ShellIterator" { - testShellIteratorOk("a", 0, &[_][]const u8{"a"}); - testShellIteratorOk("'a'", 0, &[_][]const u8{"a"}); - testShellIteratorOk("\"a\"", 0, &[_][]const u8{"a"}); - testShellIteratorOk("a b", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("'a' b", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("\"a\" b", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("a 'b'", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("a \"b\"", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("'a b'", 0, &[_][]const u8{"a b"}); - testShellIteratorOk("\"a b\"", 0, &[_][]const u8{"a b"}); - testShellIteratorOk("\"a\"\"b\"", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("'a''b'", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("'a'b", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("a'b'", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("a\\ b", 1, &[_][]const u8{"a b"}); - testShellIteratorOk("\"a\\ b\"", 1, &[_][]const u8{"a b"}); - testShellIteratorOk("'a\\ b'", 0, &[_][]const u8{"a\\ b"}); - testShellIteratorOk(" a b ", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("\\ \\ ", 0, &[_][]const u8{ " ", " " }); - - testShellIteratorOk( - \\printf 'run\nuninstall\n' - , 0, &[_][]const u8{ "printf", "run\\nuninstall\\n" }); - testShellIteratorOk( - \\setsid -f steam "steam://$action/$id" - , 0, &[_][]const u8{ "setsid", "-f", "steam", "steam://$action/$id" }); - testShellIteratorOk( - \\xargs -I% rg --no-heading --no-line-number --only-matching - \\ --case-sensitive --multiline --text --byte-offset '(?-u)%' $@ - \\ - , 0, &[_][]const u8{ - "xargs", "-I%", "rg", "--no-heading", - "--no-line-number", "--only-matching", "--case-sensitive", "--multiline", - "--text", "--byte-offset", "(?-u)%", "$@", - }); - - testShellIteratorErr("'a", error.QuoteNotClosed); - testShellIteratorErr("'a\\", error.QuoteNotClosed); - testShellIteratorErr("\"a", error.QuoteNotClosed); - testShellIteratorErr("\"a\\", error.QuoteNotClosed); - testShellIteratorErr("a\\", error.DanglingEscape); -} - -const bun = @import("bun"); - -const std = @import("std"); -const debug = std.debug; -const mem = std.mem; -const process = std.process; -const testing = std.testing; diff --git a/src/clap/clap.zig b/src/clap/clap.zig deleted file mode 100644 index cd7de8a0059a..000000000000 --- a/src/clap/clap.zig +++ /dev/null @@ -1,734 +0,0 @@ -pub const args = @import("./args.zig"); - -pub const ComptimeClap = @import("./comptime.zig").ComptimeClap; -pub const StreamingClap = @import("./streaming.zig").StreamingClap; - -/// The names a ::Param can have. -pub const Names = struct { - /// '-' prefix - short: ?u8 = null, - - /// '--' prefix (primary name, used for display/help) - long: ?[]const u8 = null, - - /// Additional '--' prefixed aliases (e.g., --grep as alias for --test-name-pattern) - long_aliases: []const []const u8 = &.{}, - - /// Check if the given name matches the primary long name or any alias - pub fn matchesLong(self: Names, name: []const u8) bool { - if (self.long) |l| { - if (mem.eql(u8, name, l)) return true; - } - for (self.long_aliases) |alias| { - if (mem.eql(u8, name, alias)) return true; - } - return false; - } -}; - -/// Whether a param takes no value (a flag), one value, or can be specified multiple times. -pub const Values = enum { - none, - one, - many, - one_optional, -}; - -/// Represents a parameter for the command line. -/// Parameters come in three kinds: -/// * Short ("-a"): Should be used for the most commonly used parameters in your program. -/// * They can take a value three different ways. -/// * "-a value" -/// * "-a=value" -/// * "-avalue" -/// * They chain if they don't take values: "-abc". -/// * The last given parameter can take a value in the same way that a single parameter can: -/// * "-abc value" -/// * "-abc=value" -/// * "-abcvalue" -/// * Long ("--long-param"): Should be used for less common parameters, or when no single character -/// can describe the paramter. -/// * They can take a value two different ways. -/// * "--long-param value" -/// * "--long-param=value" -/// * Positional: Should be used as the primary parameter of the program, like a filename or -/// an expression to parse. -/// * Positional parameters have both names.long and names.short == null. -/// * Positional parameters must take a value. -pub fn Param(comptime Id: type) type { - return struct { - id: Id = std.mem.zeroes(Id), - names: Names = std.mem.zeroes(Names), - takes_value: Values = .none, - }; -} - -/// Takes a string and parses it to a Param(Help). -/// This is the reverse of 'help' but for at single parameter only. -/// Supports multiple long name variants separated by '/' (e.g., "--test-name-pattern/--grep"). -pub fn parseParam(line: []const u8) !Param(Help) { - @setEvalBranchQuota(999999); - - var found_comma = false; - var it = mem.tokenizeAny(u8, line, " \t"); - var param_str = it.next() orelse return error.NoParamFound; - - const short_name = if (!mem.startsWith(u8, param_str, "--") and - mem.startsWith(u8, param_str, "-")) - blk: { - found_comma = param_str[param_str.len - 1] == ','; - if (found_comma) - param_str = param_str[0 .. param_str.len - 1]; - - if (param_str.len != 2) - return error.InvalidShortParam; - - const short_name = param_str[1]; - if (!found_comma) { - var res = parseParamRest(it.rest()); - res.names.short = short_name; - return res; - } - - param_str = it.next() orelse return error.NoParamFound; - break :blk short_name; - } else null; - - _ = if (mem.startsWith(u8, param_str, "--")) { - if (param_str[param_str.len - 1] == ',') - return error.TrailingComma; - } else if (found_comma) { - return error.TrailingComma; - } else if (short_name == null) { - return parseParamRest(mem.trimLeft(u8, line, " \t")); - } else null; - - var res = parseParamRest(it.rest()); - res.names.short = short_name; - - // Parse long names - supports multiple variants separated by '/' - // e.g., "--test-name-pattern/--grep" becomes primary "test-name-pattern" with alias "grep" - const long_names = parseLongNames(param_str); - res.names.long = long_names.long; - res.names.long_aliases = long_names.long_aliases; - return res; -} - -fn parseLongNames(comptime param_str: []const u8) Names { - comptime { - // Count how many long name variants we have (separated by '/') - var alias_count: usize = 0; - for (param_str) |c| { - if (c == '/') alias_count += 1; - } - - if (alias_count == 0) { - // No aliases, just the primary name - if (mem.startsWith(u8, param_str, "--")) { - return .{ .long = param_str[2..], .long_aliases = &.{} }; - } - return .{ .long = null, .long_aliases = &.{} }; - } - - // Parse multiple long names at comptime - // First pass: find the primary name - var primary: ?[]const u8 = null; - var name_it = mem.splitScalar(u8, param_str, '/'); - while (name_it.next()) |name_part| { - if (!mem.startsWith(u8, name_part, "--")) continue; - primary = name_part[2..]; - break; - } - - // Second pass: collect aliases into a comptime-known array type - const aliases = blk: { - var result: [alias_count][]const u8 = undefined; - var idx: usize = 0; - var it = mem.splitScalar(u8, param_str, '/'); - var is_first = true; - while (it.next()) |name_part| { - if (!mem.startsWith(u8, name_part, "--")) continue; - if (is_first) { - is_first = false; - continue; // Skip primary - } - result[idx] = name_part[2..]; - idx += 1; - } - break :blk result; - }; - - return .{ - .long = primary, - .long_aliases = &aliases, - }; - } -} - -fn parseParamRest(line: []const u8) Param(Help) { - if (mem.startsWith(u8, line, "<")) blk: { - const len = mem.indexOfScalar(u8, line, '>') orelse break :blk; - const takes_many = mem.startsWith(u8, line[len + 1 ..], "..."); - const takes_one_optional = mem.startsWith(u8, line[len + 1 ..], "?"); - const help_start = len + 1 + @as(usize, 3) * @intFromBool(takes_many) + (@as(usize, 1) * @intFromBool(takes_one_optional)); - return .{ - .takes_value = if (takes_many) Values.many else if (takes_one_optional) Values.one_optional else Values.one, - .id = .{ - .msg = mem.trim(u8, line[help_start..], " \t"), - .value = line[1..len], - }, - }; - } - - return .{ .id = .{ .msg = mem.trim(u8, line, " \t") } }; -} - -fn expectParam(expect: Param(Help), actual: Param(Help)) void { - testing.expectEqualStrings(expect.id.msg, actual.id.msg); - testing.expectEqualStrings(expect.id.value, actual.id.value); - testing.expectEqual(expect.names.short, actual.names.short); - testing.expectEqual(expect.takes_value, actual.takes_value); - if (expect.names.long) |long| { - testing.expectEqualStrings(long, actual.names.long.?); - } else { - testing.expectEqual(@as(?[]const u8, null), actual.names.long); - } -} - -test "parseParam" { - expectParam(Param(Help){ - .id = .{ .msg = "Help text", .value = "value" }, - .names = .{ .short = 's', .long = "long" }, - .takes_value = .one, - }, try parseParam("-s, --long Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text", .value = "value" }, - .names = .{ .short = 's', .long = "long" }, - .takes_value = .many, - }, try parseParam("-s, --long ... Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text", .value = "value" }, - .names = .{ .long = "long" }, - .takes_value = .one, - }, try parseParam("--long Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text", .value = "value" }, - .names = .{ .short = 's' }, - .takes_value = .one, - }, try parseParam("-s Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text" }, - .names = .{ .short = 's', .long = "long" }, - }, try parseParam("-s, --long Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text" }, - .names = .{ .short = 's' }, - }, try parseParam("-s Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text" }, - .names = .{ .long = "long" }, - }, try parseParam("--long Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text", .value = "A | B" }, - .names = .{ .long = "long" }, - .takes_value = .one, - }, try parseParam("--long Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text", .value = "A" }, - .names = .{}, - .takes_value = .one, - }, try parseParam(" Help text")); - - expectParam(Param(Help){ - .id = .{ .msg = "Help text", .value = "A" }, - .names = .{}, - .takes_value = .many, - }, try parseParam("... Help text")); - - testing.expectError(error.TrailingComma, parseParam("--long, Help")); - testing.expectError(error.TrailingComma, parseParam("-s, Help")); - testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); - testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); - testing.expectError(error.InvalidShortParam, parseParam("- Help")); -} - -/// Optional diagnostics used for reporting useful errors -pub const Diagnostic = struct { - arg: []const u8 = "", - name: Names = Names{}, - - /// Default diagnostics reporter when all you want is English with no colors. - /// Use this as a reference for implementing your own if needed. - pub fn report(diag: Diagnostic, _: anytype, err: anyerror) !void { - var name_buf: [1024]u8 = undefined; - const name = if (diag.name.short) |s| short: { - name_buf[0] = '-'; - name_buf[1] = s; - name_buf[2] = 0; - break :short name_buf[0..2]; - } else if (diag.name.long) |l| long: { - name_buf[0] = '-'; - name_buf[1] = '-'; - const long = l[0..@min(l.len, name_buf.len - 2)]; - @memcpy(name_buf[2..][0..long.len], long); - break :long name_buf[0 .. 2 + long.len]; - } else diag.arg; - - switch (err) { - error.DoesntTakeValue => { - Output.prettyErrorln("error: The argument '{s}' does not take a value.", .{name}); - }, - error.MissingValue => { - Output.prettyErrorln("error: The argument '{s}' requires a value but none was supplied.", .{name}); - }, - error.InvalidArgument => { - Output.prettyErrorln("error: Invalid Argument '{s}'", .{name}); - }, - else => { - Output.prettyErrorln("error: {s} while parsing argument '{s}'", .{ @errorName(err), name }); - }, - } - Output.flush(); - } -}; - -fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) void { - var buf: [1024]u8 = undefined; - var slice_stream = io.fixedBufferStream(&buf); - diag.report(slice_stream.writer(), err) catch unreachable; - testing.expectEqualStrings(expected, slice_stream.getWritten()); -} - -pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type { - return struct { - arena: bun.ArenaAllocator, - clap: ComptimeClap(Id, params), - exe_arg: ?[]const u8, - - pub fn deinit(a: *@This()) void { - a.arena.deinit(); - } - - pub fn flag(a: @This(), comptime name: []const u8) bool { - return a.clap.flag(name); - } - - pub fn option(a: @This(), comptime name: []const u8) ?[]const u8 { - return a.clap.option(name); - } - - pub fn options(a: @This(), comptime name: []const u8) []const []const u8 { - return a.clap.options(name); - } - - pub fn positionals(a: @This()) []const []const u8 { - return a.clap.positionals(); - } - - pub fn remaining(a: @This()) []const []const u8 { - return a.clap.remaining(); - } - - pub fn hasFlag(comptime name: []const u8) bool { - return ComptimeClap(Id, params).hasFlag(name); - } - }; -} - -/// Options that can be set to customize the behavior of parsing. -pub const ParseOptions = struct { - /// The allocator used for all memory allocations. Defaults to the `heap.page_allocator`. - /// Note: You should probably override this allocator if you are calling `parseEx`. Unlike - /// `parse`, `parseEx` does not wrap the allocator so the heap allocator can be - /// quite expensive. (TODO: Can we pick a better default? For `parse`, this allocator - /// is fine, as it wraps it in an arena) - allocator: mem.Allocator = heap.page_allocator, - diagnostic: ?*Diagnostic = null, - stop_after_positional_at: usize = 0, -}; - -/// Same as `parseEx` but uses the `args.OsIterator` by default. -pub fn parse( - comptime Id: type, - comptime params: []const Param(Id), - opt: ParseOptions, -) !Args(Id, params) { - var iter = args.OsIterator.init(opt.allocator); - var res = Args(Id, params){ - .arena = iter.arena, - .exe_arg = iter.exe_arg, - .clap = undefined, - }; - - // Let's reuse the arena from the `OSIterator` since we already have - // it. - res.clap = try parseEx(Id, params, &iter, .{ - .allocator = res.arena.allocator(), - .diagnostic = opt.diagnostic, - .stop_after_positional_at = opt.stop_after_positional_at, - }); - return res; -} - -/// Parses the command line arguments passed into the program based on an -/// array of `Param`s. -pub fn parseEx( - comptime Id: type, - comptime params: []const Param(Id), - iter: anytype, - opt: ParseOptions, -) !ComptimeClap(Id, params) { - const Clap = ComptimeClap(Id, params); - return try Clap.parse(iter, opt); -} - -/// Will print a help message in the following format: -/// -s, --long helpText -/// -s, helpText -/// -s helpText -/// --long helpText -/// --long helpText -pub fn helpFull( - stream: anytype, - comptime Id: type, - params: []const Param(Id), - comptime Error: type, - context: anytype, - helpText: fn (@TypeOf(context), Param(Id)) Error![]const u8, - valueText: fn (@TypeOf(context), Param(Id)) Error![]const u8, -) !void { - const max_spacing = blk: { - var res: usize = 0; - for (params) |param| { - var cs = io.countingWriter(io.null_writer); - try printParam(cs.writer(), Id, param, Error, context, valueText); - if (res < cs.bytes_written) - res = @as(usize, @intCast(cs.bytes_written)); - } - - break :blk res; - }; - - for (params) |param| { - if (param.names.short == null and param.names.long == null) - continue; - - const help_text = try helpText(context, param); - // only print flag if description is defined - if (help_text.len > 0) { - var cs = io.countingWriter(stream); - try stream.print("\t", .{}); - try printParam(cs.writer(), Id, param, Error, context, valueText); - try stream.splatByteAll(' ', max_spacing - @as(usize, @intCast(cs.bytes_written))); - try stream.print("\t{s}\n", .{try helpText(context, param)}); - } - } -} - -fn printParam( - stream: anytype, - comptime Id: type, - param: Param(Id), - comptime Error: type, - context: anytype, - valueText: fn (@TypeOf(context), Param(Id)) Error![]const u8, -) !void { - if (param.names.short) |s| { - try stream.print("-{c}", .{s}); - } else { - try stream.print(" ", .{}); - } - if (param.names.long) |l| { - if (param.names.short) |_| { - try stream.print(", ", .{}); - } else { - try stream.print(" ", .{}); - } - - try stream.print("--{s}", .{l}); - } - - switch (param.takes_value) { - .none => {}, - .one => try stream.print(" <{s}>", .{try valueText(context, param)}), - .one_optional => try stream.print(" <{s}>?", .{try valueText(context, param)}), - .many => try stream.print(" <{s}>...", .{try valueText(context, param)}), - } -} - -/// A wrapper around helpFull for simple helpText and valueText functions that -/// cant return an error or take a context. -pub fn helpEx( - stream: anytype, - comptime Id: type, - params: []const Param(Id), - helpText: *const fn (Param(Id)) []const u8, - valueText: *const fn (Param(Id)) []const u8, -) !void { - const Context = struct { - helpText: *const fn (Param(Id)) []const u8, - valueText: *const fn (Param(Id)) []const u8, - - pub fn help(c: @This(), p: Param(Id)) error{}![]const u8 { - return c.helpText(p); - } - - pub fn value(c: @This(), p: Param(Id)) error{}![]const u8 { - return c.valueText(p); - } - }; - - return helpFull( - stream, - Id, - params, - error{}, - Context{ - .helpText = helpText, - .valueText = valueText, - }, - Context.help, - Context.value, - ); -} - -pub fn simplePrintParam(param: Param(Help)) !void { - Output.pretty("\n", .{}); - if (param.names.short) |s| { - if (param.takes_value != .none and param.names.long == null) { - Output.pretty(" -{c}=\\", .{s}); - } else { - Output.pretty(" -{c}", .{s}); - } - } else { - Output.pretty(" ", .{}); - } - if (param.names.long) |l| { - if (param.names.short) |_| { - Output.pretty(", ", .{}); - } else { - Output.pretty(" ", .{}); - } - - if (param.takes_value != .none) { - Output.pretty("--{s}=\\", .{l}); - } else { - Output.pretty("--{s}", .{l}); - } - } else { - Output.pretty(" ", .{}); - } -} - -pub fn simpleHelp( - params: []const Param(Help), -) void { - const max_spacing = blk: { - var res: usize = 2; - for (params) |param| { - const flags_len = if (param.names.long) |l| l.len else 0; - const value_len: usize = if (param.takes_value != .none) 6 else 0; - if (res < flags_len + value_len) - res = flags_len + value_len; - } - - break :blk res; - }; - - for (params) |param| { - if (param.names.short == null and param.names.long == null) - continue; - - const desc_text = getHelpSimple(param); - if (desc_text.len == 0) continue; - - // create a string with spaces_len spaces - const default_allocator = bun.default_allocator; - - const flags_len = if (param.names.long) |l| l.len else 0; - const value_len: usize = if (param.takes_value != .none) 6 else 0; - const total_len = flags_len + value_len; - const num_spaces_after = max_spacing - total_len; - var spaces_after = default_allocator.alloc(u8, num_spaces_after) catch unreachable; - defer default_allocator.free(spaces_after); - for (0..num_spaces_after) |i| { - spaces_after[i] = ' '; - } - - simplePrintParam(param) catch unreachable; - Output.pretty(" {s} {s}", .{ spaces_after, desc_text }); - } -} - -pub fn simpleHelpBunTopLevel( - comptime params: []const Param(Help), -) void { - const max_spacing = 30; - const space_buf: *const [max_spacing]u8 = " " ** max_spacing; - - const computed_max_spacing = comptime blk: { - var res: usize = 2; - for (params) |param| { - const flags_len = if (param.names.long) |l| l.len else 0; - const value_len: usize = if (param.takes_value != .none) 6 else 0; - if (res < flags_len + value_len) - res = flags_len + value_len; - } - - break :blk res; - }; - - if (computed_max_spacing > max_spacing) { - @compileError("a parameter is too long to be nicely printed in `bun --help`"); - } - - inline for (params) |param| { - if (!(param.names.short == null and param.names.long == null)) { - const desc_text = comptime getHelpSimple(param); - if (desc_text.len != 0) { - simplePrintParam(param) catch unreachable; - - const flags_len = if (param.names.long) |l| l.len else 0; - const value_len: usize = if (param.takes_value != .none) 6 else 0; - const total_len = flags_len + value_len; - const num_spaces_after = max_spacing - total_len; - - Output.pretty(space_buf[0..num_spaces_after] ++ desc_text, .{}); - } - } - } -} - -pub const Help = struct { - msg: []const u8 = "", - value: []const u8 = "", -}; - -/// A wrapper around helpEx that takes a Param(Help). -pub fn help(stream: anytype, params: []const Param(Help)) !void { - try helpEx(stream, Help, params, getHelpSimple, getValueSimple); -} - -fn getHelpSimple(param: Param(Help)) []const u8 { - return param.id.msg; -} - -fn getValueSimple(param: Param(Help)) []const u8 { - return param.id.value; -} - -/// Will print a usage message in the following format: -/// [-abc] [--longa] [-d ] [--longb ] -/// -/// First all none value taking parameters, which have a short name are -/// printed, then non positional parameters and finally the positinal. -pub fn usageFull( - stream: anytype, - comptime Id: type, - params: []const Param(Id), - comptime Error: type, - context: anytype, - valueText: fn (@TypeOf(context), Param(Id)) Error![]const u8, -) !void { - var cos = io.countingWriter(stream); - const cs = cos.writer(); - for (params) |param| { - const name = param.names.short orelse continue; - if (param.takes_value != .none) - continue; - - if (cos.bytes_written == 0) - try stream.writeAll("[-"); - try cs.writeByte(name); - } - if (cos.bytes_written != 0) - try cs.writeByte(']'); - - var positional: ?Param(Id) = null; - for (params) |param| { - if (param.takes_value == .none and param.names.short != null) - continue; - - const prefix = if (param.names.short) |_| "-" else "--"; - - // Seems the zig compiler is being a little wierd. I doesn't allow me to write - // @as(*const [1]u8, s) VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV - const name = if (param.names.short) |*s| @as([*]const u8, @ptrCast(s))[0..1] else param.names.long orelse { - positional = param; - continue; - }; - if (cos.bytes_written != 0) - try cs.writeByte(' '); - - try cs.print("[{s}{s}", .{ prefix, name }); - switch (param.takes_value) { - .none => {}, - .one => try cs.print(" <{s}>", .{try valueText(context, param)}), - .one_optional => try cs.print(" <{s}>?", .{try valueText(context, param)}), - .many => try cs.print(" <{s}>...", .{try valueText(context, param)}), - } - - try cs.writeByte(']'); - } - - if (positional) |p| { - if (cos.bytes_written != 0) - try cs.writeByte(' '); - try cs.print("<{s}>", .{try valueText(context, p)}); - } -} - -/// A wrapper around usageFull for a simple valueText functions that -/// cant return an error or take a context. -pub fn usageEx( - stream: anytype, - comptime Id: type, - params: []const Param(Id), - valueText: fn (Param(Id)) []const u8, -) !void { - const Context = struct { - valueText: fn (Param(Id)) []const u8, - - pub fn value(c: @This(), p: Param(Id)) error{}![]const u8 { - return c.valueText(p); - } - }; - - return usageFull( - stream, - Id, - params, - error{}, - Context{ .valueText = valueText }, - Context.value, - ); -} - -/// A wrapper around usageEx that takes a Param(Help). -pub fn usage(stream: anytype, params: []const Param(Help)) !void { - try usageEx(stream, Help, params, getValueSimple); -} - -fn testUsage(expected: []const u8, params: []const Param(Help)) !void { - var buf: [1024]u8 = undefined; - var fbs = io.fixedBufferStream(&buf); - try usage(fbs.writer(), params); - testing.expectEqualStrings(expected, fbs.getWritten()); -} - -const Output = @import("../bun_core/output.zig"); -const bun = @import("bun"); - -const std = @import("std"); -const heap = std.heap; -const io = std.io; -const mem = std.mem; -const testing = std.testing; diff --git a/src/clap/comptime.zig b/src/clap/comptime.zig deleted file mode 100644 index a2a35c8d0164..000000000000 --- a/src/clap/comptime.zig +++ /dev/null @@ -1,199 +0,0 @@ -/// Deprecated: Use `parseEx` instead -pub fn ComptimeClap( - comptime Id: type, - comptime params: []const clap.Param(Id), -) type { - var _flags: usize = 0; - var _single_options: usize = 0; - var _multi_options: usize = 0; - var _converted_params: []const clap.Param(usize) = &[_]clap.Param(usize){}; - for (params) |param| { - var index: usize = 0; - if (param.names.long != null or param.names.short != null) { - const ptr = switch (param.takes_value) { - .none => &_flags, - .one_optional, .one => &_single_options, - .many => &_multi_options, - }; - index = ptr.*; - ptr.* += 1; - } - - const converted = clap.Param(usize){ - .id = index, - .names = param.names, - .takes_value = param.takes_value, - }; - _converted_params = _converted_params ++ [_]clap.Param(usize){converted}; - } - const flags = _flags; - const single_options = _single_options; - const multi_options = _multi_options; - const converted_params = _converted_params; - - return struct { - single_options: [single_options]?[]const u8, - multi_options: [multi_options][]const []const u8, - flags: [flags]bool, - pos: []const []const u8, - passthrough_positionals: []const []const u8, - allocator: mem.Allocator, - - pub fn parse(iter: anytype, opt: clap.ParseOptions) !@This() { - const allocator = opt.allocator; - var multis = [_]std.array_list.Managed([]const u8){undefined} ** multi_options; - for (&multis) |*multi| { - multi.* = std.array_list.Managed([]const u8).init(allocator); - } - - var pos = std.array_list.Managed([]const u8).init(allocator); - var passthrough_positionals = std.array_list.Managed([]const u8).init(allocator); - - var res = @This(){ - .single_options = [_]?[]const u8{null} ** single_options, - .multi_options = [_][]const []const u8{undefined} ** multi_options, - .flags = [_]bool{false} ** flags, - .pos = undefined, - .allocator = allocator, - .passthrough_positionals = undefined, - }; - - var stream = clap.StreamingClap(usize, @typeInfo(@TypeOf(iter)).pointer.child){ - .params = converted_params, - .iter = iter, - .diagnostic = opt.diagnostic, - }; - - while (try stream.next()) |arg| { - const param = arg.param; - if (param.names.long == null and param.names.short == null) { - try pos.append(arg.value.?); - if (opt.stop_after_positional_at > 0 and pos.items.len >= opt.stop_after_positional_at) { - var remaining_ = stream.iter.remain; - const first: []const u8 = if (remaining_.len > 0) bun.span(remaining_[0]) else ""; - if (first.len > 0 and std.mem.eql(u8, first, "--")) { - remaining_ = remaining_[1..]; - } - - try passthrough_positionals.ensureTotalCapacityPrecise(remaining_.len); - for (remaining_) |arg_| { - // use bun.span due to the optimization for long strings - passthrough_positionals.appendAssumeCapacity(bun.span(arg_)); - } - break; - } - } else if (param.takes_value == .one or param.takes_value == .one_optional) { - debug.assert(res.single_options.len != 0); - if (res.single_options.len != 0) - res.single_options[param.id] = arg.value orelse ""; - } else if (param.takes_value == .many) { - debug.assert(multis.len != 0); - if (multis.len != 0) - try multis[param.id].append(arg.value.?); - } else { - debug.assert(res.flags.len != 0); - if (res.flags.len != 0) - res.flags[param.id] = true; - } - } - - for (&multis, 0..) |*multi, i| - res.multi_options[i] = try multi.toOwnedSlice(); - res.pos = try pos.toOwnedSlice(); - res.passthrough_positionals = try passthrough_positionals.toOwnedSlice(); - return res; - } - - pub fn deinit(parser: @This()) void { - for (parser.multi_options) |o| - parser.allocator.free(o); - parser.allocator.free(parser.pos); - } - - pub fn flag(parser: @This(), comptime name: []const u8) bool { - const param = comptime findParam(name); - if (param.takes_value != .none and param.takes_value != .one_optional) - @compileError(name ++ " is an option and not a flag."); - - return parser.flags[param.id]; - } - - pub fn option(parser: @This(), comptime name: []const u8) ?[]const u8 { - const param = comptime findParam(name); - if (param.takes_value == .none) - @compileError(name ++ " is a flag and not an option."); - if (param.takes_value == .many) - @compileError(name ++ " takes many options, not one."); - return parser.single_options[param.id]; - } - - pub fn options(parser: @This(), comptime name: []const u8) []const []const u8 { - const param = comptime findParam(name); - if (param.takes_value == .none) - @compileError(name ++ " is a flag and not an option."); - if (param.takes_value == .one or param.takes_value == .one_optional) - @compileError(name ++ " takes one option, not multiple."); - - return parser.multi_options[param.id]; - } - - pub fn positionals(parser: @This()) []const []const u8 { - return parser.pos; - } - - pub fn remaining(parser: @This()) []const []const u8 { - return parser.passthrough_positionals; - } - - pub fn hasFlag(comptime name: []const u8) bool { - comptime { - for (converted_params) |param| { - if (param.names.short) |s| { - if (mem.eql(u8, name, "-" ++ [_]u8{s})) - return true; - } - if (param.names.long) |l| { - if (mem.eql(u8, name, "--" ++ l)) - return true; - } - // Check aliases - for (param.names.long_aliases) |alias| { - if (mem.eql(u8, name, "--" ++ alias)) - return true; - } - } - - return false; - } - } - - fn findParam(comptime name: []const u8) clap.Param(usize) { - comptime { - for (converted_params) |param| { - if (param.names.short) |s| { - if (mem.eql(u8, name, "-" ++ [_]u8{s})) - return param; - } - if (param.names.long) |l| { - if (mem.eql(u8, name, "--" ++ l)) - return param; - } - // Check aliases - for (param.names.long_aliases) |alias| { - if (mem.eql(u8, name, "--" ++ alias)) - return param; - } - } - - @compileError(name ++ " is not a parameter."); - } - } - }; -} - -const bun = @import("bun"); -const clap = @import("./clap.zig"); - -const std = @import("std"); -const debug = std.debug; -const mem = std.mem; diff --git a/src/clap/gyro.zzz b/src/clap/gyro.zzz deleted file mode 100644 index 3853db0493ad..000000000000 --- a/src/clap/gyro.zzz +++ /dev/null @@ -1,14 +0,0 @@ -pkgs: - clap: - version: 0.3.0 - license: Unlicense - description: Simple command line argument parsing library - source_url: "https://github.com/Hejsil/zig-clap" - root: clap.zig - files: - README.md - LICENSE - build.zig - clap/*.zig - example/*.zig - diff --git a/src/clap/streaming.zig b/src/clap/streaming.zig deleted file mode 100644 index 37ac8691a78d..000000000000 --- a/src/clap/streaming.zig +++ /dev/null @@ -1,449 +0,0 @@ -// Disabled because not all CLI arguments are parsed with Clap. -pub var warn_on_unrecognized_flag = false; - -/// The result returned from StreamingClap.next -pub fn Arg(comptime Id: type) type { - return struct { - const Self = @This(); - - param: *const clap.Param(Id), - value: ?[]const u8 = null, - }; -} - -/// A command line argument parser which, given an ArgIterator, will parse arguments according -/// to the params. StreamingClap parses in an iterating manner, so you have to use a loop together with -/// StreamingClap.next to parse all the arguments of your program. -pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { - return struct { - const State = union(enum) { - normal, - chaining: Chaining, - rest_are_positional, - - const Chaining = struct { - arg: []const u8, - index: usize, - }; - }; - - const ArgError = error{ DoesntTakeValue, MissingValue, InvalidArgument }; - - params: []const clap.Param(Id), - iter: *ArgIterator, - state: State = .normal, - positional: ?*const clap.Param(Id) = null, - diagnostic: ?*clap.Diagnostic = null, - - /// Get the next Arg that matches a Param. - pub fn next(parser: *@This()) ArgError!?Arg(Id) { - switch (parser.state) { - .normal => return try parser.normal(), - .chaining => |state| return try parser.chainging(state), - .rest_are_positional => { - const param = parser.positionalParam() orelse unreachable; - const value = parser.iter.next() orelse return null; - return Arg(Id){ .param = param, .value = value }; - }, - } - } - - fn normal(parser: *@This()) ArgError!?Arg(Id) { - const ArgType = Arg(Id); - const arg_info = (try parser.parseNextArg()) orelse return null; - const arg = arg_info.arg; - - switch (arg_info.kind) { - .long => { - const eql_index = mem.indexOfScalar(u8, arg, '='); - const name = if (eql_index) |i| arg[0..i] else arg; - - const maybe_value = if (eql_index) |i| arg[i + 1 ..] else null; - - for (parser.params) |*param| { - if (!param.names.matchesLong(name)) - continue; - - if (param.takes_value == .none or param.takes_value == .one_optional) { - if (param.takes_value == .none and maybe_value != null) { - return parser.err(arg, .{ .long = name }, error.DoesntTakeValue); - } - - return ArgType{ .param = param, .value = maybe_value }; - } - - const value = blk: { - if (maybe_value) |v| - break :blk v; - - break :blk parser.iter.next() orelse { - return parser.err(arg, .{ .long = name }, error.MissingValue); - }; - }; - - return ArgType{ .param = param, .value = value }; - } - - // unrecognized command - // if flag else arg - if (arg_info.kind == .long or arg_info.kind == .short) { - if (warn_on_unrecognized_flag) { - Output.warn("unrecognized flag: {s}{s}\n", .{ if (arg_info.kind == .long) "--" else "-", name }); - Output.flush(); - } - - // continue parsing after unrecognized flag - return parser.next(); - } - - if (warn_on_unrecognized_flag) { - Output.warn("unrecognized argument: {s}\n", .{name}); - Output.flush(); - } - return null; - }, - .short => return try parser.chainging(.{ - .arg = arg, - .index = 0, - }), - .positional => if (parser.positionalParam()) |param| { - // If we find a positional with the value `--` then we - // interpret the rest of the arguments as positional - // arguments. - if (mem.eql(u8, arg, "--")) { - parser.state = .rest_are_positional; - // return null to terminate arg parsing - const value = parser.iter.next() orelse return null; - return Arg(Id){ .param = param, .value = value }; - } - - return Arg(Id){ .param = param, .value = arg }; - } else { - return parser.err(arg, .{}, error.InvalidArgument); - }, - } - } - - fn chainging(parser: *@This(), state: State.Chaining) ArgError!?Arg(Id) { - const arg = state.arg; - const index = state.index; - const next_index = index + 1; - - for (parser.params) |*param| { - const short = param.names.short orelse continue; - if (short != arg[index]) - continue; - - // Before we return, we have to set the new state of the clap - defer { - if (arg.len <= next_index or param.takes_value != .none) { - parser.state = .normal; - } else { - parser.state = .{ - .chaining = .{ - .arg = arg, - .index = next_index, - }, - }; - } - } - - const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; - if (param.takes_value == .none or param.takes_value == .one_optional) { - if (next_is_eql and param.takes_value == .none) - return parser.err(arg, .{ .short = short }, error.DoesntTakeValue); - return Arg(Id){ .param = param }; - } - - if (arg.len <= next_index) { - const value = parser.iter.next() orelse - return parser.err(arg, .{ .short = short }, error.MissingValue); - - return Arg(Id){ .param = param, .value = value }; - } - - if (next_is_eql) - return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] }; - - return Arg(Id){ .param = param, .value = arg[next_index..] }; - } - - return parser.err(arg, .{ .short = arg[index] }, error.InvalidArgument); - } - - fn positionalParam(parser: *@This()) ?*const clap.Param(Id) { - if (parser.positional) |p| - return p; - - for (parser.params) |*param| { - if (param.names.long) |_| - continue; - if (param.names.short) |_| - continue; - - parser.positional = param; - return param; - } - - return null; - } - - const ArgInfo = struct { - arg: []const u8, - kind: enum { - long, - short, - positional, - }, - }; - - fn parseNextArg(parser: *@This()) ArgError!?ArgInfo { - const full_arg = parser.iter.next() orelse return null; - if (mem.eql(u8, full_arg, "--") or mem.eql(u8, full_arg, "-")) - return ArgInfo{ .arg = full_arg, .kind = .positional }; - if (mem.startsWith(u8, full_arg, "--")) - return ArgInfo{ .arg = full_arg[2..], .kind = .long }; - if (mem.startsWith(u8, full_arg, "-")) - return ArgInfo{ .arg = full_arg[1..], .kind = .short }; - - return ArgInfo{ .arg = full_arg, .kind = .positional }; - } - - fn err(parser: @This(), arg: []const u8, names: clap.Names, _err: anytype) @TypeOf(_err) { - if (parser.diagnostic) |d| - d.* = .{ .arg = arg, .name = names }; - return _err; - } - }; -} - -fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, results: []const Arg(u8)) void { - var iter = args.SliceIterator{ .args = args_strings }; - var c = StreamingClap(u8, args.SliceIterator){ - .params = params, - .iter = &iter, - }; - - for (results) |res| { - const arg = (c.next() catch unreachable) orelse unreachable; - testing.expectEqual(res.param, arg.param); - const expected_value = res.value orelse { - testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); - continue; - }; - const actual_value = arg.value orelse unreachable; - testing.expectEqualSlices(u8, expected_value, actual_value); - } - - if (c.next() catch unreachable) |_| - unreachable; -} - -fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, expected: []const u8) void { - var diag = clap.Diagnostic{}; - var iter = args.SliceIterator{ .args = args_strings }; - var c = StreamingClap(u8, args.SliceIterator){ - .params = params, - .iter = &iter, - .diagnostic = &diag, - }; - while (c.next() catch |err| { - var buf: [1024]u8 = undefined; - var fbs = io.fixedBufferStream(&buf); - diag.report(fbs.writer(), err) catch unreachable; - testing.expectEqualStrings(expected, fbs.getWritten()); - return; - }) |_| {} - - testing.expect(false); -} - -test "short params" { - const params = [_]clap.Param(u8){ - .{ .id = 0, .names = .{ .short = 'a' } }, - .{ .id = 1, .names = .{ .short = 'b' } }, - .{ - .id = 2, - .names = .{ .short = 'c' }, - .takes_value = .one, - }, - .{ - .id = 3, - .names = .{ .short = 'd' }, - .takes_value = .many, - }, - }; - - const a = ¶ms[0]; - const b = ¶ms[1]; - const c = ¶ms[2]; - const d = ¶ms[3]; - - testNoErr( - ¶ms, - &[_][]const u8{ - "-a", "-b", "-ab", "-ba", - "-c", "0", "-c=0", "-ac", - "0", "-ac=0", "-d=0", - }, - &[_]Arg(u8){ - .{ .param = a }, - .{ .param = b }, - .{ .param = a }, - .{ .param = b }, - .{ .param = b }, - .{ .param = a }, - .{ .param = c, .value = "0" }, - .{ .param = c, .value = "0" }, - .{ .param = a }, - .{ .param = c, .value = "0" }, - .{ .param = a }, - .{ .param = c, .value = "0" }, - .{ .param = d, .value = "0" }, - }, - ); -} - -test "long params" { - const params = [_]clap.Param(u8){ - .{ .id = 0, .names = .{ .long = "aa" } }, - .{ .id = 1, .names = .{ .long = "bb" } }, - .{ - .id = 2, - .names = .{ .long = "cc" }, - .takes_value = .one, - }, - .{ - .id = 3, - .names = .{ .long = "dd" }, - .takes_value = .many, - }, - }; - - const aa = ¶ms[0]; - const bb = ¶ms[1]; - const cc = ¶ms[2]; - const dd = ¶ms[3]; - - testNoErr( - ¶ms, - &[_][]const u8{ - "--aa", "--bb", - "--cc", "0", - "--cc=0", "--dd=0", - }, - &[_]Arg(u8){ - .{ .param = aa }, - .{ .param = bb }, - .{ .param = cc, .value = "0" }, - .{ .param = cc, .value = "0" }, - .{ .param = dd, .value = "0" }, - }, - ); -} - -test "positional params" { - const params = [_]clap.Param(u8){.{ - .id = 0, - .takes_value = .one, - }}; - - testNoErr( - ¶ms, - &[_][]const u8{ "aa", "bb" }, - &[_]Arg(u8){ - .{ .param = ¶ms[0], .value = "aa" }, - .{ .param = ¶ms[0], .value = "bb" }, - }, - ); -} - -test "all params" { - const params = [_]clap.Param(u8){ - .{ - .id = 0, - .names = .{ .short = 'a', .long = "aa" }, - }, - .{ - .id = 1, - .names = .{ .short = 'b', .long = "bb" }, - }, - .{ - .id = 2, - .names = .{ .short = 'c', .long = "cc" }, - .takes_value = .one, - }, - .{ .id = 3, .takes_value = .one }, - }; - - const aa = ¶ms[0]; - const bb = ¶ms[1]; - const cc = ¶ms[2]; - const positional = ¶ms[3]; - - testNoErr( - ¶ms, - &[_][]const u8{ - "-a", "-b", "-ab", "-ba", - "-c", "0", "-c=0", "-ac", - "0", "-ac=0", "--aa", "--bb", - "--cc", "0", "--cc=0", "something", - "-", "--", "--cc=0", "-a", - }, - &[_]Arg(u8){ - .{ .param = aa }, - .{ .param = bb }, - .{ .param = aa }, - .{ .param = bb }, - .{ .param = bb }, - .{ .param = aa }, - .{ .param = cc, .value = "0" }, - .{ .param = cc, .value = "0" }, - .{ .param = aa }, - .{ .param = cc, .value = "0" }, - .{ .param = aa }, - .{ .param = cc, .value = "0" }, - .{ .param = aa }, - .{ .param = bb }, - .{ .param = cc, .value = "0" }, - .{ .param = cc, .value = "0" }, - .{ .param = positional, .value = "something" }, - .{ .param = positional, .value = "-" }, - .{ .param = positional, .value = "--cc=0" }, - .{ .param = positional, .value = "-a" }, - }, - ); -} - -test "errors" { - const params = [_]clap.Param(u8){ - .{ - .id = 0, - .names = .{ .short = 'a', .long = "aa" }, - }, - .{ - .id = 1, - .names = .{ .short = 'c', .long = "cc" }, - .takes_value = .one, - }, - }; - testErr(¶ms, &[_][]const u8{"q"}, "Invalid argument 'q'\n"); - testErr(¶ms, &[_][]const u8{"-q"}, "Invalid argument '-q'\n"); - testErr(¶ms, &[_][]const u8{"--q"}, "Invalid argument '--q'\n"); - testErr(¶ms, &[_][]const u8{"--q=1"}, "Invalid argument '--q'\n"); - testErr(¶ms, &[_][]const u8{"-a=1"}, "The argument '-a' does not take a value\n"); - testErr(¶ms, &[_][]const u8{"--aa=1"}, "The argument '--aa' does not take a value\n"); - testErr(¶ms, &[_][]const u8{"-c"}, "The argument '-c' requires a value but none was supplied\n"); - testErr(¶ms, &[_][]const u8{"--cc"}, "The argument '--cc' requires a value but none was supplied\n"); -} - -const clap = @import("./clap.zig"); -const args = clap.args; - -const bun = @import("bun"); -const Output = bun.Output; - -const std = @import("std"); -const io = std.io; -const mem = std.mem; -const testing = std.testing; diff --git a/src/clap/zig.mod b/src/clap/zig.mod deleted file mode 100644 index 00c1a690d589..000000000000 --- a/src/clap/zig.mod +++ /dev/null @@ -1,5 +0,0 @@ -id: aoe2l16htluewam6bfwvv0khsbbno8g8jd7suonifg74u7kd -name: clap -main: clap.zig -license: Unlicense -dependencies: diff --git a/src/codegen/bake-codegen.ts b/src/codegen/bake-codegen.ts index b60a3dba613e..1eaf4ff7239c 100644 --- a/src/codegen/bake-codegen.ts +++ b/src/codegen/bake-codegen.ts @@ -14,18 +14,21 @@ if (!codegenRoot) { const base_dir = join(import.meta.dirname, "../runtime/bake"); process.chdir(base_dir); // to make bun build predictable in development -function convertZigEnum(zig: string, names: string[]) { - let output = "/** Generated from DevServer.zig */\n"; +function convertRustEnum(rust: string, names: string[]) { + let output = "/** Generated from dev_server/mod.rs */\n"; for (const name of names) { - const startTrigger = `\npub const ${name} = enum(u8) {`; - const start = zig.indexOf(startTrigger) + startTrigger.length; - const endTrigger = /\n pub (inline )?fn |\n};/g; - const end = zig.slice(start).search(endTrigger) + start; - const enumText = zig.slice(start, end); - const values = enumText.replaceAll("\n ", "\n ").replace(/\n\s*(\w+)\s*=\s*'(.+?)',/g, (_, name, value) => { - return `\n ${name} = ${value.charCodeAt(0)},`; - }); - output += `export const enum ${name} {${values}}\n`; + const startTrigger = `\npub enum ${name} {`; + const start = rust.indexOf(startTrigger); + if (start === -1) throw new Error(`bake-codegen: enum ${name} not found in dev_server/mod.rs`); + const bodyStart = start + startTrigger.length; + const end = rust.indexOf("\n}", bodyStart); + let values = ""; + for (const m of rust.slice(bodyStart, end).matchAll(/^\s*(\w+)\s*=\s*b'(.)'\s*,?/gm)) { + const snake = m[1].replace(/([a-z0-9])([A-Z])/g, "$1_$2").toLowerCase(); + values += `\n ${snake} = ${m[2].charCodeAt(0)},`; + } + if (!values) throw new Error(`bake-codegen: no variants extracted from enum ${name}`); + output += `export const enum ${name} {${values}\n}\n`; } return output; } @@ -41,8 +44,8 @@ function css(file: string, is_development: boolean): string { } async function run() { - const devServerZig = readFileSync(join(base_dir, "DevServer.zig"), "utf-8"); - writeIfNotChanged(join(base_dir, "generated.ts"), convertZigEnum(devServerZig, ["IncomingMessageId", "MessageId"])); + const devServerRust = readFileSync(join(base_dir, "dev_server/mod.rs"), "utf-8"); + writeIfNotChanged(join(base_dir, "generated.ts"), convertRustEnum(devServerRust, ["IncomingMessageId", "MessageId"])); const results = await Promise.allSettled( ["client", "server", "error"].map(async file => { diff --git a/src/codegen/bindgen.ts b/src/codegen/bindgen.ts index 2584f2a38083..295d83fc9a51 100644 --- a/src/codegen/bindgen.ts +++ b/src/codegen/bindgen.ts @@ -4,7 +4,6 @@ // Generated bindings are available as `bun.generated..*` on the native side, // or `Generated::::*` in C++ from including `Generated.h`. import assert from "node:assert"; -import fs from "node:fs"; import * as path from "node:path"; import { ArgStrategyChildItem, @@ -1164,15 +1163,7 @@ const unsortedFiles = readdirRecursiveWithExclusionsAndExtensionsSync(src, ["nod // Sort for deterministic output for (const fileName of [...unsortedFiles].sort()) { const zigFile = path.relative(src, fileName.replace(/\.bind\.ts$/, ".zig")); - const zigFilePath = path.join(src, zigFile); let file = files.get(zigFile); - if (!fs.existsSync(zigFilePath)) { - // It would be nice if this would generate the file with the correct boilerplate - const bindName = path.basename(fileName); - throw new Error( - `${bindName} is missing a corresponding Zig file at ${zigFile}. Please create it and make sure it matches signatures in ${bindName}.`, - ); - } if (!file) { file = { functions: [], typedefs: [] }; files.set(zigFile, file); @@ -1588,7 +1579,6 @@ writeIfNotChanged( path.join(codegenRoot, "GeneratedBindings.cpp"), [...headers].map(name => `#include ${str(name)}\n`).join("") + "\n" + cppInternal.buffer + "\n" + cpp.buffer, ); -writeIfNotChanged(path.join(src, "jsc/bindings/GeneratedBindings.zig"), zig.buffer + zigInternal.buffer); // Headers for (const [filename, { functions, typedefs }] of files) { diff --git a/src/codegen/bindgenv2/internal/base.ts b/src/codegen/bindgenv2/internal/base.ts index 93732f3fbd58..51c76d7b40e6 100644 --- a/src/codegen/bindgenv2/internal/base.ts +++ b/src/codegen/bindgenv2/internal/base.ts @@ -56,9 +56,6 @@ export abstract class NamedType extends Type { get cppSource(): string | null { return null; } - get zigSource(): string | null { - return null; - } // These getters are faster than `.cppHeader != null` etc. get hasCppHeader(): boolean { return false; @@ -66,9 +63,6 @@ export abstract class NamedType extends Type { get hasCppSource(): boolean { return false; } - get hasZigSource(): boolean { - return false; - } getHeaders(result: Set): void { result.add(`Generated${this.name}.h`); } diff --git a/src/codegen/bindgenv2/internal/dictionary.ts b/src/codegen/bindgenv2/internal/dictionary.ts index 47598e9e50c0..529e46042fa4 100644 --- a/src/codegen/bindgenv2/internal/dictionary.ts +++ b/src/codegen/bindgenv2/internal/dictionary.ts @@ -256,92 +256,6 @@ export function dictionary( })()} `); } - - get hasZigSource() { - return true; - } - get zigSource() { - return reindent(` - pub const ${name} = struct { - const Self = @This(); - - ${joinIndented( - 10, - fullMembers.map(memberInfo => { - return `${memberInfo.internalName}: ${memberInfo.type.zigType("pretty")},`; - }), - )} - - pub fn deinit(self: *Self) void { - ${joinIndented( - 12, - fullMembers.map(memberInfo => { - return `bun.memory.deinit(&self.${memberInfo.internalName});`; - }), - )} - self.* = undefined; - }${(() => { - if (!generateConversionFunction) { - return ""; - } - const result = dedent(` - pub fn fromJS(globalThis: *jsc.JSGlobalObject, value: jsc.JSValue) bun.JSError!Self { - var scope: jsc.ExceptionValidationScope = undefined; - scope.init(globalThis, @src()); - defer scope.deinit(); - var extern_result: Extern${name} = undefined; - const success = bindgenConvertJSTo${name}(globalThis, value, &extern_result); - scope.assertExceptionPresenceMatches(!success); - return if (success) - Bindgen${name}.convertFromExtern(extern_result) - else - error.JSError; - } - `); - return addIndent(10, "\n" + result); - })()} - }; - - pub const Bindgen${name} = struct { - const Self = @This(); - pub const ZigType = ${name}; - pub const ExternType = Extern${name}; - pub fn convertFromExtern(extern_value: Self.ExternType) Self.ZigType { - return .{ - ${joinIndented( - 14, - fullMembers.map(memberInfo => { - const internalName = memberInfo.internalName; - const bindgenType = memberInfo.type.bindgenType; - const rhs = `${bindgenType}.convertFromExtern(extern_value.${internalName})`; - return `.${internalName} = ${rhs},`; - }), - )} - }; - } - }; - - const Extern${name} = extern struct { - ${joinIndented( - 10, - fullMembers.map(memberInfo => { - return `${memberInfo.internalName}: ${memberInfo.type.bindgenType}.ExternType,`; - }), - )} - }; - - extern fn bindgenConvertJSTo${name}( - globalObject: *jsc.JSGlobalObject, - value: jsc.JSValue, - result: *Extern${name}, - ) bool; - - const bindgen_generated = @import("bindgen_generated"); - const bun = @import("bun"); - const bindgen = bun.bun_js.bindgen; - const jsc = bun.bun_js.jsc; - `); - } })(); } diff --git a/src/codegen/bindgenv2/internal/enumeration.ts b/src/codegen/bindgenv2/internal/enumeration.ts index 2839fbeab564..502487717b3f 100644 --- a/src/codegen/bindgenv2/internal/enumeration.ts +++ b/src/codegen/bindgenv2/internal/enumeration.ts @@ -173,23 +173,5 @@ export function enumeration( } `); } - - get hasZigSource() { - return true; - } - get zigSource() { - return reindent(` - pub const ${name} = enum(u32) { - ${joinIndented( - 10, - uniqueValues.map(value => `@${toQuotedLiteral(value)},`), - )} - }; - - pub const Bindgen${name} = bindgen.BindgenTrivial(${name}); - const bun = @import("bun"); - const bindgen = bun.bun_js.bindgen; - `); - } })(); } diff --git a/src/codegen/bindgenv2/internal/union.ts b/src/codegen/bindgenv2/internal/union.ts index 737f8c4f6f59..7f9fe8f6b61c 100644 --- a/src/codegen/bindgenv2/internal/union.ts +++ b/src/codegen/bindgenv2/internal/union.ts @@ -132,54 +132,5 @@ export function union( } `); } - - get hasZigSource() { - return true; - } - get zigSource() { - return reindent(` - pub const ${name} = union(enum) { - ${joinIndented( - 10, - Object.entries(namedAlternatives).map(([altName, altType]) => { - return `${altName}: ${altType.zigType("pretty")},`; - }), - )} - - pub fn deinit(self: *@This()) void { - switch (std.meta.activeTag(self.*)) { - inline else => |tag| bun.memory.deinit(&@field(self, @tagName(tag))), - } - self.* = undefined; - } - }; - - pub const Bindgen${name} = struct { - const Self = @This(); - pub const ZigType = ${name}; - pub const ExternType = bindgen.ExternTaggedUnion(&.{ ${alternatives - .map(a => a.bindgenType + ".ExternType") - .join(", ")} }); - pub fn convertFromExtern(extern_value: Self.ExternType) Self.ZigType { - return switch (extern_value.tag) { - ${joinIndented( - 14, - Object.entries(namedAlternatives).map(([altName, altType], i) => { - const bindgenType = altType.bindgenType; - const innerRhs = `${bindgenType}.convertFromExtern(extern_value.data.@"${i}")`; - return `${i} => .{ .${altName} = ${innerRhs} },`; - }), - )} - else => unreachable, - }; - } - }; - - const bindgen_generated = @import("bindgen_generated"); - const std = @import("std"); - const bun = @import("bun"); - const bindgen = bun.bun_js.bindgen; - `); - } })(); } diff --git a/src/codegen/bindgenv2/script.ts b/src/codegen/bindgenv2/script.ts index aafeacabb51d..a057d1a0725c 100755 --- a/src/codegen/bindgenv2/script.ts +++ b/src/codegen/bindgenv2/script.ts @@ -42,16 +42,6 @@ function cppSourcePath(type: NamedType): string { return `${codegenPath}/Generated${type.name}.cpp`; } -function zigSourcePath(typeOrNamespace: NamedType | string): string { - let ns: string; - if (typeof typeOrNamespace === "string") { - ns = typeOrNamespace; - } else { - ns = toZigNamespace(typeOrNamespace.name); - } - return `${codegenPath}/bindgen_generated/${ns}.zig`; -} - function toZigNamespace(name: string): string { const result = name .replace(/([^A-Z_])([A-Z])/g, "$1_$2") @@ -64,18 +54,15 @@ function toZigNamespace(name: string): string { } function listOutputs(): void { - const outputs: string[] = [`${codegenPath}/bindgen_generated.zig`]; + const outputs: string[] = []; for (const type of getNamedExports()) { if (type.hasCppSource) outputs.push(cppSourcePath(type)); - if (type.hasZigSource) outputs.push(zigSourcePath(type)); } process.stdout.write(outputs.join(";")); } function generate(): void { const names = new Set(); - const zigRoot: string[] = []; - const zigRootInternal: string[] = []; const namedExports = getNamedExports(); { @@ -111,34 +98,13 @@ function generate(): void { const cppHeader = type.cppHeader; const cppSource = type.cppSource; - const zigSource = type.zigSource; if (cppHeader) { helpers.writeIfNotChanged(cppHeaderPath(type), cppHeader); } if (cppSource) { helpers.writeIfNotChanged(cppSourcePath(type), cppSource); } - if (zigSource) { - zigRoot.push( - `pub const ${zigNamespace} = @import("./bindgen_generated/${zigNamespace}.zig");`, - `pub const ${type.name} = ${zigNamespace}.${type.name};`, - "", - ); - zigRootInternal.push(`pub const ${type.name} = ${zigNamespace}.Bindgen${type.name};`); - helpers.writeIfNotChanged(zigSourcePath(zigNamespace), zigSource); - } } - - helpers.writeIfNotChanged( - `${codegenPath}/bindgen_generated.zig`, - [ - ...zigRoot, - `pub const internal = struct {`, - ...zigRootInternal.map(s => " " + s), - `};`, - "", - ].join("\n"), - ); } function main(): void { diff --git a/src/codegen/bundle-modules.ts b/src/codegen/bundle-modules.ts index 1ddd7082fe15..45372839c33f 100644 --- a/src/codegen/bundle-modules.ts +++ b/src/codegen/bundle-modules.ts @@ -15,7 +15,7 @@ import path from "path"; import jsclasses from "./../jsc/bindings/js_classes"; import { sliceSourceCode } from "./builtin-parser"; import { createAssertClientJS, createLogClientJS } from "./client-js"; -import { getJS2NativeCPP, getJS2NativeRust, getJS2NativeZig } from "./generate-js2native"; +import { getJS2NativeCPP, getJS2NativeRust } from "./generate-js2native"; import { cap, declareASCIILiteral, writeIfNotChanged } from "./helpers"; import { createInternalModuleRegistry } from "./internal-module-registry-scanner"; import { define } from "./replacements"; @@ -477,10 +477,6 @@ writeIfNotChanged( writeIfNotChanged(path.join(CODEGEN_DIR, "GeneratedJS2Native.h"), getJS2NativeCPP()); -// zig will complain if this file is outside of the module -const js2nativeZigPath = path.join(import.meta.dir, "../jsc/bindings/GeneratedJS2Native.zig"); -writeIfNotChanged(js2nativeZigPath, getJS2NativeZig(js2nativeZigPath)); - // Rust sibling: include!()'d by src/runtime/generated_js2native.rs writeIfNotChanged(path.join(CODEGEN_DIR, "generated_js2native.rs"), getJS2NativeRust()); diff --git a/src/codegen/ci_info.ts b/src/codegen/ci_info.ts deleted file mode 100644 index 4797ecd1a53d..000000000000 --- a/src/codegen/ci_info.ts +++ /dev/null @@ -1,454 +0,0 @@ -type Vendor = { - name: string; - constant: string; - env: EnvMatch; - pr?: unknown; -}; -type EnvMatch = - | string - | EnvMatch[] - | { - env: string; - includes: string; - } - | { - any: string[]; - } - | Record; - -// The vendors list is copied from https://github.com/watson/ci-info/blob/master/vendors.json -// The extras list is copied and edited from https://github.com/watson/ci-info/blob/master/index.js line `exports.isCI = !!(...)` -// To update, copy the JSON again. -/* -The MIT License (MIT) - -Copyright (c) 2016 Thomas Watson Steen - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ -const extras: string[] = [ - "BUILD_ID", // Jenkins, Cloudbees - "BUILD_NUMBER", // Jenkins, TeamCity - "CI", // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari, Cloudflare Pages/Workers - "CI_APP_ID", // Appflow - "CI_BUILD_ID", // Appflow - "CI_BUILD_NUMBER", // Appflow - "CI_NAME", // Codeship and others - "CONTINUOUS_INTEGRATION", // Travis CI, Cirrus CI - "RUN_ID", // TaskCluster, dsari -]; -const vendors: Vendor[] = [ - { - "name": "Agola CI", - "constant": "AGOLA", - "env": "AGOLA_GIT_REF", - "pr": "AGOLA_PULL_REQUEST_ID", - }, - { - "name": "Appcircle", - "constant": "APPCIRCLE", - "env": "AC_APPCIRCLE", - "pr": { - "env": "AC_GIT_PR", - "ne": "false", - }, - }, - { - "name": "AppVeyor", - "constant": "APPVEYOR", - "env": "APPVEYOR", - "pr": "APPVEYOR_PULL_REQUEST_NUMBER", - }, - { - "name": "AWS CodeBuild", - "constant": "CODEBUILD", - "env": "CODEBUILD_BUILD_ARN", - "pr": { - "env": "CODEBUILD_WEBHOOK_EVENT", - "any": ["PULL_REQUEST_CREATED", "PULL_REQUEST_UPDATED", "PULL_REQUEST_REOPENED"], - }, - }, - { - "name": "Azure Pipelines", - "constant": "AZURE_PIPELINES", - "env": "TF_BUILD", - "pr": { - "BUILD_REASON": "PullRequest", - }, - }, - { - "name": "Bamboo", - "constant": "BAMBOO", - "env": "bamboo_planKey", - }, - { - "name": "Bitbucket Pipelines", - "constant": "BITBUCKET", - "env": "BITBUCKET_COMMIT", - "pr": "BITBUCKET_PR_ID", - }, - { - "name": "Bitrise", - "constant": "BITRISE", - "env": "BITRISE_IO", - "pr": "BITRISE_PULL_REQUEST", - }, - { - "name": "Buddy", - "constant": "BUDDY", - "env": "BUDDY_WORKSPACE_ID", - "pr": "BUDDY_EXECUTION_PULL_REQUEST_ID", - }, - { - "name": "Buildkite", - "constant": "BUILDKITE", - "env": "BUILDKITE", - "pr": { - "env": "BUILDKITE_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "CircleCI", - "constant": "CIRCLE", - "env": "CIRCLECI", - "pr": "CIRCLE_PULL_REQUEST", - }, - { - "name": "Cirrus CI", - "constant": "CIRRUS", - "env": "CIRRUS_CI", - "pr": "CIRRUS_PR", - }, - { - "name": "Cloudflare Pages", - "constant": "CLOUDFLARE_PAGES", - "env": "CF_PAGES", - }, - { - "name": "Cloudflare Workers", - "constant": "CLOUDFLARE_WORKERS", - "env": "WORKERS_CI", - }, - { - "name": "Codefresh", - "constant": "CODEFRESH", - "env": "CF_BUILD_ID", - "pr": { - "any": ["CF_PULL_REQUEST_NUMBER", "CF_PULL_REQUEST_ID"], - }, - }, - { - "name": "Codemagic", - "constant": "CODEMAGIC", - "env": "CM_BUILD_ID", - "pr": "CM_PULL_REQUEST", - }, - { - "name": "Codeship", - "constant": "CODESHIP", - "env": { - "CI_NAME": "codeship", - }, - }, - { - "name": "Drone", - "constant": "DRONE", - "env": "DRONE", - "pr": { - "DRONE_BUILD_EVENT": "pull_request", - }, - }, - { - "name": "dsari", - "constant": "DSARI", - "env": "DSARI", - }, - { - "name": "Earthly", - "constant": "EARTHLY", - "env": "EARTHLY_CI", - }, - { - "name": "Expo Application Services", - "constant": "EAS", - "env": "EAS_BUILD", - }, - { - "name": "Gerrit", - "constant": "GERRIT", - "env": "GERRIT_PROJECT", - }, - { - "name": "Gitea Actions", - "constant": "GITEA_ACTIONS", - "env": "GITEA_ACTIONS", - }, - { - "name": "GitHub Actions", - "constant": "GITHUB_ACTIONS", - "env": "GITHUB_ACTIONS", - "pr": { - "GITHUB_EVENT_NAME": "pull_request", - }, - }, - { - "name": "GitLab CI", - "constant": "GITLAB", - "env": "GITLAB_CI", - "pr": "CI_MERGE_REQUEST_ID", - }, - { - "name": "GoCD", - "constant": "GOCD", - "env": "GO_PIPELINE_LABEL", - }, - { - "name": "Google Cloud Build", - "constant": "GOOGLE_CLOUD_BUILD", - "env": "BUILDER_OUTPUT", - }, - { - "name": "Harness CI", - "constant": "HARNESS", - "env": "HARNESS_BUILD_ID", - }, - { - "name": "Heroku", - "constant": "HEROKU", - "env": { - "env": "NODE", - "includes": "/app/.heroku/node/bin/node", - }, - }, - { - "name": "Hudson", - "constant": "HUDSON", - "env": "HUDSON_URL", - }, - { - "name": "Jenkins", - "constant": "JENKINS", - "env": ["JENKINS_URL", "BUILD_ID"], - "pr": { - "any": ["ghprbPullId", "CHANGE_ID"], - }, - }, - { - "name": "LayerCI", - "constant": "LAYERCI", - "env": "LAYERCI", - "pr": "LAYERCI_PULL_REQUEST", - }, - { - "name": "Magnum CI", - "constant": "MAGNUM", - "env": "MAGNUM", - }, - { - "name": "Netlify CI", - "constant": "NETLIFY", - "env": "NETLIFY", - "pr": { - "env": "PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Nevercode", - "constant": "NEVERCODE", - "env": "NEVERCODE", - "pr": { - "env": "NEVERCODE_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Prow", - "constant": "PROW", - "env": "PROW_JOB_ID", - }, - { - "name": "ReleaseHub", - "constant": "RELEASEHUB", - "env": "RELEASE_BUILD_ID", - }, - { - "name": "Render", - "constant": "RENDER", - "env": "RENDER", - "pr": { - "IS_PULL_REQUEST": "true", - }, - }, - { - "name": "Sail CI", - "constant": "SAIL", - "env": "SAILCI", - "pr": "SAIL_PULL_REQUEST_NUMBER", - }, - { - "name": "Screwdriver", - "constant": "SCREWDRIVER", - "env": "SCREWDRIVER", - "pr": { - "env": "SD_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Semaphore", - "constant": "SEMAPHORE", - "env": "SEMAPHORE", - "pr": "PULL_REQUEST_NUMBER", - }, - { - "name": "Sourcehut", - "constant": "SOURCEHUT", - "env": { - "CI_NAME": "sourcehut", - }, - }, - { - "name": "Strider CD", - "constant": "STRIDER", - "env": "STRIDER", - }, - { - "name": "TaskCluster", - "constant": "TASKCLUSTER", - "env": ["TASK_ID", "RUN_ID"], - }, - { - "name": "TeamCity", - "constant": "TEAMCITY", - "env": "TEAMCITY_VERSION", - }, - { - "name": "Travis CI", - "constant": "TRAVIS", - "env": "TRAVIS", - "pr": { - "env": "TRAVIS_PULL_REQUEST", - "ne": "false", - }, - }, - { - "name": "Vela", - "constant": "VELA", - "env": "VELA", - "pr": { - "VELA_PULL_REQUEST": "1", - }, - }, - { - "name": "Vercel", - "constant": "VERCEL", - "env": { - "any": ["NOW_BUILDER", "VERCEL"], - }, - "pr": "VERCEL_GIT_PULL_REQUEST_ID", - }, - { - "name": "Visual Studio App Center", - "constant": "APPCENTER", - "env": "APPCENTER_BUILD_ID", - }, - { - "name": "Woodpecker", - "constant": "WOODPECKER", - "env": { - "CI": "woodpecker", - }, - "pr": { - "CI_BUILD_EVENT": "pull_request", - }, - }, - { - "name": "Xcode Cloud", - "constant": "XCODE_CLOUD", - "env": "CI_XCODE_PROJECT", - "pr": "CI_PULL_REQUEST_NUMBER", - }, - { - "name": "Xcode Server", - "constant": "XCODE_SERVER", - "env": "XCS", - }, -]; - -function genEnvCondition(env: EnvMatch): string { - if (typeof env === "string") { - return `bun.getenvZ(${JSON.stringify(env)}) != null`; - } else if (Array.isArray(env)) { - return env - .map(itm => { - const res = genEnvCondition(itm); - if (res.includes(" or ")) return `(${res})`; - return res; - }) - .join(" and "); - } else if (typeof env === "object") { - if ("env" in env) { - return `bun.strings.containsComptime(bun.getenvZ(${JSON.stringify(env.env)}) orelse "", ${JSON.stringify(env.includes)})`; - } else if ("any" in env) { - return (env.any as string[]).map(genEnvCondition).join(" or "); - } else { - return Object.entries(env) - .map( - ([key, value]) => - `bun.strings.eqlComptime(bun.getenvZ(${JSON.stringify(key)}) orelse "", ${JSON.stringify(value)})`, - ) - .join(" and "); - } - } else throw new Error("Not implemented"); -} - -let codegen: string[] = []; -codegen.push(`/// Generated by src/codegen/ci_info.ts\n`); -codegen.push(`pub fn isCIUncachedGenerated() bool {\n`); -for (const extra of extras) { - codegen.push(` if (${genEnvCondition(extra)}) return true;\n`); -} -codegen.push(` return false;\n`); -codegen.push(`}\n`); -codegen.push(`\n`); -codegen.push(`/// Generated by src/codegen/ci_info.ts\n`); -codegen.push(`pub fn detectUncachedGenerated() ?[]const u8 {\n`); -for (const vendor of vendors) { - // Names are changed to match what `npm publish` uses - // https://github.com/npm/cli/blob/63d6a732c3c0e9c19fd4d147eaa5cc27c29b168d/workspaces/config/lib/definitions/definitions.js#L2129 - const npm_style_name = vendor.name.toLowerCase().replaceAll(" ", "-"); - codegen.push(` if (${genEnvCondition(vendor.env)}) return ${JSON.stringify(npm_style_name)};\n`); -} -codegen.push(` return null;\n`); -codegen.push(`}\n`); -codegen.push(`\n`); -codegen.push(`const bun = @import("bun");\n`); -const result = codegen.join(""); - -if (import.meta.main) { - const args = process.argv.slice(2); - const out = args[0]; - if (out) { - await Bun.write(out, result); - } else { - console.log(result); - } -} diff --git a/src/codegen/class-definitions.ts b/src/codegen/class-definitions.ts index 86827d34c65b..0c46abd9a049 100644 --- a/src/codegen/class-definitions.ts +++ b/src/codegen/class-definitions.ts @@ -92,15 +92,12 @@ export class ClassDefinition { */ name: string; /** - * Which language implements the native side of this class. + * Legacy. All classes emit implementer thunks into `generated_classes.rs`; + * this field is accepted for backward compatibility but has no effect. * - * The C++ wrapper output (`ZigGeneratedClasses.{h,cpp}`) is byte-identical - * regardless of this flag — it only selects whether the implementer thunks - * land in `ZigGeneratedClasses.zig` or `generated_classes.rs`. - * - * @default "zig" + * @default "rust" */ - lang?: "zig" | "rust"; + lang?: "rust"; /** * Fully-qualified Rust path of the native struct backing this class, e.g. * `crate::webcore::request::Request`. The codegen emits @@ -160,43 +157,32 @@ export class ClassDefinition { * You _must_ free the pointer to your native class! * * Example for pointers only owned by JavaScript classes: - * ```zig - * pub const NativeClass = struct { - * - * fn constructor(global: *JSC.JSGlobalObject, frame: *JSC.CallFrame) bun.JSError!*SocketAddress { - * // do stuff - * return bun.new(NativeClass, .{ - * // ... - * }); - * } + * ```rust + * impl NativeClass { + * pub fn constructor(global: &JSGlobalObject, frame: &CallFrame) -> JsResult> { + * // do stuff + * Ok(Box::new(NativeClass { + * // ... + * })) + * } * - * fn finalize(this: *NativeClass) void { - * // free allocations owned by this class, then free the struct itself. - * bun.destroy(this); - * } - * }; + * pub fn finalize(self: Box) { + * // free allocations owned by this class; Box drop frees the struct itself. + * } + * } * ``` * Example with ref counting: - * ``` - * pub const RefCountedNativeClass = struct { - * const RefCount = bun.ptr.RefCount(@This(), "ref_count", deinit, .{}); - * pub const ref = RefCount.ref; - * pub const deref = RefCount.deref; - * - * fn constructor(global: *JSC.JSGlobalObject, frame: *JSC.CallFrame) bun.JSError!*SocketAddress { - * // do stuff - * return bun.new(NativeClass, .{ - * // ... - * }); - * } - * - * fn deinit(this: *NativeClass) void { - * // free allocations owned by this class, then free the struct itself. - * bun.destroy(this); - * } + * ```rust + * impl RefCountedNativeClass { + * pub fn constructor(global: &JSGlobalObject, frame: &CallFrame) -> JsResult<*mut Self> { + * // do stuff; refcount starts at 1 + * Ok(Self::new(...).into_raw()) + * } * - * pub const finalize = deref; // GC will deref, which can free if no references are left. - * }; + * pub fn finalize(&mut self) { + * self.deref(); // GC drops its ref; frees when the count hits zero. + * } + * } * ``` * @todo remove this and require all classes to implement `finalize`. */ @@ -229,15 +215,15 @@ export class ClassDefinition { final?: boolean; /** - * Class has an `estimatedSize` function that reports external allocations to GC. + * Class has an `estimated_size` function that reports external allocations to GC. * Called from any thread. * * When `true`, classes should have a method with this signature: - * ```zig - * pub fn estimatedSize(this: *@This()) usize; + * ```rust + * pub fn estimated_size(&self) -> usize; * ``` * - * Report `@sizeOf(@this())` as well as any external allocations. + * Report `size_of::()` as well as any external allocations. */ estimatedSize?: boolean; /** diff --git a/src/codegen/cppbind.ts b/src/codegen/cppbind.ts index f5b3f479d780..b3f10957ae40 100644 --- a/src/codegen/cppbind.ts +++ b/src/codegen/cppbind.ts @@ -81,7 +81,7 @@ type SyntaxNode = import("@lezer/common").SyntaxNode; const { parser: cppParser } = await import("@lezer/cpp"); const { mkdir } = await import("fs/promises"); const { join, relative } = await import("path"); -const { bannedTypes, sharedTypes, typeDeclarations } = await import("./shared-types"); +const { bannedTypes } = await import("./shared-types"); type Point = { line: number; @@ -555,6 +555,9 @@ function generateRustType(type: CppType, parent: CppType | null): string { throwError(type.position, "void must have a pointer parent or no parent"); } if (type.type === "named") { + if (bannedTypes[type.name]) { + appendError(type.position, bannedTypes[type.name]); + } const t = rustSharedTypes[type.name]; if (t) return t; // Unknown opaque — only valid behind a pointer (the per-type shim casts the @@ -661,13 +664,25 @@ function generateRustFn(fn: CppFn, rustRaw: string[], rustWrap: string[]): void const globalArg = fn.parameters.find(p => isGlobalObjectPtr(p.type)); if (!globalArg) { - // Emit a stub so the module still - // compiles and the symbol name is greppable. + appendError(fn.position, `no JSGlobalObject* parameter found (required for ZIG_EXPORT(${fn.tag}))`); rustWrap.push(`// skipped ${fn.name}: ${fn.tag} requires a JSGlobalObject* parameter`); return; } const gname = rustIdent(globalArg.name); + if (fn.tag === "zero_is_throw" && ret !== "crate::JSValue") { + appendError(fn.position, "ZIG_EXPORT(zero_is_throw) is only allowed for functions that return JSValue"); + } else if (fn.tag === "false_is_throw" && ret !== "bool") { + appendError(fn.position, "ZIG_EXPORT(false_is_throw) is only allowed for functions that return bool"); + } else if (fn.tag === "null_is_throw" && fn.returnType.type !== "pointer") { + appendError(fn.position, "ZIG_EXPORT(null_is_throw) is only allowed for functions that return a pointer"); + } else if (fn.tag === "check_slow" && ret === "crate::JSValue") { + appendError( + fn.position, + "Use ZIG_EXPORT(zero_is_throw) instead of ZIG_EXPORT(check_slow) for functions that return JSValue", + ); + } + if (fn.tag === "check_slow") { // Inline the `top_scope!` body (rather than the `call_check_slow` *function* form, // which routes `SourceLocation::from_caller()` → thread-local intern probe per call @@ -724,81 +739,6 @@ function generateRustFn(fn: CppFn, rustRaw: string[], rustWrap: string[]): void ); } -const sharedTypesText = await Bun.file("src/codegen/shared-types.ts").text(); -const sharedTypesLines = sharedTypesText.split("\n"); -let sharedTypesLine = 0; -let sharedTypesColumn = 0; -let sharedTypesColumnEnd = 0; -for (const line of sharedTypesLines) { - sharedTypesLine++; - if (line.includes("export const sharedTypes")) { - sharedTypesColumn = line.indexOf("sharedTypes") + 1; - sharedTypesColumnEnd = sharedTypesColumn + "sharedTypes".length; - break; - } -} - -const errorsForTypes: Map = new Map(); -function generateZigType(type: CppType, parent: CppType | null) { - if (type.type === "pointer") { - const optionalChar = type.isNonNull ? "" : "?"; - const ptrChar = type.isMany ? "[*]" : "*"; - const constChar = type.isConst ? "const " : ""; - return `${optionalChar}${ptrChar}${constChar}${generateZigType(type.child, type)}`; - } - if (type.type === "fn") { - return `fn(${type.parameters.map(p => formatZigName(p.name) + ": " + generateZigType(p.type, null)).join(", ")}) callconv(.c) ${generateZigType(type.returnType, null)}`; - } - if (type.type === "named" && type.name === "void") { - if (parent?.type === "pointer") return "anyopaque"; - if (!parent) return "void"; - throwError(type.position, "void must have a pointer parent or no parent"); - } - if (type.type === "named") { - const bannedType = bannedTypes[type.name]; - if (bannedType) { - appendError(type.position, bannedType); - return "anyopaque"; - } - const sharedType = sharedTypes[type.name]; - if (sharedType) return sharedType; - const error = errorsForTypes.has(type.name) - ? errorsForTypes.get(type.name)! - : appendError( - { - file: "src/codegen/shared-types.ts", - start: { line: sharedTypesLine, column: sharedTypesColumn }, - end: { line: sharedTypesLine, column: sharedTypesColumnEnd }, - }, - "sharedTypes is missing type: " + JSON.stringify(type.name), - ); - errorsForTypes.set(type.name, error); - error.notes.push({ position: type.position, message: "used in exported function here" }); - return "anyopaque"; - } - assertNever(type); -} -function formatZigName(name: string): string { - if (name.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) return name; - return "@" + JSON.stringify(name); -} -function generateZigParameterList(parameters: CppParameter[], globalThisArg?: CppParameter): string { - return parameters - .map(p => { - if (p === globalThisArg) { - return `${formatZigName(p.name)}: *jsc.JSGlobalObject`; - } else { - return `${formatZigName(p.name)}: ${generateZigType(p.type, null)}`; - } - }) - .join(", "); -} -function generateZigSourceComment(cfg: Cfg, resultSourceLinks: string[], fn: CppFn): string { - const fileName = relative(cfg.dstDir, fn.position.file); - resultSourceLinks.push(`${fn.name}:${fileName}:${fn.position.start.line}:${fn.position.start.column}`); - return `/// Source: ${fn.name}`; -} - function closest(node: SyntaxNode | null, type: string): SyntaxNode | null { while (node) { if (node.name === type) return node; @@ -958,99 +898,6 @@ async function renderError(position: Srcloc, message: string, label: string, col type Cfg = { dstDir: string; }; -function generateZigFn( - fn: CppFn, - resultRaw: string[], - resultBindings: string[], - resultSourceLinks: string[], - cfg: Cfg, -): void { - let returnType = generateZigType(fn.returnType, null); - if (resultBindings.length) resultBindings.push(""); - resultBindings.push(generateZigSourceComment(cfg, resultSourceLinks, fn)); - if (fn.tag === "nothrow") { - resultBindings.push( - `pub extern fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters)}) ${returnType};`, - ); - return; - } - - resultRaw.push(` extern fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters)}) ${returnType};`); - let globalThisArg: CppParameter | undefined; - for (const param of fn.parameters) { - const type = generateZigType(param.type, null); - if (type === "?*jsc.JSGlobalObject") { - globalThisArg = param; - break; - } - } - if (!globalThisArg) throwError(fn.position, "no globalThis argument found (required for " + fn.tag + ")"); - if (fn.tag === "check_slow") { - if (returnType === "jsc.JSValue") { - appendError( - fn.position, - "Use ZIG_EXPORT(zero_is_throw) instead of ZIG_EXPORT(check_slow) for functions that return JSValue", - ); - } - resultBindings.push( - `pub fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) error{JSError}!${returnType} {`, - ` if (comptime Environment.ci_assert) {`, - ` var scope: jsc.TopExceptionScope = undefined;`, - ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, - ` defer scope.deinit();`, - ``, - ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` try scope.returnIfException();`, - ` return result;`, - ` } else {`, - ` const result = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` if (Bun__RETURN_IF_EXCEPTION(${formatZigName(globalThisArg.name)})) return error.JSError;`, - ` return result;`, - ` }`, - `}`, - ); - return; - } - - let equalsValue: string; - if (fn.tag === "zero_is_throw") { - equalsValue = ".zero"; - if (returnType !== "jsc.JSValue") { - appendError(fn.position, "ZIG_EXPORT(zero_is_throw) is only allowed for functions that return JSValue"); - } - } else if (fn.tag === "false_is_throw") { - equalsValue = "false"; - if (returnType !== "bool") { - appendError(fn.position, "ZIG_EXPORT(false_is_throw) is only allowed for functions that return bool"); - } - returnType = "void"; - } else if (fn.tag === "null_is_throw") { - equalsValue = "null"; - if (!returnType.startsWith("?*")) { - appendError(fn.position, "ZIG_EXPORT(null_is_throw) is only allowed for functions that return optional pointer"); - } - returnType = returnType.slice(1); - } else assertNever(fn.tag); - resultBindings.push( - `pub fn ${formatZigName(fn.name)}(${generateZigParameterList(fn.parameters, globalThisArg)}) error{JSError}!${returnType} {`, - ` if (comptime Environment.ci_assert) {`, - ` var scope: jsc.ExceptionValidationScope = undefined;`, - ` scope.init(${formatZigName(globalThisArg.name)}, @src());`, - ` defer scope.deinit();`, - ``, - ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` scope.assertExceptionPresenceMatches(value == ${equalsValue});`, - ` return if (value == ${equalsValue}) error.JSError ${fn.tag === "false_is_throw" ? "" : "else value"}${fn.tag === "null_is_throw" ? ".?" : ""};`, - ` } else {`, - ` const value = raw.${formatZigName(fn.name)}(${fn.parameters.map(p => formatZigName(p.name)).join(", ")});`, - ` if (value == ${equalsValue}) return error.JSError;`, - ...(fn.tag === "false_is_throw" ? [] : [` return value${fn.tag === "null_is_throw" ? ".?" : ""};`]), - ` }`, - `}`, - ); - return; -} - async function readFileOrEmpty(file: string): Promise { try { const fileContents = await Bun.file(file).text(); @@ -1103,17 +950,9 @@ async function main() { await Promise.all(allCppFiles.map(file => processFile(parser, file, allFunctions))); allFunctions.sort((a, b) => (a.position.file < b.position.file ? -1 : a.position.file > b.position.file ? 1 : 0)); - const resultRaw: string[] = []; - const resultBindings: string[] = []; - const resultSourceLinks: string[] = []; const rustRaw: string[] = []; const rustWrap: string[] = []; for (const fn of allFunctions) { - try { - generateZigFn(fn, resultRaw, resultBindings, resultSourceLinks, { dstDir }); - } catch (e) { - appendErrorFromCatch(e, fn.position); - } try { generateRustFn(fn, rustRaw, rustWrap); } catch (e) { @@ -1129,18 +968,6 @@ async function main() { console.error(); } - const resultFilePath = join(dstDir, "cpp.zig"); - const resultContents = - typeDeclarations + - "\n" + - resultBindings.join("\n") + - "\n\nconst raw = struct {\n" + - resultRaw.join("\n") + - "\n};\n"; - if ((await readFileOrEmpty(resultFilePath)) !== resultContents) { - await Bun.write(resultFilePath, resultContents); - } - const rustFilePath = join(dstDir, "cpp.rs"); const rustContents = "// generated by cppbind.ts from functions marked with [[ZIG_EXPORT(mode)]]\n" + @@ -1157,24 +984,17 @@ async function main() { await Bun.write(rustFilePath, rustContents); } - const resultSourceLinksFilePath = join(dstDir, "cpp.source-links"); - const resultSourceLinksContents = resultSourceLinks.join("\n"); - if ((await readFileOrEmpty(resultSourceLinksFilePath)) !== resultSourceLinksContents) { - await Bun.write(resultSourceLinksFilePath, resultSourceLinksContents); + if (process.env.CI) { const now = Date.now(); - const sin = Math.round(((Math.sin((now / 1000) * 1) + 1) / 2) * 0); - if (process.env.CI) { - console.log( - " ".repeat(sin) + - (errors.length > 0 ? "✗" : "✓") + - " cppbind.ts generated bindings to " + - resultFilePath + - (errors.length > 0 ? " with errors" : "") + - " in " + - (now - start) + - "ms", - ); - } + console.log( + (errors.length > 0 ? "✗" : "✓") + + " cppbind.ts generated bindings to " + + rustFilePath + + (errors.length > 0 ? " with errors" : "") + + " in " + + (now - start) + + "ms", + ); } if (errors.length > 0) { diff --git a/src/codegen/generate-classes.ts b/src/codegen/generate-classes.ts index b659bb334bf0..718ca1fbfef0 100644 --- a/src/codegen/generate-classes.ts +++ b/src/codegen/generate-classes.ts @@ -3,7 +3,7 @@ import { existsSync, readFileSync } from "fs"; import path from "path"; import jsclasses from "./../jsc/bindings/js_classes"; import { InvalidThisBehavior, type ClassDefinition, type Field } from "./class-definitions"; -import { camelCase, pascalCase, writeIfNotChanged } from "./helpers"; +import { writeIfNotChanged } from "./helpers"; if (process.env.BUN_SILENT === "1") { console.log = () => {}; @@ -79,26 +79,6 @@ function DOMJITType(type) { }[type]; } -function ZigDOMJITArgType(type) { - return { - ["bool"]: "bool", - ["int"]: "i32", - ["JSUint8Array"]: "*jsc.JSUint8Array", - ["JSString"]: "*jsc.JSString", - ["JSValue"]: "jsc.JSValue", - }[type]; -} - -function ZigDOMJITArgTypeDefinition(type, index) { - return `arg${index}: ${ZigDOMJITArgType(type)}`; -} - -function ZigDOMJITFunctionType(thisName, { args, returns }) { - return `fn (*${thisName}, *jsc.JSGlobalObject, ${args - .map(ZigDOMJITArgType) - .join(", ")}) callconv(jsc.conv) ${ZigDOMJITArgType("JSValue")}`; -} - function DOMJITReturnType(type) { return { ["bool"]: "bool", @@ -865,59 +845,6 @@ function renderCallbacksCppImpl(typeName, callbacks: Record) { return rows.map(a => a.trim()).join("\n"); } -function renderCallbacksZig(typeName, callbacks: Record) { - if (Object.keys(callbacks).length === 0) return ""; - - var out = - "\n" + - `pub const Callbacks = struct { - instance: jsc.JSValue,` + - "\n"; - - for (const name in callbacks) { - const get = symbolName(typeName, "_callback_get_" + name); - const set = symbolName(typeName, "_callback_set_" + name); - out += ` - extern fn ${get}(jsc.JSValue) callconv(jsc.conv) jsc.JSValue; - extern fn ${set}(jsc.JSValue, jsc.JSValue) callconv(jsc.conv) void; - pub const ${pascalCase(name)}Callback = jsc.Codegen.CallbackWrapper(${get}, ${set}); - pub fn ${camelCase(name)}(cb: @This(), thisValue: jsc.JSValue, globalObject: *jsc.JSGlobalObject, args: []const jsc.JSValue) ?jsc.JSValue { - return ${pascalCase(name)}Callback.call(.{.instance = cb.instance}, thisValue, globalObject, args); - } - `; - } - - out = out.trim(); - - out += ` - extern fn ${symbolName(typeName, "_setAllCallbacks")}(jsc.JSValue, ${Object.keys(callbacks) - .map((a, i) => `callback${i}: jsc.JSValue`) - .join(", ")}) callconv(jsc.conv) void; - - pub inline fn set(this: @This(), values: struct { - ${Object.keys(callbacks) - .map((name, i) => `${camelCase(name)}: jsc.JSValue = .zero,`) - .join("\n")} - }) void { - ${symbolName(typeName, "_setAllCallbacks")}(this.instance, ${Object.keys(callbacks) - .map((name, i) => `values.${camelCase(name)}`) - .join(", ")},); - } - `; - - out += "\n};\n"; - - out += ` - - pub fn callbacks(_: *const ${typeName}, instance: jsc.JSValue) Callbacks { - return .{.instance = instance }; - } - -`; - - return "\n" + out; -} - function renderDecls(symbolName, typeName, proto, supportsObjectCreate = false) { const rows = []; @@ -2037,536 +1964,10 @@ function generateImpl(typeName, obj: ClassDefinition) { .join("\n\n"); } -function generateZig( - typeName, - { - klass = {}, - proto = {}, - own = {}, - construct, - constructNeedsThis = false, - finalize, - noConstructor = false, - overridesToJS = false, - estimatedSize, - call = false, - memoryCost, - values = [], - valuesArray = false, - hasPendingActivity = false, - structuredClone = false, - getInternalProperties = false, - callbacks = {}, - } = {} as ClassDefinition, -) { - const exports = new Map(); - - if (hasPendingActivity) { - exports.set("hasPendingActivity", symbolName(typeName, "hasPendingActivity")); - } - - if (getInternalProperties) { - exports.set("getInternalProperties", symbolName(typeName, "getInternalProperties")); - } - - if (structuredClone) { - exports.set("onStructuredCloneSerialize", symbolName(typeName, "onStructuredCloneSerialize")); - - if (typeof structuredClone === "object" && structuredClone.transferable) { - exports.set("onStructuredCloneTransfer", symbolName(typeName, "onStructuredCloneTransfer")); - } - - exports.set("onStructuredCloneDeserialize", symbolName(typeName, "onStructuredCloneDeserialize")); - } - - proto = { - ...Object.fromEntries(Object.entries(own || {}).map(([name, getterName]) => [name, { getter: getterName }])), - ...proto, - }; - - const gc_fields = Object.entries({ - ...proto, - ...Object.fromEntries((values || []).map(a => [a, { internal: true }])), - }).filter(([name, { cache, internal }]) => (cache && typeof cache !== "string") || internal); - - const cached_values_string = - gc_fields.length > 0 - ? ` - pub const gc = enum (u8) { - ${gc_fields.map(([name]) => `${name},`).join("\n")} - - pub fn get(comptime field: gc, thisValue: jsc.JSValue) ?jsc.JSValue { - const value = switch (field) { - ${gc_fields - .map(([name]) => ` .${name} => ${protoSymbolName(typeName, name)}GetCachedValue(thisValue),`) - .join("\n ")} - }; - - if (value == .zero) { - return null; - } - - return value; - } - - pub fn clear(comptime field: gc, thisValue: jsc.JSValue, globalObject: *jsc.JSGlobalObject) void { - field.set(thisValue, globalObject, .zero); - } - - pub fn set(comptime field: gc, thisValue: jsc.JSValue, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void { - switch (field) { - ${gc_fields - .map( - ([name]) => - ` .${name} => ${protoSymbolName(typeName, name)}SetCachedValue(thisValue, globalObject, value),`, - ) - .join("\n")} - } - } - }; - ` - : ""; - - const externs = gc_fields - .map( - ([name]) => - `extern fn ${protoSymbolName(typeName, name)}SetCachedValue(jsc.JSValue, *jsc.JSGlobalObject, jsc.JSValue) callconv(jsc.conv) void; - - extern fn ${protoSymbolName(typeName, name)}GetCachedValue(jsc.JSValue) callconv(jsc.conv) jsc.JSValue; - - /// \`${typeName}.${name}\` setter - /// This value will be visited by the garbage collector. - pub fn ${name}SetCached(thisValue: jsc.JSValue, globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) void { - jsc.markBinding(@src()); - ${protoSymbolName(typeName, name)}SetCachedValue(thisValue, globalObject, value); - } - - /// \`${typeName}.${name}\` getter - /// This value will be visited by the garbage collector. - pub fn ${name}GetCached(thisValue: jsc.JSValue) ?jsc.JSValue { - jsc.markBinding(@src()); - const result = ${protoSymbolName(typeName, name)}GetCachedValue(thisValue); - if (result == .zero) - return null; - - return result; - } -`.trim() + "\n", - ) - .join("\n"); - - var renderedCallbacks = ""; - if (Object.keys(callbacks).length) { - renderedCallbacks = renderCallbacksZig(typeName, callbacks); - } - - function renderMethods() { - const exports = new Map(); - var output = ` -const JavaScriptCoreBindings = struct { - -`; - - if (memoryCost) { - exports.set("memoryCost", symbolName(typeName, "memoryCost")); - output += ` - pub fn ${symbolName(typeName, "memoryCost")}(thisValue: *${typeName}) callconv(jsc.conv) usize { - return @call(bun.callmod_inline, ${typeName}.memoryCost, .{thisValue}); - } - `; - } - - if (estimatedSize) { - exports.set("estimatedSize", symbolName(typeName, "estimatedSize")); - output += ` - pub fn ${symbolName(typeName, "estimatedSize")}(thisValue: *${typeName}) callconv(jsc.conv) usize { - return @call(bun.callmod_inline, ${typeName}.estimatedSize, .{thisValue}); - } - `; - } else if (!memoryCost && !estimatedSize) { - output += ` - export const ${symbolName(typeName, "ZigStructSize")}: usize = @sizeOf(${typeName}); - `; - } - - if (hasPendingActivity) { - exports.set("hasPendingActivity", symbolName(typeName, "hasPendingActivity")); - output += ` - pub fn ${symbolName(typeName, "hasPendingActivity")}(thisValue: *${typeName}) callconv(jsc.conv) bool { - return @call(bun.callmod_inline, ${typeName}.hasPendingActivity, .{thisValue}); - } - `; - } - - if (finalize) { - exports.set("finalize", classSymbolName(typeName, "finalize")); - output += ` - pub fn ${classSymbolName(typeName, "finalize")}(thisValue: *${typeName}) callconv(jsc.conv) void { - if (comptime Environment.enable_logs) log_zig_finalize("${typeName}", thisValue); - @call(bun.callmod_inline, ${typeName}.finalize, .{thisValue}); - } - `; - } - - if (construct && !noConstructor) { - exports.set("construct", classSymbolName(typeName, "construct")); - if (constructNeedsThis) { - output += ` - pub fn ${classSymbolName(typeName, "construct")}(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame, thisValue: jsc.JSValue) callconv(jsc.conv) ?*anyopaque { - if (comptime Environment.enable_logs) log_zig_constructor("${typeName}", callFrame); - return @as(*${typeName}, ${typeName}.constructor(globalObject, callFrame, thisValue) catch |err| switch (err) { - error.JSError => return null, - error.OutOfMemory => { - globalObject.throwOutOfMemory() catch {}; - return null; - }, - error.JSTerminated => return null, - }); - } - `; - } else { - output += ` - pub fn ${classSymbolName(typeName, "construct")}(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) callconv(jsc.conv) ?*anyopaque { - if (comptime Environment.enable_logs) log_zig_constructor("${typeName}", callFrame); - return @as(*${typeName}, ${typeName}.constructor(globalObject, callFrame) catch |err| switch (err) { - error.JSError => return null, - error.OutOfMemory => { - globalObject.throwOutOfMemory() catch {}; - return null; - }, - error.JSTerminated => return null, - }); - } - `; - } - } - - if (call) { - exports.set("call", classSymbolName(typeName, "call")); - output += ` - pub fn ${classSymbolName(typeName, "call")}(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_call("${typeName}", callFrame); - return @call(bun.callmod_inline, jsc.toJSHostFn(${typeName}.call), .{globalObject, callFrame}); - } - `; - } - - if (getInternalProperties) { - exports.set("getInternalProperties", classSymbolName(typeName, "getInternalProperties")); - output += ` - pub fn ${classSymbolName(typeName, "getInternalProperties")}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, thisValue: jsc.JSValue) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_get_internal_properties("${typeName}"); - return @call(bun.callmod_inline, ${typeName}.getInternalProperties, .{thisValue, globalObject, thisValue}); - } - `; - } - - { - const exportNames = name => zigExportName(exports, name => protoSymbolName(typeName, name), proto[name]); - for (const name in proto) { - const { getter, setter, accessor, fn, this: thisValue = false, cache, DOMJIT } = proto[name]; - const names = exportNames(name); - if (names.getter) { - output += ` - pub fn ${names.getter}(this: *${typeName}, ${thisValue ? "thisValue: jsc.JSValue," : ""} globalObject: *jsc.JSGlobalObject) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_getter("${typeName}", "${name}"); - return switch (@typeInfo(@typeInfo(@TypeOf(${typeName}.${getter})).@"fn".return_type.?)) { - .error_union => { - return @call(bun.callmod_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${getter}, .{this, ${thisValue ? "thisValue," : ""} globalObject}}); - }, - else => @call(bun.callmod_inline, ${typeName}.${getter}, .{this, ${thisValue ? "thisValue," : ""} globalObject}), - }; - } - `; - } - - if (names.setter) { - output += ` - pub fn ${names.setter}(this: *${typeName}, ${thisValue ? "thisValue: jsc.JSValue," : ""} globalObject: *jsc.JSGlobalObject, value: jsc.JSValue) callconv(jsc.conv) bool { - if (comptime Environment.enable_logs) log_zig_setter("${typeName}", "${name}", value); - switch (@typeInfo(@typeInfo(@TypeOf(${typeName}.${setter})).@"fn".return_type.?)) { - .error_union => |error_union| { - if (error_union.payload != void) { - @compileError("Setter return type must be JSError!void or void"); - } - return @call(bun.callmod_inline, jsc.host_fn.toJSHostSetterValue, .{globalObject, @call(bun.callmod_inline, ${typeName}.${setter}, .{this, ${thisValue ? "thisValue," : ""} globalObject, value})}); - }, - .void => { - @call(bun.callmod_inline, ${typeName}.${setter}, .{this, ${thisValue ? "thisValue," : ""} globalObject, value}); - return true; - }, - else => @compileError("Setter return type must be JSError!void or void"), - } - } - `; - } - - if (names.fn) { - if (names.DOMJIT) { - const { args, returns } = DOMJIT; - output += ` - pub fn ${names.DOMJIT}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, ${args - .map(ZigDOMJITArgTypeDefinition) - .join(", ")}) callconv(jsc.conv) jsc.JSValue { - return @call(bun.callmod_inline, ${typeName}.${DOMJITName(fn)}, .{thisValue, globalObject, ${args.map((_, i) => `arg${i}`).join(", ")}}); - } - `; - } - - output += ` - pub fn ${names.fn}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame${proto[name].passThis ? ", js_this_value: jsc.JSValue" : ""}) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_method("${typeName}", "${name}", callFrame); - return @call(bun.callmod_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${fn}, .{thisValue, globalObject, callFrame${proto[name].passThis ? ", js_this_value" : ""}}}); - } - `; - } - } - } - - { - const exportNames = name => zigExportName(exports, name => classSymbolName(typeName, name), klass[name]); - for (const name in klass) { - const { getter, setter, accessor, fn, this: thisValue = true, cache, DOMJIT } = klass[name]; - const names = exportNames(name); - if (names.getter) { - output += ` - pub fn ${names.getter}(globalObject: *jsc.JSGlobalObject, ${thisValue ? "thisValue: jsc.JSValue," : ""} propertyName: jsc.JSValue) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_class_getter("${typeName}", "${name}"); - return switch (@typeInfo(@typeInfo(@TypeOf(${typeName}.${getter})).@"fn".return_type.?)) { - .error_union => { - return @call(bun.callmod_inline, jsc.toJSHostCall, .{globalObject, @src(), ${typeName}.${getter}, .{globalObject, ${thisValue ? "thisValue," : ""} propertyName}}); - }, - else => { - return @call(bun.callmod_inline, ${typeName}.${getter}, .{globalObject, ${thisValue ? "thisValue," : ""} propertyName}); - }, - }; - } - `; - } - - if (names.setter) { - output += ` - pub fn ${names.setter}(globalObject: *jsc.JSGlobalObject, thisValue: jsc.JSValue, target: jsc.JSValue) callconv(jsc.conv) bool { - if (comptime Environment.enable_logs) log_zig_class_setter("${typeName}", "${name}", target); - return @call(bun.callmod_inline, ${typeName}.${setter || accessor.setter}, .{thisValue, globalObject, target}); - } - `; - } - - if (names.fn) { - if (DOMJIT) { - const { args, returns } = DOMJIT; - - output += ` - pub fn ${names.DOMJIT}(globalObject: *jsc.JSGlobalObject, thisValue: jsc.JSValue, ${args - .map(ZigDOMJITArgTypeDefinition) - .join(", ")}) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_class_domjit("${typeName}", "${name}"); - return @call(bun.callmod_inline, ${typeName}.${DOMJITName(fn)}, .{thisValue, globalObject, ${args.map((_, i) => `arg${i}`).join(", ")}}); - } - `; - } - - output += ` - pub fn ${names.fn}(globalObject: *jsc.JSGlobalObject, callFrame: *jsc.CallFrame) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_class_method("${typeName}", "${name}", callFrame); - return @call(bun.callmod_inline, jsc.toJSHostFn(${typeName}.${fn}), .{globalObject, callFrame}); - } - `; - } - } - } - - if (structuredClone) { - exports.set("structuredClone", symbolName(typeName, "onStructuredCloneSerialize")); - output += ` - pub fn ${symbolName(typeName, "onStructuredCloneSerialize")}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, ctx: *anyopaque, writeBytes: WriteBytesFn) callconv(jsc.conv) void { - if (comptime Environment.enable_logs) log_zig_structured_clone_serialize("${typeName}"); - @call(bun.callmod_inline, ${typeName}.onStructuredCloneSerialize, .{thisValue, globalObject, ctx, writeBytes}); - } - `; - - if (typeof structuredClone === "object" && structuredClone.transferable) { - exports.set("structuredClone_transferable", symbolName(typeName, "onStructuredCloneTransfer")); - output += ` - pub fn ${exports.get("structuredClone_transferable")}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, ctx: *anyopaque, write: WriteBytesFn) callconv(jsc.conv) void { - if (comptime Environment.enable_logs) log_zig_structured_clone_transfer("${typeName}"); - @call(bun.callmod_inline, ${typeName}.onStructuredCloneTransfer, .{thisValue, globalObject, ctx, write}); - } - `; - } - - exports.set("structuredCloneDeserialize", symbolName(typeName, "onStructuredCloneDeserialize")); - - output += ` - pub fn ${symbolName(typeName, "onStructuredCloneDeserialize")}(globalObject: *jsc.JSGlobalObject, ptr: *[*]u8, end: [*]u8) callconv(jsc.conv) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_structured_clone_deserialize("${typeName}"); - return @call(bun.callmod_inline, jsc.toJSHostCall, .{ globalObject, @src(), ${typeName}.onStructuredCloneDeserialize, .{globalObject, ptr, end} }); - } - `; - } else { - output += ` - pub fn ${symbolName(typeName, "onStructuredCloneSerialize")}(thisValue: *${typeName}, globalObject: *jsc.JSGlobalObject, ctx: *anyopaque, writeBytes: WriteBytesFn) callconv(jsc.conv) void { - _ = thisValue; - _ = globalObject; - _ = ctx; - _ = writeBytes; - @compileLog("onStructuredCloneSerialize not implemented for ${typeName}"); - } - `; - } - - return ( - output.trim() + - ` - }; - comptime { -${[...exports.values()].map(name => ` @export(&JavaScriptCoreBindings.${name}, .{ .name = "${name}" });`).join("\n")} - }` - ); - } - - return ` - -pub const ${className(typeName)} = struct { - const ${typeName} = Classes.${typeName}; - - /// Return the pointer to the wrapped object. - /// If the object does not match the type, return null. - pub fn fromJS(value: jsc.JSValue) ?*${typeName} { - if (comptime Environment.enable_logs) log_zig_from_js("${typeName}"); - return ${symbolName(typeName, "fromJS")}(value); - } - - /// Return the pointer to the wrapped object only if it is a direct instance of the type. - /// If the object does not match the type, return null. - /// If the object is a subclass of the type or has mutated the structure, return null. - /// Note: this may return null for direct instances of the type if the user adds properties to the object. - pub fn fromJSDirect(value: jsc.JSValue) ?*${typeName} { - if (comptime Environment.enable_logs) log_zig_from_js_direct("${typeName}"); - return ${symbolName(typeName, "fromJSDirect")}(value); - } - - ${externs} - ${cached_values_string} - - ${ - !noConstructor - ? ` - /// Get the ${typeName} constructor value. - /// This loads lazily from the global object. - pub fn getConstructor(globalObject: *jsc.JSGlobalObject) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_get_constructor("${typeName}"); - return ${symbolName(typeName, "getConstructor")}(globalObject); - } - ` - : "" - } - - ${ - !overridesToJS - ? ` - /// Create a new instance of ${typeName} - pub fn toJS(this: *${typeName}, globalObject: *jsc.JSGlobalObject) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_to_js("${typeName}"); - if (comptime Environment.allow_assert) { - const value__ = ${symbolName(typeName, "create")}(globalObject, this); - @import("bun").assert(value__.as(${typeName}).? == this); // If this fails, likely a C ABI issue. - return value__; - } else { - return ${symbolName(typeName, "create")}(globalObject, this); - } - }` - : "" - } - - ${ - valuesArray && !overridesToJS - ? ` - /// Create a new instance of ${typeName} with a MarkedArgumentBuffer - pub fn toJSWithValues(this: *${typeName}, globalObject: *jsc.JSGlobalObject, markedArgumentBuffer: *jsc.MarkedArgumentBuffer) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_to_js("${typeName}"); - if (comptime Environment.allow_assert) { - const value__ = ${symbolName(typeName, "createWithValues")}(globalObject, this, markedArgumentBuffer); - @import("bun").assert(value__.as(${typeName}).? == this); // If this fails, likely a C ABI issue. - return value__; - } else { - return ${symbolName(typeName, "createWithValues")}(globalObject, this, markedArgumentBuffer); - } - }` - : "" - } - - ${ - valuesArray && values.length > 0 && !overridesToJS - ? ` - /// Create a new instance of ${typeName} with initial values - pub fn toJSWithInitialValues(this: *${typeName}, globalObject: *jsc.JSGlobalObject${values.map(v => `, ${v}: jsc.JSValue`).join("")}) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_to_js("${typeName}"); - if (comptime Environment.allow_assert) { - const value__ = ${symbolName(typeName, "createWithInitialValues")}(globalObject, this${values.map(v => `, ${v}`).join("")}); - @import("bun").assert(value__.as(${typeName}).? == this); // If this fails, likely a C ABI issue. - return value__; - } else { - return ${symbolName(typeName, "createWithInitialValues")}(globalObject, this${values.map(v => `, ${v}`).join("")}); - } - }` - : "" - } - - ${ - valuesArray && values.length > 0 && !overridesToJS - ? ` - /// Create a new instance of ${typeName} with both a MarkedArgumentBuffer and initial values - pub fn toJSWithValuesAndInitialValues(this: *${typeName}, globalObject: *jsc.JSGlobalObject, markedArgumentBuffer: *jsc.MarkedArgumentBuffer${values.map(v => `, ${v}: jsc.JSValue`).join("")}) jsc.JSValue { - if (comptime Environment.enable_logs) log_zig_to_js("${typeName}"); - if (comptime Environment.allow_assert) { - const value__ = ${symbolName(typeName, "createWithValuesAndInitialValues")}(globalObject, this, markedArgumentBuffer${values.map(v => `, ${v}`).join("")}); - @import("bun").assert(value__.as(${typeName}).? == this); // If this fails, likely a C ABI issue. - return value__; - } else { - return ${symbolName(typeName, "createWithValuesAndInitialValues")}(globalObject, this, markedArgumentBuffer${values.map(v => `, ${v}`).join("")}); - } - }` - : "" - } - - /// Modify the internal ptr to point to a new instance of ${typeName}. - pub fn dangerouslySetPtr(value: jsc.JSValue, ptr: ?*${typeName}) bool { - jsc.markBinding(@src()); - return ${symbolName(typeName, "dangerouslySetPtr")}(value, ptr); - } - - /// Detach the ptr from the thisValue - pub fn detachPtr(_: *${typeName}, value: jsc.JSValue) void { - jsc.markBinding(@src()); - bun.assert(${symbolName(typeName, "dangerouslySetPtr")}(value, null)); - } - - extern fn ${symbolName(typeName, "fromJS")}(jsc.JSValue) callconv(jsc.conv) ?*${typeName}; - extern fn ${symbolName(typeName, "fromJSDirect")}(jsc.JSValue) callconv(jsc.conv) ?*${typeName}; - extern fn ${symbolName(typeName, "getConstructor")}(*jsc.JSGlobalObject) callconv(jsc.conv) jsc.JSValue; - extern fn ${symbolName(typeName, "create")}(globalObject: *jsc.JSGlobalObject, ptr: ?*${typeName}) callconv(jsc.conv) jsc.JSValue; - ${valuesArray ? `extern fn ${symbolName(typeName, "createWithValues")}(globalObject: *jsc.JSGlobalObject, ptr: ?*${typeName}, markedArgumentBuffer: *anyopaque) callconv(jsc.conv) jsc.JSValue;` : ""} - ${valuesArray && values.length > 0 ? `extern fn ${symbolName(typeName, "createWithInitialValues")}(globalObject: *jsc.JSGlobalObject, ptr: ?*${typeName}${values.map(v => `, ${v}: jsc.JSValue`).join("")}) callconv(jsc.conv) jsc.JSValue;` : ""} - ${valuesArray && values.length > 0 ? `extern fn ${symbolName(typeName, "createWithValuesAndInitialValues")}(globalObject: *jsc.JSGlobalObject, ptr: ?*${typeName}, markedArgumentBuffer: *anyopaque${values.map(v => `, ${v}: jsc.JSValue`).join("")}) callconv(jsc.conv) jsc.JSValue;` : ""} - - /// Create a new instance of ${typeName} without validating it works. - pub const toJSUnchecked = ${symbolName(typeName, "create")}; - - extern fn ${typeName}__dangerouslySetPtr(jsc.JSValue, ?*${typeName}) callconv(jsc.conv) bool; - -${renderMethods()} - -}; - -`; -} - // ────────────────────────────────────────────────────────────────────────── -// Rust emitter — sibling of generateZig(). +// Rust emitter. // -// Emits, per class with \`lang === "rust"\`, a block of \`#[unsafe(no_mangle)] +// Emits, per class, a block of \`#[unsafe(no_mangle)] // pub extern "C" fn\` thunks whose unmangled names and signatures are // byte-identical to the externs the C++ side declares (renderDecls / // renderStaticDecls / generateConstructorImpl). The C++ output is invariant; @@ -3374,48 +2775,6 @@ void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor& `.trim(); } -const ZIG_GENERATED_CLASSES_HEADER = ` -/// Generated code! To regenerate, run: -/// -/// bun run build -/// -/// This file is generated by: -/// 1. \`bun src/codegen/generate-classes.ts\` -/// 2. Scan for **/*.classes.ts files in src/ -/// 3. Generate a JS wrapper for each class in: -/// - Zig: generated_classes.zig -/// - C++: ZigGeneratedClasses.h, ZigGeneratedClasses.cpp -/// 4. For the Zig code to successfully compile: -/// - Add it to generated_classes_list.zig -/// - \`\`\` -/// pub const js = jsc.Codegen.JSMyClassName; -/// pub const toJS = js.toJS; -/// pub const fromJS = js.fromJS; -/// pub const fromJSDirect = js.fromJSDirect; -/// \`\`\` -/// 5. bun run build -/// -const bun = @import("bun"); -const jsc = bun.jsc; -const Classes = jsc.GeneratedClassesList; -const Environment = bun.Environment; -const std = @import("std"); -const zig = bun.Output.scoped(.zig, .hidden); - -const wrapHostFunction = bun.gen_classes_lib.wrapHostFunction; -const wrapMethod = bun.gen_classes_lib.wrapMethod; -const wrapMethodWithThis = bun.gen_classes_lib.wrapMethodWithThis; -const wrapConstructor = bun.gen_classes_lib.wrapConstructor; -const wrapGetterCallback = bun.gen_classes_lib.wrapGetterCallback; -const wrapGetterWithValueCallback = bun.gen_classes_lib.wrapGetterWithValueCallback; - -pub const StaticGetterType = fn(*jsc.JSGlobalObject, jsc.JSValue, jsc.JSValue) callconv(jsc.conv) jsc.JSValue; -pub const StaticSetterType = fn(*jsc.JSGlobalObject, jsc.JSValue, jsc.JSValue, jsc.JSValue) callconv(jsc.conv) bool; -pub const StaticCallbackType = jsc.JSHostFn; -pub const WriteBytesFn = *const fn(*anyopaque, ptr: [*]const u8, len: u32) callconv(jsc.conv) void; - -`; - const classes: ClassDefinition[] = []; { let errors = []; @@ -3542,12 +2901,9 @@ function writeCppSerializers() { return output; } -// ── Rust output: per-class thunks for `lang === "rust"` (default). ───────── -// Zig output is still emitted for every class so the C++ side's `extern` -// declarations stay satisfied; the Zig thunks for rust-lang classes simply go -// unreferenced once the Rust crate links. +// ── Rust output: per-class thunks ────────────────────────────────────────── { - const rustClasses = classes.filter(a => (a.lang ?? "rust") === "rust"); + const rustClasses = classes; let totalSyms = 0; let resolved = 0; const blocks = rustClasses.map(a => { @@ -3567,137 +2923,6 @@ function writeCppSerializers() { ); } -await writeIfNotChanged(`${outBase}/ZigGeneratedClasses.zig`, [ - ZIG_GENERATED_CLASSES_HEADER, - - ...classes.map(a => generateZig(a.name, a).trim()).join("\n"), - "\n", - ` -comptime { - ${classes.map(a => `_ = ${className(a.name)};`).join("\n ")} -} - - - -// -- Avoid instantiating these log functions too many times -fn log_zig_method_call(typename: []const u8, method_name: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.{s}({d} args)", .{typename, method_name, callframe.arguments().len}); - } -} - -fn log_zig_getter(typename: []const u8, property_name: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("get {s}.{s}", .{typename, property_name}); - } -} - -fn log_zig_setter(typename: []const u8, property_name: []const u8, value: jsc.JSValue) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("set {s}.{s} = {?s}", .{typename, property_name, bun.tagName(jsc.JSValue, value)}); - } -} - -fn log_zig_finalize(typename: []const u8, ptr: *const anyopaque) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("~{s} 0x{x:8}", .{typename, @intFromPtr(ptr)}); - } -} - -fn log_zig_function_call(typename: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}({d} args)", .{typename, callframe.arguments().len}); - } -} - -fn log_zig_constructor(typename: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("new {s}({d} args)", .{typename, callframe.arguments().len}); - } -} - -fn log_zig_call(typename: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}({d} args)", .{typename, callframe.arguments().len}); - } -} - -fn log_zig_get_internal_properties(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("getInternalProperties {s}", .{typename}); - } -} - -fn log_zig_method(typename: []const u8, method_name: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.{s}({d} args)", .{typename, method_name, callframe.arguments().len}); - } -} - -fn log_zig_structured_clone_serialize(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("structuredCloneSerialize {s}", .{typename}); - } -} - -fn log_zig_structured_clone_transfer(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("structuredCloneTransfer {s}", .{typename}); - } -} - -fn log_zig_structured_clone_deserialize(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("structuredCloneDeserialize {s}", .{typename}); - } -} - -fn log_zig_from_js(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.fromJS", .{typename}); - } -} - -fn log_zig_from_js_direct(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.fromJSDirect", .{typename}); - } -} - -fn log_zig_get_constructor(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.constructor", .{typename}); - } -} - - -fn log_zig_to_js(typename: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.toJS", .{typename}); - } -} - -fn log_zig_class_method(typename: []const u8, method_name: []const u8, callframe: *jsc.CallFrame) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("{s}.{s}({d} args)", .{typename, method_name, callframe.arguments().len}); - } -} - -fn log_zig_class_getter(typename: []const u8, property_name: []const u8) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("static get {s}.{s}", .{typename, property_name}); - } -} - -fn log_zig_class_setter(typename: []const u8, property_name: []const u8, value: jsc.JSValue) callconv(bun.callconv_inline) void { - if (comptime Environment.enable_logs) { - zig("static set {s}.{s} = {?s}", .{typename, property_name, bun.tagName(jsc.JSValue, value)}); - } -} - - `, -]); - if (!process.env.ONLY_ZIG) { const allHeaders = classes.map(a => generateHeader(a.name, a)); await writeIfNotChanged(`${outBase}/ZigGeneratedClasses.h`, [ diff --git a/src/codegen/generate-compact-string-table.ts b/src/codegen/generate-compact-string-table.ts deleted file mode 100644 index 9f75d7cf2095..000000000000 --- a/src/codegen/generate-compact-string-table.ts +++ /dev/null @@ -1,430 +0,0 @@ -#!/usr/bin/env bun - -/** - * Compact String Table Generator - * - * Generates a Zig enum that stores multiple strings in a contiguous buffer with - * reduced per-string overhead compared to individual string slices. - * - * Instead of storing each string as a separate slice (16 bytes each), this packs - * the string metadata into enum values using bit fields. The actual string data - * is stored in a single static array. - * - * ## How it works: - * - * 1. Groups strings by length for uniform spacing within each group - * 2. Stores position and length group in bit-packed enum values - * 3. Uses non-power-of-2 integers (u9, u12, etc.) to minimize enum size - * - * ## Usage: - * - * ```bash - * # Input: newline-delimited strings - * echo -e "application/json\\ntext/html\\ntext/plain" > strings.txt - * - * # Generate Zig code - * bun src/codegen/generate-compact-string-table.ts strings.txt output.zig MyStrings - * ``` - * - * ## Trade-offs: - * - * - Reduces memory overhead from 16 bytes to 1-2 bytes per string - * - O(1) string access through length-based grouping - * - Uniform spacing within groups may include some padding - * - Requires build-time code generation - * - */ - -import { writeFileSync } from "fs"; - -const args = process.argv.slice(2); - -if (args.length < 3) { - console.error("Usage: generate-compact-string-table.ts [namespace]"); - console.error("Provide strings via stdin, one per line"); - process.exit(1); -} - -const [inputPath, outputPath, enumName, namespace] = args; - -interface StringEntry { - name: string; - value: string; - offset: number; - length: number; -} - -interface PackedString { - value: string; - offset: number; - entries: StringEntry[]; -} - -function escapeZigIdentifier(name: string): string { - // Always use @"..." syntax for consistency - return `@"${name.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`; -} - -function escapeZigString(str: string): string { - return str - .replace(/\\/g, "\\\\") - .replace(/"/g, '\\"') - .replace(/\n/g, "\\n") - .replace(/\r/g, "\\r") - .replace(/\t/g, "\\t") - .replace(/[\x00-\x1F\x7F-\x9F]/g, char => { - const code = char.charCodeAt(0); - return `\\x${code.toString(16).padStart(2, "0")}`; - }); -} - -function findSmallestIntType(maxValue: number): string { - if (maxValue <= 0xff) return "u8"; - if (maxValue <= 0xffff) return "u16"; - if (maxValue <= 0xffffffff) return "u32"; - return "u64"; -} - -interface LengthGroup { - length: number; - strings: { name: string; value: string }[]; - startOffset: number; -} - -function optimizeStringPacking(strings: { name: string; value: string }[]): { - entries: StringEntry[]; - packedData: string; - lengthGroups: LengthGroup[]; -} { - // First, identify unique string values and do substring deduplication - const uniqueValues = new Map(); // value -> [names] - - for (const { name, value } of strings) { - if (!uniqueValues.has(value)) { - uniqueValues.set(value, []); - } - uniqueValues.get(value)!.push(name); - } - - // Sort unique values by length descending for substring detection - const sortedValues = Array.from(uniqueValues.keys()).sort((a, b) => b.length - a.length); - - // Find which strings can be substrings of others - const substringMap = new Map(); - const rootStrings: string[] = []; - - for (const value of sortedValues) { - let foundAsSubstring = false; - - // Check if this string is a substring of any root string - for (const root of rootStrings) { - const index = root.indexOf(value); - if (index !== -1) { - substringMap.set(value, { parent: root, offset: index }); - foundAsSubstring = true; - break; - } - } - - if (!foundAsSubstring) { - // This is a new root string, check if it contains any existing roots - const newRoot = value; - const toRemove: number[] = []; - - for (let i = 0; i < rootStrings.length; i++) { - const existingRoot = rootStrings[i]; - const index = newRoot.indexOf(existingRoot); - if (index !== -1) { - // Update all strings that were substrings of the old root - for (const [substr, info] of substringMap.entries()) { - if (info.parent === existingRoot) { - substringMap.set(substr, { - parent: newRoot, - offset: index + info.offset, - }); - } - } - // The existing root is now a substring of the new root - substringMap.set(existingRoot, { parent: newRoot, offset: index }); - toRemove.push(i); - } - } - - // Remove absorbed roots - for (let i = toRemove.length - 1; i >= 0; i--) { - rootStrings.splice(toRemove[i], 1); - } - - rootStrings.push(newRoot); - } - } - - // Now reorganize by length groups for uniform spacing - const lengthMap = new Map(); - - for (const [value, names] of uniqueValues.entries()) { - const length = value.length; - if (!lengthMap.has(length)) { - lengthMap.set(length, []); - } - lengthMap.get(length)!.push({ value, names }); - } - - // Sort length groups by frequency - const lengthGroups: LengthGroup[] = Array.from(lengthMap.entries()) - .sort((a, b) => { - // Group with more total strings comes first (smaller index = fewer bits) - const aCount = a[1].reduce((sum, v) => sum + v.names.length, 0); - const bCount = b[1].reduce((sum, v) => sum + v.names.length, 0); - if (aCount !== bCount) return bCount - aCount; - return a[0] - b[0]; - }) - .map(([length, values]) => ({ - length, - strings: values.flatMap(v => v.names.map(name => ({ name, value: v.value }))), - startOffset: 0, - })); - - // Build packed data with uniform spacing within length groups - let packedData = ""; - const entries: StringEntry[] = []; - - for (const group of lengthGroups) { - group.startOffset = packedData.length; - - // Get unique values in this length group - const uniqueInGroup = new Map(); - for (const { name, value } of group.strings) { - if (!uniqueInGroup.has(value)) { - uniqueInGroup.set(value, []); - } - uniqueInGroup.get(value)!.push(name); - } - - // Sort values for consistent ordering - const sortedValues = Array.from(uniqueInGroup.keys()).sort(); - - // Pack values uniformly - for (let i = 0; i < sortedValues.length; i++) { - const value = sortedValues[i]; - const offset = group.startOffset + i * group.length; - - // Get the actual string data to pack - let sourceData: string; - if (substringMap.has(value)) { - // This is a substring of another string - const { parent, offset: parentOffset } = substringMap.get(value)!; - // We need to ensure the parent data is available - sourceData = value; // We'll still pack it directly for uniform spacing - } else { - sourceData = value; - } - - packedData += sourceData; - - // Create entries for all names with this value - for (const name of uniqueInGroup.get(value)!) { - entries.push({ - name, - value, - offset, - length: group.length, - }); - } - } - } - - return { entries, packedData, lengthGroups }; -} - -export function generateCompactStringTable( - enumName: string, - strings: { name: string; value: string }[], - namespace?: string, -): string { - if (strings.length === 0) { - throw new Error("No strings provided"); - } - - const { entries, packedData, lengthGroups } = optimizeStringPacking(strings); - - // Create lookup tables for length groups - const lengthGroupMap = new Map(); - const uniqueLengths: number[] = []; - const groupStartOffsets: number[] = []; - const groupCounts: number[] = []; - - lengthGroups.forEach((group, index) => { - const uniqueInGroup = new Set(group.strings.map(s => s.value)).size; - lengthGroupMap.set(group.length, { - index, - startOffset: group.startOffset, - count: uniqueInGroup, - }); - uniqueLengths.push(group.length); - groupStartOffsets.push(group.startOffset); - groupCounts.push(uniqueInGroup); - }); - - // For each entry, calculate its position within its length group - const entryPositions = new Map(); - - for (const group of lengthGroups) { - // Get unique values in this length group (must match packing logic exactly) - const uniqueInGroup = new Map(); - for (const { name, value } of group.strings) { - if (!uniqueInGroup.has(value)) { - uniqueInGroup.set(value, []); - } - uniqueInGroup.get(value)!.push(name); - } - - // Sort values for consistent ordering (must match packing logic exactly) - const sortedValues = Array.from(uniqueInGroup.keys()).sort(); - - // Assign positions - sortedValues.forEach((value, position) => { - for (const name of uniqueInGroup.get(value)!) { - entryPositions.set(name, { - groupIndex: lengthGroupMap.get(group.length)!.index, - positionInGroup: position, - }); - } - }); - } - - // Calculate bits needed - const lengthGroupBits = Math.ceil(Math.log2(lengthGroups.length || 1)); - const maxPositionInGroup = Math.max(...groupCounts); - const positionBits = Math.ceil(Math.log2(maxPositionInGroup || 1)); - const actualPackedBits = lengthGroupBits + positionBits; - - // Use exact bit size for the enum - const packedIntType = `u${actualPackedBits}`; - - // Sort entries by name for stable output - entries.sort((a, b) => a.name.localeCompare(b.name)); - - let output = `//! Generated by generate-compact-string-table.ts -//! Do not edit manually -//! To regenerate, run: -//! \`\`\` -//! bun run src/codegen/generate-compact-string-table.ts ${inputPath} ${outputPath} ${enumName} -//! \`\`\` -`; - - if (namespace) { - output += `\npub const ${namespace} = struct {\n`; - } - - output += `pub const ${enumName} = enum(${packedIntType}) { - const LengthGroupBits = ${lengthGroupBits}; - const PositionBits = ${positionBits}; - const PackedInt = ${packedIntType}; - - pub const Packed = packed struct (PackedInt) { - length_group: u${lengthGroupBits}, - position: u${positionBits}, - }; - - const _bytes = "${escapeZigString(packedData)}"; - const _lengths = [_]${findSmallestIntType(Math.max(...uniqueLengths))}{${uniqueLengths.join(", ")}}; - const _group_start_offsets = [_]${findSmallestIntType(Math.max(...groupStartOffsets))}{${groupStartOffsets.join(", ")}}; - -`; - - // Generate enum fields - // Sort entries by name for stable output - entries.sort((a, b) => a.name.localeCompare(b.name)); - - for (const entry of entries) { - const pos = entryPositions.get(entry.name)!; - const packedValue = pos.groupIndex | (pos.positionInGroup << lengthGroupBits); - output += ` ${escapeZigIdentifier(entry.name)} = ${packedValue},\n`; - } - - output += ` - pub fn slice(this: ${enumName}) []const u8 { - const p: Packed = @bitCast(@as(PackedInt, @intFromEnum(this))); - const length: usize = _lengths[p.length_group]; - const offset = @as(usize, _group_start_offsets[p.length_group]) + @as(usize, p.position) * @as(usize, length); - return _bytes[offset..][0..length]; - } - - pub fn len(this: ${enumName}) usize { - const p: Packed = @bitCast(@as(PackedInt, @intFromEnum(this))); - return _lengths[p.length_group]; - } - - pub fn ptr(this: ${enumName}) [*]const u8 { - const p: Packed = @bitCast(@as(PackedInt, @intFromEnum(this))); - const length: usize = _lengths[p.length_group]; - const offset = @as(usize, _group_start_offsets[p.length_group]) + @as(usize, p.position) * @as(usize, length); - return _bytes[offset..].ptr; - } - - pub const count = ${entries.length}; - pub const all = &[_]${enumName}{ -${entries.map(entry => ` .${escapeZigIdentifier(entry.name)},`).join("\n")} - }; -}; -`; - - if (namespace) { - output += `};\n`; - } - - output += `\nconst std = @import("std");\n`; - - return output; -} - -// CLI interface - -// Read strings from stdin -const input = await Bun.file(inputPath).text(); -const strings: { name: string; value: string }[] = []; - -for (const line of input.trim().split("\n")) { - if (!line) continue; - // Each line is just a string value, use it as both name and value - strings.push({ name: line.trim(), value: line.trim() }); -} - -if (strings.length === 0) { - console.error("No valid strings provided"); - process.exit(1); -} - -try { - const output = generateCompactStringTable(enumName, strings, namespace); - writeFileSync(outputPath, output); - - // Print statistics - const totalOriginalSize = strings.reduce((sum, s) => sum + s.value.length, 0); - const packedSize = output.match(/const _bytes = "(.*?)"/s)?.[1]?.length ?? 0; - const lengthsMatch = output.match(/const _lengths = \[_\][^{]+\{([^}]+)\}/); - const lengthGroupsCount = lengthsMatch ? lengthsMatch[1].split(",").filter(s => s.trim()).length : 0; - - // Calculate actual memory usage - const naiveMemory = strings.length * 16; // Each []const u8 is 16 bytes - const actualBits = - parseInt(output.match(/const LengthGroupBits = (\d+)/)?.[1] ?? "0") + - parseInt(output.match(/const PositionBits = (\d+)/)?.[1] ?? "0"); - const ourEnumSize = Math.ceil(actualBits / 8); - const ourTotalMemory = strings.length * ourEnumSize; // Each enum value - - console.log(`Generated ${outputPath}`); - console.log(` Strings: ${strings.length}`); - console.log(` Length groups: ${lengthGroupsCount}`); - console.log(` Packed bits: ${actualBits} (u${actualBits})`); - console.log(` Packed data: ${packedSize} bytes`); - console.log(` String deduplication: ${((1 - packedSize / totalOriginalSize) * 100).toFixed(1)}% saved`); - console.log( - ` Memory per value: ${ourEnumSize} bytes vs 16 bytes (${((1 - ourEnumSize / 16) * 100).toFixed(1)}% saved)`, - ); - console.log(` Total memory: ${ourTotalMemory} bytes vs ${naiveMemory} bytes`); -} catch (error) { - console.error("Error:", error); - process.exit(1); -} diff --git a/src/codegen/generate-js2native.ts b/src/codegen/generate-js2native.ts index 86bfed725774..e32f5c4e0c8e 100644 --- a/src/codegen/generate-js2native.ts +++ b/src/codegen/generate-js2native.ts @@ -1,10 +1,10 @@ -// This file implements the global state for $zig and $cpp preprocessor macros +// This file implements the global state for $rust and $cpp preprocessor macros // as well as all the code it generates. // // For the actual parsing, see replacements.ts import path, { basename, sep } from "path"; -import { cap, readdirRecursiveWithExclusionsAndExtensionsSync } from "./helpers"; +import { readdirRecursiveWithExclusionsAndExtensionsSync } from "./helpers"; // interface NativeCall { @@ -25,38 +25,105 @@ interface WrapperCall { filename: string; } -type NativeCallType = "zig" | "cpp" | "bind"; +type NativeCallType = "rust" | "cpp" | "bind"; const nativeCalls: NativeCall[] = []; const wrapperCalls: WrapperCall[] = []; +const srcDir = path.join(import.meta.dir, "../"); + const sourceFiles = readdirRecursiveWithExclusionsAndExtensionsSync( - path.join(import.meta.dir, "../"), + srcDir, ["deps", "node_modules", "WebKit"], - [".cpp", ".zig", ".bind.ts"], + [".cpp", ".bind.ts"], ); +// The $rust() macro's first argument is an identifier naming the module a +// native symbol belongs to. The file itself is never opened, but its path +// under src/ drives both the exported C symbol name (normalizeSymbolPathPrefix) +// and the Rust crate path (rustTarget). Adding a new $rust() call site +// requires adding its entry below. +const rustIdentifierPaths: Record = { + "bun.rs": "bun.rs", + "Counters.rs": "jsc/Counters.rs", + "FrameworkRouter.rs": "runtime/bake/FrameworkRouter.rs", + "Listener.rs": "runtime/socket/Listener.rs", + "SecureContext.rs": "runtime/api/bun/SecureContext.rs", + "Stat.rs": "runtime/node/Stat.rs", + "bindgen_test.rs": "jsc/bindgen_test.rs", + "collections/linear_fifo.rs": "collections/linear_fifo.rs", + "crash_handler.rs": "crash_handler/crash_handler.rs", + "css_internals.rs": "css_jsc/css_internals.rs", + "dependency.rs": "install/dependency.rs", + "escapeRegExp.rs": "string/escapeRegExp.rs", + "event_loop.rs": "jsc/event_loop.rs", + "ffi.rs": "runtime/ffi/ffi.rs", + "h2_frame_parser.rs": "runtime/api/bun/h2_frame_parser.rs", + "hosted_git_info.rs": "install/hosted_git_info.rs", + "http/H2Client.rs": "http/H2Client.rs", + "http/H3Client.rs": "http/H3Client.rs", + "ini.rs": "ini/ini.rs", + "install_binding.rs": "install_jsc/install_binding.rs", + "ipc.rs": "jsc/ipc.rs", + "mysql.rs": "sql_jsc/mysql.rs", + "node_assert_binding.rs": "runtime/node/node_assert_binding.rs", + "node_cluster_binding.rs": "runtime/node/node_cluster_binding.rs", + "node_crypto_binding.rs": "runtime/node/node_crypto_binding.rs", + "node_fs_binding.rs": "runtime/node/node_fs_binding.rs", + "node_http_binding.rs": "runtime/node/node_http_binding.rs", + "node_net_binding.rs": "runtime/node/node_net_binding.rs", + "node_os.rs": "runtime/node/node_os.rs", + "node_util_binding.rs": "runtime/node/node_util_binding.rs", + "node_zlib_binding.rs": "runtime/node/node_zlib_binding.rs", + "npm.rs": "install/npm.rs", + "pack_command.rs": "runtime/cli/pack_command.rs", + "parse_args.rs": "runtime/node/util/parse_args.rs", + "patch.rs": "patch/patch.rs", + "postgres.rs": "sql_jsc/postgres.rs", + "runtime/dns_jsc/dns.rs": "runtime/dns_jsc/dns.rs", + "runtime/node/types.rs": "runtime/node/types.rs", + "runtime/socket/socket.rs": "runtime/socket/socket.rs", + "runtime/timer/Timer.rs": "runtime/timer/Timer.rs", + "runtime/webcore/FileSink.rs": "runtime/webcore/FileSink.rs", + "shell.rs": "runtime/shell/shell.rs", + "sourcemap/InternalSourceMap.rs": "sourcemap/InternalSourceMap.rs", + "string/immutable/unicode.rs": "bun_core/string/immutable/unicode.rs", + "subprocess.rs": "runtime/api/bun/subprocess.rs", + "sys.rs": "sys/sys.rs", + "sys/Error.rs": "sys/Error.rs", + "udp_socket.rs": "runtime/socket/udp_socket.rs", + "upgrade_command.rs": "runtime/cli/upgrade_command.rs", + "virtual_machine_exports.rs": "jsc/virtual_machine_exports.rs", +}; + function callBaseName(x: string) { return x.split(/[^A-Za-z0-9]/g).pop()!; } function resolveNativeFileId(call_type: NativeCallType, filename: string) { - const ext = call_type === "bind" ? ".bind.ts" : `.${call_type}`; + const ext = call_type === "bind" ? ".bind.ts" : call_type === "rust" ? ".rs" : `.${call_type}`; if (!filename.endsWith(ext)) { throw new Error(`Expected filename for $${call_type} to have ${ext} extension, got ${JSON.stringify(filename)}`); } + if (call_type === "rust") { + const relative = rustIdentifierPaths[filename]; + if (!relative) { + throw new Error( + `Unknown $rust() file identifier ${JSON.stringify(filename)}. Add it to rustIdentifierPaths in src/codegen/generate-js2native.ts.`, + ); + } + return path.join(srcDir, relative.replaceAll("/", sep)); + } + filename = filename.replaceAll("/", sep); + const resolved = sourceFiles.find(file => file.endsWith(sep + filename)); if (!resolved) { const fnName = call_type === "bind" ? "bindgenFn" : call_type; throw new Error(`Could not find file ${filename} in $${fnName} call`); } - if (call_type === "zig") { - return resolved; - } - return filename; } @@ -103,8 +170,8 @@ export function registerNativeCall( } function symbol(call: Pick) { - return call.type === "zig" - ? `JS2Zig__${call.filename ? normalizeSymbolPathPrefix(call.filename) + "_" : ""}${call.symbol.replace(/[^A-Za-z]/g, "_")}` + return call.type === "rust" + ? `JS2Rust__${call.filename ? normalizeSymbolPathPrefix(call.filename) + "_" : ""}${call.symbol.replace(/[^A-Za-z]/g, "_")}` : call.symbol; } @@ -116,7 +183,7 @@ function normalizeSymbolPathPrefix(input: string) { input = input.slice(bunDir.length); } - return input.replaceAll(".zig", "_zig_").replace(/[^A-Za-z]/g, "_"); + return input.replaceAll(".rs", "_rs_").replace(/[^A-Za-z]/g, "_"); } function cppPointer(call: NativeCall) { @@ -131,7 +198,7 @@ export function getJS2NativeCPP() { const externs: string[] = []; const nativeCallStrings = nativeCalls - .filter(x => x.type === "zig") + .filter(x => x.type === "rust") .flatMap( call => ( externs.push(`extern "C" SYSV_ABI JSC::EncodedJSValue ${symbol(call)}_workaround(Zig::GlobalObject*);` + "\n"), @@ -146,10 +213,10 @@ export function getJS2NativeCPP() { const wrapperCallStrings = wrapperCalls.map(x => { if (x.wrap_kind === "new-function") { return [ - (x.type === "zig" && + (x.type === "rust" && externs.push( `BUN_DECLARE_HOST_FUNCTION(${symbol({ - type: "zig", + type: "rust", symbol: x.symbol_target, filename: x.filename, })});`, @@ -207,68 +274,27 @@ export function getJS2NativeCPP() { ].join("\n"); } -export function getJS2NativeZig(gs2NativeZigPath: string) { - return [ - "//! This file is generated by src/codegen/generate-js2native.ts based on seen calls to the $zig() JS macro", - `const bun = @import("bun");`, - `const jsc = bun.jsc;`, - ...nativeCalls - .filter(x => x.type === "zig") - .flatMap(call => [ - `export fn ${symbol(call)}_workaround(global: *jsc.JSGlobalObject) callconv(jsc.conv) jsc.JSValue {`, - ` return jsc.toJSHostCall(global, @src(), @import(${JSON.stringify(path.relative(path.dirname(gs2NativeZigPath), call.filename))}).${call.symbol}, .{global});`, - "}", - ]), - ...wrapperCalls - .filter(x => x.type === "zig") - .flatMap(x => [ - `export fn ${symbol({ - type: "zig", - symbol: x.symbol_target, - filename: x.filename, - })}(global: *jsc.JSGlobalObject, call_frame: *jsc.CallFrame) callconv(jsc.conv) jsc.JSValue {`, - ` const function = @import(${JSON.stringify(path.relative(path.dirname(gs2NativeZigPath), x.filename))});`, - ` return @call(bun.callmod_inline, jsc.toJSHostFn(function.${x.symbol_target}), .{global, call_frame});`, - "}", - ]), - "comptime {", - ...nativeCalls - .filter(x => x.type === "bind") - .flatMap(x => { - const base = basename(x.filename.replace(/\.bind\.ts$/, "")); - return [ - ` @export(&bun.gen.${base}.create${cap(x.symbol)}Callback, .{ .name = ${JSON.stringify( - `js2native_bindgen_${base}_${x.symbol}`, - )} });`, - ]; - }), - "}", - ].join("\n"); -} - -// ────────────────────────────────────────────────────────────────────────── -// Rust emitter — sibling of getJS2NativeZig(). +// Rust emitter. // -// Emits, for every $zig() call site, a `#[unsafe(no_mangle)] extern "C"` +// Emits, for every $rust() call site, a `#[unsafe(no_mangle)] extern "C"` // thunk whose unmangled name and signature is byte-identical to the extern // the C++ side declares in GeneratedJS2Native.h. The C++ output is invariant; // only the implementer of the symbol changes. // // Two ABI shapes: -// • nativeCalls (type "zig") → `${sym}_workaround(global) -> JSValue` -// • wrapperCalls (type "zig") → `${sym}(global, callframe) -> JSValue` +// • nativeCalls (type "rust") → `${sym}_workaround(global) -> JSValue` +// • wrapperCalls (type "rust") → `${sym}(global, callframe) -> JSValue` // -// Each thunk calls the hand-ported Rust function directly at -// `crate::::` — no trait, no -// runtime panic fallback. A missing function is a compile error. -// ────────────────────────────────────────────────────────────────────────── +// Each thunk calls the Rust function directly at +// `crate::::` — no trait, no runtime +// panic fallback. A missing function is a compile error. export function getJS2NativeRust() { // Symbols already hand-exported in src/ (via `export_host_fn!` or - // `#[unsafe(export_name = "JS2Zig__…")]`) — skip emitting a thunk for these + // `#[unsafe(export_name = "JS2Rust__…")]`) — skip emitting a thunk for these // so the linker doesn't see two definitions. const handExported = new Set([ - "JS2Zig___src_runtime_dns_jsc_dns_zig__Resolver_getRuntimeDefaultResultOrderOption", - "JS2Zig___src_runtime_dns_jsc_dns_zig__Resolver_newResolver", + "JS2Rust___src_runtime_dns_jsc_dns_rs__Resolver_getRuntimeDefaultResultOrderOption", + "JS2Rust___src_runtime_dns_jsc_dns_rs__Resolver_newResolver", ]); const srcRoot = path.resolve(import.meta.dir, ".."); @@ -279,13 +305,13 @@ export function getJS2NativeRust() { .replace(/[.\-]/g, "_") .toLowerCase(); - // `src/runtime/node/node_util_binding.zig` + `parseEnv` + // `src/runtime/node/node_util_binding.rs` + `parseEnv` // → `crate::node::node_util_binding::parse_env` - // `src/ini/ini.zig` + `IniTestingAPIs.parse` (outside bun_runtime) + // `src/ini/ini.rs` + `IniTestingAPIs.parse` (outside bun_runtime) // → `crate::dispatch::js2native::ini_ini_testing_apis_parse` (single - // landing pad the port-agents fill in; still a compile error if missing). + // landing pad; still a compile error if missing). const rustTarget = (filename: string, sym: string) => { - const rel = path.relative(srcRoot, filename).replace(/\.zig$/, ""); + const rel = path.relative(srcRoot, filename).replace(/\.rs$/, ""); const segs = rel.split(path.sep); const fn = sym .split(".") @@ -306,13 +332,13 @@ export function getJS2NativeRust() { const thunks: string[] = []; const seen = new Set(); - for (const call of nativeCalls.filter(x => x.type === "zig")) { + for (const call of nativeCalls.filter(x => x.type === "rust")) { const sym = `${symbol(call)}_workaround`; if (seen.has(sym)) continue; seen.add(sym); const target = rustTarget(call.filename, call.symbol); thunks.push( - `// $zig(${path.basename(call.filename)}, ${call.symbol})`, + `// $rust(${path.basename(call.filename)}, ${call.symbol})`, `bun_jsc::jsc_host_abi! {`, ` #[unsafe(no_mangle)]`, ` pub unsafe fn ${sym}(global: &JSGlobalObject) -> JSValue {`, @@ -323,8 +349,8 @@ export function getJS2NativeRust() { ); } - for (const x of wrapperCalls.filter(x => x.type === "zig")) { - const sym = symbol({ type: "zig", symbol: x.symbol_target, filename: x.filename }); + for (const x of wrapperCalls.filter(x => x.type === "rust")) { + const sym = symbol({ type: "rust", symbol: x.symbol_target, filename: x.filename }); if (seen.has(sym)) continue; seen.add(sym); if (handExported.has(sym)) { @@ -333,7 +359,7 @@ export function getJS2NativeRust() { } const target = rustTarget(x.filename, x.symbol_target); thunks.push( - `// $zig(${path.basename(x.filename)}, ${x.symbol_target})`, + `// $rust(${path.basename(x.filename)}, ${x.symbol_target})`, `bun_jsc::jsc_host_abi! {`, ` #[unsafe(no_mangle)]`, ` pub unsafe fn ${sym}(global: &JSGlobalObject, callframe: &CallFrame) -> JSValue {`, @@ -347,7 +373,7 @@ export function getJS2NativeRust() { return [ `// Auto-generated by src/codegen/generate-js2native.ts — DO NOT EDIT.`, `//`, - `// \`#[unsafe(no_mangle)] extern "C"\` thunks satisfying the JS2Zig__* externs`, + `// \`#[unsafe(no_mangle)] extern "C"\` thunks satisfying the JS2Rust__* externs`, `// declared by GeneratedJS2Native.h (the JS-module → native dispatch table).`, `// Each thunk calls the hand-ported Rust function directly; a missing`, `// function is a compile error in \`cargo check -p bun_runtime\`.`, @@ -371,10 +397,9 @@ export function getJS2NativeDTS() { .filter(x => x.endsWith("cpp")) .map(x => JSON.stringify(basename(x))) .join("|"), - "declare type NativeFilenameZig = " + - sourceFiles - .filter(x => x.endsWith("zig")) - .map(x => JSON.stringify(basename(x))) + "declare type NativeFilenameRust = " + + Object.keys(rustIdentifierPaths) + .map(x => JSON.stringify(x)) .join("|"), "", ].join("\n"); diff --git a/src/codegen/generate-node-errors.ts b/src/codegen/generate-node-errors.ts index 4bab0c5cf38a..41400504aed3 100644 --- a/src/codegen/generate-node-errors.ts +++ b/src/codegen/generate-node-errors.ts @@ -19,7 +19,6 @@ if (count > 1 << 16) { let enumHeader = ``; let listHeader = ``; -let zig = ``; enumHeader = ` // clang-format off @@ -49,38 +48,6 @@ struct ErrorCodeData { static constexpr ErrorCodeData errors[${count}] = { `; -zig = ` -// Generated by: src/codegen/generate-node-errors.ts -const std = @import("std"); -const bun = @import("bun"); -const jsc = bun.jsc; - -pub fn ErrorBuilder(comptime code: Error, comptime fmt: [:0]const u8, Args: type) type { - return struct { - global: *jsc.JSGlobalObject, - args: Args, - - // Throw this error as a JS exception - pub inline fn throw(this: @This()) bun.JSError { - return code.throw(this.global, fmt, this.args); - } - - /// Turn this into a JSValue - pub inline fn toJS(this: @This()) jsc.JSValue { - return code.fmt(this.global, fmt, this.args); - } - - /// Turn this into a JSPromise that is already rejected. - pub inline fn reject(this: @This()) jsc.JSValue { - return jsc.JSPromise.rejectedPromise(this.global, code.fmt(this.global, fmt, this.args)).toJS(); - } - }; -} - -pub const Error = enum(u16) { - -`; - let i = 0; for (let [code, constructor, name, ...other_constructors] of NodeErrors) { if (name == null) name = constructor.name; @@ -90,8 +57,6 @@ for (let [code, constructor, name, ...other_constructors] of NodeErrors) { enumHeader += ` ${code} = ${i},\n`; listHeader += ` { JSC::ErrorType::${constructor.name}, "${name}"_s, "${code}"_s },\n`; - zig += ` /// ${name}: ${code} (instanceof ${constructor.name})\n`; - zig += ` ${codeWithoutPrefix} = ${i},\n`; i++; for (const con of other_constructors) { @@ -99,8 +64,6 @@ for (let [code, constructor, name, ...other_constructors] of NodeErrors) { if (name == null) name = con.name; enumHeader += ` ${code}_${con.name} = ${i},\n`; listHeader += ` { JSC::ErrorType::${con.name}, "${con.name}"_s, "${code}"_s },\n`; - zig += ` /// ${name}: ${code} (instanceof ${con.name})\n`; - zig += ` ${codeWithoutPrefix}_${con.name} = ${i},\n`; i++; } } @@ -114,36 +77,6 @@ listHeader += ` }; `; -zig += ` - - - extern fn Bun__createErrorWithCode(globalThis: *jsc.JSGlobalObject, code: Error, message: *bun.String) jsc.JSValue; - - /// Creates an Error object with the given error code. - /// If an error is thrown while creating the Error object, returns that error instead. - /// Derefs the message string. - pub fn toJS(this: Error, globalThis: *jsc.JSGlobalObject, message: *bun.String) jsc.JSValue { - defer message.deref(); - return Bun__createErrorWithCode(globalThis, this, message); - } - - pub fn fmt(this: Error, globalThis: *jsc.JSGlobalObject, comptime fmt_str: [:0]const u8, args: anytype) jsc.JSValue { - if (comptime std.meta.fieldNames(@TypeOf(args)).len == 0) { - var message = bun.String.static(fmt_str); - return toJS(this, globalThis, &message); - } - - var message = bun.handleOom(bun.String.createFormat(fmt_str, args)); - return toJS(this, globalThis, &message); - } - - pub fn throw(this: Error, globalThis: *jsc.JSGlobalObject, comptime fmt_str: [:0]const u8, args: anytype) bun.JSError { - return globalThis.throwValue(fmt(this, globalThis, fmt_str, args)); - } - -}; -`; - let builtindtsPath = path.join(import.meta.dir, "..", "..", "src", "js", "builtins.d.ts"); let builtindts = await Bun.file(builtindtsPath).text(); @@ -174,5 +107,4 @@ declare function $${code}(message: string): ${namedError};\n`; writeIfNotChanged(path.join(outputDir, "ErrorCode+List.h"), enumHeader); writeIfNotChanged(path.join(outputDir, "ErrorCode+Data.h"), listHeader); -writeIfNotChanged(path.join(outputDir, "ErrorCode.zig"), zig); writeIfNotChanged(path.join(outputDir, "ErrorCode.d.ts"), dts); diff --git a/src/codegen/process_windows_translate_c.zig b/src/codegen/process_windows_translate_c.zig deleted file mode 100644 index 38e48c78805f..000000000000 --- a/src/codegen/process_windows_translate_c.zig +++ /dev/null @@ -1,73 +0,0 @@ -// translate-c is unable to translate the unsuffixed windows functions -// like `SetCurrentDirectory` since they are defined with an odd macro -// that translate-c doesn't handle. -// -// #define SetCurrentDirectory __MINGW_NAME_AW(SetCurrentDirectory) -// -// In these cases, it's better to just reference the underlying function -// directly: SetCurrentDirectoryW. To make the error better, a post -// processing step is applied to the translate-c file. - -const symbol_replacements = std.StaticStringMap([]const u8).initComptime(&.{ - &.{ "NTSTATUS", "@import(\"std\").os.windows.NTSTATUS" }, - &.{ "HANDLE", "@import(\"std\").os.windows.HANDLE" }, - &.{ "PHANDLE", "*HANDLE" }, -}); - -pub fn main() !void { - const gpa = std.heap.smp_allocator; - var args = try std.process.argsWithAllocator(gpa); - errdefer args.deinit(); - assert(args.skip()); - - const in = brk: { - const in_path = args.next() orelse @panic("missing argument"); - const in = try std.fs.cwd().openFile(in_path, .{}); - defer in.close(); - break :brk try in.readToEndAllocOptions(gpa, std.math.maxInt(u32), null, .fromByteUnits(1), 0); - }; - defer gpa.free(in); - - var out = try std.array_list.Managed(u8).initCapacity(gpa, in.len); - defer out.deinit(); - const w = out.writer(); - - var i: usize = 0; - while (mem.indexOfPos(u8, in, i, "pub const ")) |pub_i| { - var tokenizer = std.zig.Tokenizer.init(in); - tokenizer.index = pub_i + "pub const ".len; - const symbol_name_token = tokenizer.next(); - assert(symbol_name_token.tag == .identifier); - const symbol_name = in[symbol_name_token.loc.start..symbol_name_token.loc.end]; - try w.writeAll(in[i..symbol_name_token.loc.end]); - i = symbol_name_token.loc.end; - var end_of_line = mem.indexOfScalarPos(u8, in, symbol_name_token.loc.end, '\n') orelse in.len; - if (in[end_of_line - 1] != ';') { - // skip multiline decl - try w.writeAll(in[i..end_of_line]); - i = end_of_line; - continue; - } - end_of_line += 1; // include the \n - if (symbol_replacements.get(symbol_name)) |replace| { - try w.print(" = {s};\n", .{replace}); - } else if (mem.startsWith(u8, in[i..], " = __MINGW_NAME_AW(")) { - try w.print(" = @compileError(\"Use '{s}W' instead.\");\n", .{symbol_name}); - } else { - try w.writeAll(in[i..end_of_line]); - } - i = end_of_line; - } - try w.writeAll(in[i..]); - try std.fs.cwd().writeFile(.{ - .sub_path = args.next() orelse @panic("missing argument"), - .data = out.items, - }); -} - -fn assert(cond: bool) void { - if (!cond) @panic("unhandled"); -} - -const std = @import("std"); -const mem = std.mem; diff --git a/src/codegen/replacements.ts b/src/codegen/replacements.ts index 10dc18c4fbef..6bc297b7a109 100644 --- a/src/codegen/replacements.ts +++ b/src/codegen/replacements.ts @@ -165,8 +165,8 @@ export interface ReplacementRule { export const function_replacements = [ "$debug", "$assert", - "$zig", - "$newZigFunction", + "$rust", + "$newRustFunction", "$cpp", "$newCppFunction", "$isPromiseFulfilled", @@ -222,8 +222,8 @@ export function applyReplacements(src: string, length: number) { rest2, true, ]; - } else if (["zig", "cpp", "newZigFunction", "newCppFunction"].includes(name)) { - const kind = name.includes("ig") ? "zig" : "cpp"; + } else if (["rust", "cpp", "newRustFunction", "newCppFunction"].includes(name)) { + const kind = name.includes("ust") ? "rust" : "cpp"; const is_create_fn = name.startsWith("new"); const inner = sliceSourceCode(rest, true); diff --git a/src/codegen/shared-types.ts b/src/codegen/shared-types.ts index e998b7f3e255..fc1958e2fb8c 100644 --- a/src/codegen/shared-types.ts +++ b/src/codegen/shared-types.ts @@ -1,67 +1,3 @@ -export const typeDeclarations = `// generated by cppbind.ts from functions marked with [[ZIG_EXPORT(mode)]] - -const bun = @import("bun"); -const jsc = bun.jsc; -const HTTPServerAgent = bun.jsc.Debugger.HTTPServerAgent; -const Environment = bun.Environment; -`; - -export const sharedTypes: Record = { - // Basic types - "bool": "bool", - "char": "u8", - "unsigned char": "u8", - "signed char": "i8", - "char16_t": "u16", - "short": "c_short", - "unsigned short": "c_ushort", - "int": "c_int", - "unsigned": "c_uint", - "unsigned int": "c_uint", - "long": "c_long", - "unsigned long": "c_ulong", - "long long": "c_longlong", - "unsigned long long": "c_ulonglong", - "float": "f32", - "double": "f64", - "size_t": "usize", - "ssize_t": "isize", - "int8_t": "i8", - "uint8_t": "u8", - "int16_t": "i16", - "uint16_t": "u16", - "int32_t": "i32", - "uint32_t": "u32", - "int64_t": "i64", - "uint64_t": "u64", - - // Common Bun types - "BunString": "bun.String", - "JSC::EncodedJSValue": "jsc.JSValue", - "EncodedJSValue": "jsc.JSValue", - "JSC::JSGlobalObject": "jsc.JSGlobalObject", - "ZigException": "jsc.ZigException", - "Inspector::InspectorHTTPServerAgent": "HTTPServerAgent.InspectorHTTPServerAgent", - "HotReloadId": "HTTPServerAgent.HotReloadId", - "ServerId": "HTTPServerAgent.ServerId", - "Route": "HTTPServerAgent.Route", - "Zig::GlobalObject": "jsc.JSGlobalObject", - "JSC::VM": "jsc.VM", - "WTF::StringImpl": "bun.WTF._StringImplStruct", - "WebCore::DOMURL": "bun.DOMURL", - "ZigString": "bun.jsc.ZigString", - "JSC::JSPromise": "bun.jsc.JSPromise", - "JSC::JSMap": "bun.jsc.JSMap", - "JSC::CustomGetterSetter": "bun.jsc.CustomGetterSetter", - "JSC::SourceProvider": "bun.jsc.SourceProvider", - "JSC::CallFrame": "bun.jsc.CallFrame", - "JSC::JSObject": "bun.jsc.JSObject", - "JSC::JSString": "bun.jsc.JSString", - "JSC::Exception": "bun.jsc.Exception", - "JSC::JSInternalPromise": "bun.jsc.JSInternalPromise", - "WebCore::EventLoopTask": "bun.jsc.CppTask", -}; - export const bannedTypes: Record = { "JSC::JSValue": "Not allowed, use JSC::EncodedJSValue instead", }; diff --git a/src/collections/StaticHashMap.zig b/src/collections/StaticHashMap.zig deleted file mode 100644 index a8eb7627cb97..000000000000 --- a/src/collections/StaticHashMap.zig +++ /dev/null @@ -1,781 +0,0 @@ -// https://github.com/lithdew/rheia/blob/162293d0f0e8d6572a8954c0add83f13f76b3cc6/hash_map.zig -// Apache License 2.0 - -pub fn AutoHashMap(comptime K: type, comptime V: type, comptime max_load_percentage: comptime_int) type { - return HashMap(K, V, std.hash_map.AutoContext(K), max_load_percentage); -} - -pub fn AutoStaticHashMap(comptime K: type, comptime V: type, comptime capacity: comptime_int) type { - return StaticHashMap(K, V, std.hash_map.AutoContext(K), capacity); -} - -pub fn StaticHashMap(comptime K: type, comptime V: type, comptime Context: type, comptime capacity: usize) type { - assert(math.isPowerOfTwo(capacity)); - - const shift = 63 - math.log2_int(u64, capacity) + 1; - const overflow = capacity / 10 + (63 - @as(u64, shift) + 1) << 1; - - return struct { - const empty_hash = math.maxInt(u64); - - pub const Entry = struct { - hash: u64 = empty_hash, - key: K = std.mem.zeroes(K), - value: V = std.mem.zeroes(V), - - pub fn isEmpty(self: Entry) bool { - return self.hash == empty_hash; - } - - pub fn format(self: Entry, writer: *std.Io.Writer) !void { - try writer.print("(hash: {}, key: {}, value: {})", .{ self.hash, self.key, self.value }); - } - }; - - pub const GetOrPutResult = struct { - value_ptr: *V, - found_existing: bool, - }; - - const Self = @This(); - - entries: [capacity + overflow]Entry = [_]Entry{.{}} ** (capacity + overflow), - len: usize = 0, - shift: u6 = shift, - - // put_probe_count: usize = 0, - // get_probe_count: usize = 0, - // del_probe_count: usize = 0, - - const impl = HashMapMixin(Self, K, V, Context); - pub const putAssumeCapacity = impl.putAssumeCapacity; - pub const slice = impl.slice; - pub const clearRetainingCapacity = impl.clearRetainingCapacity; - pub const putAssumeCapacityContext = impl.putAssumeCapacityContext; - pub const getOrPutAssumeCapacity = impl.getOrPutAssumeCapacity; - pub const getOrPutAssumeCapacityContext = impl.getOrPutAssumeCapacityContext; - pub const get = impl.get; - pub const getContext = impl.getContext; - pub const has = impl.has; - pub const hasWithHash = impl.hasWithHash; - pub const hasContext = impl.hasContext; - pub const delete = impl.delete; - pub const deleteContext = impl.deleteContext; - }; -} - -pub fn HashMap(comptime K: type, comptime V: type, comptime Context: type, comptime max_load_percentage: comptime_int) type { - return struct { - const empty_hash = math.maxInt(u64); - - pub const Entry = struct { - hash: u64 = empty_hash, - key: K = undefined, - value: V = undefined, - - pub fn isEmpty(self: Entry) bool { - return self.hash == empty_hash; - } - - pub fn format(self: Entry, writer: *std.Io.Writer) !void { - try writer.print("(hash: {}, key: {}, value: {})", .{ self.hash, self.key, self.value }); - } - }; - - pub const GetOrPutResult = struct { - value_ptr: *V, - found_existing: bool, - }; - - const Self = @This(); - - entries: [*]Entry, - len: usize = 0, - shift: u6, - - // put_probe_count: usize = 0, - // get_probe_count: usize = 0, - // del_probe_count: usize = 0, - - const impl = HashMapMixin(Self, K, V, Context); - pub const putAssumeCapacity = impl.putAssumeCapacity; - pub const slice = impl.slice; - pub const clearRetainingCapacity = impl.clearRetainingCapacity; - pub const putAssumeCapacityContext = impl.putAssumeCapacityContext; - pub const getOrPutAssumeCapacity = impl.getOrPutAssumeCapacity; - pub const getOrPutAssumeCapacityContext = impl.getOrPutAssumeCapacityContext; - pub const get = impl.get; - pub const getContext = impl.getContext; - pub const has = impl.has; - pub const hasWithHash = impl.hasWithHash; - pub const hasContext = impl.hasContext; - pub const delete = impl.delete; - pub const deleteContext = impl.deleteContext; - - pub fn initCapacity(gpa: mem.Allocator, capacity: u64) !Self { - assert(math.isPowerOfTwo(capacity)); - - const shift = 63 - math.log2_int(u64, capacity) + 1; - const overflow = capacity / 10 + (63 - @as(u64, shift) + 1) << 1; - - const entries = try gpa.alloc(Entry, @as(usize, @intCast(capacity + overflow))); - @memset(entries, .{}); - - return Self{ - .entries = entries.ptr, - .shift = shift, - }; - } - - pub fn deinit(self: *Self, gpa: mem.Allocator) void { - gpa.free(self.slice()); - } - - pub fn ensureUnusedCapacity(self: *Self, gpa: mem.Allocator, count: usize) !void { - try self.ensureTotalCapacity(gpa, self.len + count); - } - - pub fn ensureTotalCapacity(self: *Self, gpa: mem.Allocator, count: usize) !void { - while (true) { - const capacity = @as(u64, 1) << (63 - self.shift + 1); - if (count <= capacity * max_load_percentage / 100) { - break; - } - try self.grow(gpa); - } - } - - fn grow(self: *Self, gpa: mem.Allocator) !void { - const capacity = @as(u64, 1) << (63 - self.shift + 1); - const overflow = capacity / 10 + (63 - @as(usize, self.shift) + 1) << 1; - const end = self.entries + @as(usize, @intCast(capacity + overflow)); - - const map = try Self.initCapacity(gpa, @as(usize, @intCast(capacity * 2))); - var src = self.entries; - var dst = map.entries; - - while (src != end) { - const entry = src[0]; - - const i = if (!entry.isEmpty()) entry.hash >> map.shift else 0; - const p = map.entries + i; - - dst = if (@intFromPtr(p) >= @intFromPtr(dst)) p else dst; - dst[0] = entry; - - src += 1; - dst += 1; - } - - self.deinit(gpa); - self.entries = map.entries; - self.shift = map.shift; - } - - pub fn put(self: *Self, gpa: mem.Allocator, key: K, value: V) !void { - try self.putContext(gpa, key, value, undefined); - } - - pub fn putContext(self: *Self, gpa: mem.Allocator, key: K, value: V, ctx: Context) !void { - try self.ensureUnusedCapacity(gpa, 1); - self.putAssumeCapacityContext(key, value, ctx); - } - - pub fn getOrPut(self: *Self, gpa: mem.Allocator, key: K) !GetOrPutResult { - return try self.getOrPutContext(gpa, key, undefined); - } - - pub fn getOrPutContext(self: *Self, gpa: mem.Allocator, key: K, ctx: Context) !GetOrPutResult { - try self.ensureUnusedCapacity(gpa, 1); - return self.getOrPutAssumeCapacityContext(key, ctx); - } - }; -} - -fn HashMapMixin( - comptime Self: type, - comptime K: type, - comptime V: type, - comptime Context: type, -) type { - return struct { - pub fn clearRetainingCapacity(self: *Self) void { - @memset(self.slice(), .{}); - self.len = 0; - } - - pub fn slice(self: *Self) []Self.Entry { - const capacity = @as(u64, 1) << (63 - self.shift + 1); - const overflow = capacity / 10 + (63 - @as(usize, self.shift) + 1) << 1; - return self.entries[0..@as(usize, @intCast(capacity + overflow))]; - } - - pub fn putAssumeCapacity(self: *Self, key: K, value: V) void { - self.putAssumeCapacityContext(key, value, undefined); - } - - pub fn putAssumeCapacityContext(self: *Self, key: K, value: V, ctx: Context) void { - const result = self.getOrPutAssumeCapacityContext(key, ctx); - if (!result.found_existing) result.value_ptr.* = value; - } - - pub fn getOrPutAssumeCapacity(self: *Self, key: K) Self.GetOrPutResult { - return self.getOrPutAssumeCapacityContext(key, undefined); - } - - pub fn getOrPutAssumeCapacityContext(self: *Self, key: K, ctx: Context) Self.GetOrPutResult { - var it: Self.Entry = .{ .hash = ctx.hash(key), .key = key, .value = undefined }; - var i = it.hash >> self.shift; - - assert(it.hash != Self.empty_hash); - - var inserted_at: ?usize = null; - while (true) : (i += 1) { - const entry = self.entries[i]; - if (entry.hash >= it.hash) { - if (ctx.eql(entry.key, key)) { - return .{ .found_existing = true, .value_ptr = &self.entries[i].value }; - } - self.entries[i] = it; - if (entry.isEmpty()) { - self.len += 1; - return .{ .found_existing = false, .value_ptr = &self.entries[inserted_at orelse i].value }; - } - if (inserted_at == null) { - inserted_at = i; - } - it = entry; - } - // self.put_probe_count += 1; - } - } - - pub fn get(self: *const Self, key: K) ?V { - return self.getContext(key, undefined); - } - - pub fn getContext(self: *const Self, key: K, ctx: Context) ?V { - const hash = ctx.hash(key); - assert(hash != Self.empty_hash); - - for (self.entries[hash >> self.shift ..]) |entry| { - if (entry.hash >= hash) { - if (!ctx.eql(entry.key, key)) { - return null; - } - return entry.value; - } - // self.get_probe_count += 1; - } - } - - pub fn has(self: *const Self, key: K) bool { - return self.hasContext(key, undefined); - } - - pub fn hasWithHash(self: *const Self, key_hash: u64) bool { - assert(key_hash != Self.empty_hash); - - for (self.entries[key_hash >> self.shift ..]) |entry| { - if (entry.hash >= key_hash) { - return entry.hash == key_hash; - } - } - - return false; - } - - pub fn hasContext(self: *const Self, key: K, ctx: Context) bool { - const hash = ctx.hash(key); - assert(hash != Self.empty_hash); - - for (self.entries[hash >> self.shift ..]) |entry| { - if (entry.hash >= hash) { - if (!ctx.eql(entry.key, key)) { - return false; - } - return true; - } - // self.get_probe_count += 1; - } - unreachable; - } - - pub fn delete(self: *Self, key: K) ?V { - return self.deleteContext(key, undefined); - } - - pub fn deleteContext(self: *Self, key: K, ctx: Context) ?V { - const hash = ctx.hash(key); - assert(hash != Self.empty_hash); - - var i = hash >> self.shift; - while (true) : (i += 1) { - const entry = self.entries[i]; - if (entry.hash >= hash) { - if (!ctx.eql(entry.key, key)) { - return null; - } - break; - } - // self.del_probe_count += 1; - } - - const value = self.entries[i].value; - - while (true) : (i += 1) { - const j = self.entries[i + 1].hash >> self.shift; - if (i < j or self.entries[i + 1].isEmpty()) { - break; - } - self.entries[i] = self.entries[i + 1]; - // self.del_probe_count += 1; - } - self.entries[i] = .{}; - self.len -= 1; - - return value; - } - }; -} - -pub fn SortedHashMap(comptime V: type, comptime max_load_percentage: comptime_int) type { - return struct { - const empty_hash: [32]u8 = [_]u8{0xFF} ** 32; - - pub const Entry = struct { - hash: [32]u8 = empty_hash, - value: V = undefined, - - pub fn isEmpty(self: Entry) bool { - return cmp(self.hash, empty_hash) == .eq; - } - - pub fn format(self: Entry, writer: *std.Io.Writer) !void { - try writer.print("(hash: {x}, value: {})", .{ mem.asBytes(&self.hash), self.value }); - } - }; - - const Self = @This(); - - entries: [*]Entry, - len: usize = 0, - shift: u6, - - // put_probe_count: usize = 0, - // get_probe_count: usize = 0, - // del_probe_count: usize = 0, - - pub fn init(gpa: mem.Allocator) !Self { - return Self.initCapacity(gpa, 16); - } - - pub fn initCapacity(gpa: mem.Allocator, capacity: u64) !Self { - assert(math.isPowerOfTwo(capacity)); - - const shift = 63 - math.log2_int(u64, capacity) + 1; - const overflow = capacity / 10 + (63 - @as(u64, shift) + 1) << 1; - - const entries = try gpa.alloc(Entry, @as(usize, @intCast(capacity + overflow))); - @memset(entries, Entry{}); - - return Self{ - .entries = entries.ptr, - .shift = shift, - }; - } - - pub fn deinit(self: *Self, gpa: mem.Allocator) void { - gpa.free(self.slice()); - } - - /// The following routine has its branches optimized against inputs that are cryptographic hashes by - /// assuming that if the first 64 bits of 'a' and 'b' are equivalent, then 'a' and 'b' are most likely - /// equivalent. - fn cmp(a: [32]u8, b: [32]u8) math.Order { - const msa = @as(u64, @bitCast(a[0..8].*)); - const msb = @as(u64, @bitCast(b[0..8].*)); - if (msa != msb) { - return if (mem.bigToNative(u64, msa) < mem.bigToNative(u64, msb)) .lt else .gt; - } else if (@reduce(.And, @as(@Vector(32, u8), a) == @as(@Vector(32, u8), b))) { - return .eq; - } else { - switch (math.order(mem.readIntBig(u64, a[8..16]), mem.readIntBig(u64, b[8..16]))) { - .eq => {}, - .lt => return .lt, - .gt => return .gt, - } - switch (math.order(mem.readIntBig(u64, a[16..24]), mem.readIntBig(u64, b[16..24]))) { - .eq => {}, - .lt => return .lt, - .gt => return .gt, - } - return math.order(mem.readIntBig(u64, a[24..32]), mem.readIntBig(u64, b[24..32])); - } - } - - /// In release-fast mode, LLVM will optimize this routine to utilize 109 cycles. This routine scatters - /// hash values across a table into buckets which are lexicographically ordered from one another in - /// ascending order. - fn idx(a: [32]u8, shift: u6) usize { - return @as(usize, @intCast(mem.readIntBig(u64, a[0..8]) >> shift)); - } - - pub fn clearRetainingCapacity(self: *Self) void { - @memset(self.slice(), Entry{}); - self.len = 0; - } - - pub fn slice(self: *Self) []Entry { - const capacity = @as(u64, 1) << (63 - self.shift + 1); - const overflow = capacity / 10 + (63 - @as(usize, self.shift) + 1) << 1; - return self.entries[0..@as(usize, @intCast(capacity + overflow))]; - } - - pub fn ensureUnusedCapacity(self: *Self, gpa: mem.Allocator, count: usize) !void { - try self.ensureTotalCapacity(gpa, self.len + count); - } - - pub fn ensureTotalCapacity(self: *Self, gpa: mem.Allocator, count: usize) !void { - while (true) { - const capacity = @as(u64, 1) << (63 - self.shift + 1); - if (count <= capacity * max_load_percentage / 100) { - break; - } - try self.grow(gpa); - } - } - - fn grow(self: *Self, gpa: mem.Allocator) !void { - const capacity = @as(u64, 1) << (63 - self.shift + 1); - const overflow = capacity / 10 + (63 - @as(usize, self.shift) + 1) << 1; - const end = self.entries + @as(usize, @intCast(capacity + overflow)); - - const map = try Self.initCapacity(gpa, @as(usize, @intCast(capacity * 2))); - var src = self.entries; - var dst = map.entries; - - while (src != end) { - const entry = src[0]; - - const i = if (!entry.isEmpty()) idx(entry.hash, map.shift) else 0; - const p = map.entries + i; - - dst = if (@intFromPtr(p) >= @intFromPtr(dst)) p else dst; - dst[0] = entry; - - src += 1; - dst += 1; - } - - self.deinit(gpa); - self.entries = map.entries; - self.shift = map.shift; - } - - pub fn put(self: *Self, gpa: mem.Allocator, key: [32]u8, value: V) !void { - try self.ensureUnusedCapacity(gpa, 1); - self.putAssumeCapacity(key, value); - } - - pub fn putAssumeCapacity(self: *Self, key: [32]u8, value: V) void { - const result = self.getOrPutAssumeCapacity(key); - if (!result.found_existing) result.value_ptr.* = value; - } - - pub const GetOrPutResult = struct { - value_ptr: *V, - found_existing: bool, - }; - - pub fn getOrPut(self: *Self, gpa: mem.Allocator, key: [32]u8) !GetOrPutResult { - try self.ensureUnusedCapacity(gpa, 1); - return self.getOrPutAssumeCapacity(key); - } - - pub fn getOrPutAssumeCapacity(self: *Self, key: [32]u8) GetOrPutResult { - assert(self.len < (@as(u64, 1) << (63 - self.shift + 1))); - assert(cmp(key, empty_hash) != .eq); - - var it: Entry = .{ .hash = key, .value = undefined }; - var i = idx(key, self.shift); - - var inserted_at: ?usize = null; - while (true) : (i += 1) { - const entry = self.entries[i]; - if (cmp(entry.hash, it.hash).compare(.gte)) { - if (cmp(entry.hash, key) == .eq) { - return .{ .found_existing = true, .value_ptr = &self.entries[i].value }; - } - self.entries[i] = it; - if (entry.isEmpty()) { - self.len += 1; - return .{ .found_existing = false, .value_ptr = &self.entries[inserted_at orelse i].value }; - } - if (inserted_at == null) { - inserted_at = i; - } - it = entry; - } - self.put_probe_count += 1; - } - } - - pub fn get(self: *Self, key: [32]u8) ?V { - assert(cmp(key, empty_hash) != .eq); - - for (self.entries[idx(key, self.shift)..]) |entry| { - if (cmp(entry.hash, key).compare(.gte)) { - if (cmp(entry.hash, key) != .eq) { - return null; - } - return entry.value; - } - // self.get_probe_count += 1; - } - } - - pub fn delete(self: *Self, key: [32]u8) ?V { - assert(cmp(key, empty_hash) != .eq); - - var i = idx(key, self.shift); - while (true) : (i += 1) { - const entry = self.entries[i]; - if (cmp(entry.hash, key).compare(.gte)) { - if (cmp(entry.hash, key) != .eq) { - return null; - } - break; - } - self.del_probe_count += 1; - } - - const value = self.entries[i].value; - - while (true) : (i += 1) { - const j = idx(self.entries[i + 1].hash, self.shift); - if (i < j or self.entries[i + 1].isEmpty()) { - break; - } - self.entries[i] = self.entries[i + 1]; - self.del_probe_count += 1; - } - self.entries[i] = .{}; - self.len -= 1; - - return value; - } - }; -} - -test "StaticHashMap: put, get, delete, grow" { - var map: AutoStaticHashMap(usize, usize, 512) = .{}; - - for (0..128) |seed| { - var rng = std.rand.DefaultPrng.init(seed); - - const keys = try testing.allocator.alloc(usize, 512); - defer testing.allocator.free(keys); - - for (keys) |*key| key.* = @as(usize, rng.next()); - - try testing.expectEqual(@as(u6, 55), map.shift); - - for (keys, 0..) |key, i| map.putAssumeCapacity(key, i); - try testing.expectEqual(keys.len, map.len); - - var it: usize = 0; - for (map.slice()) |entry| { - if (!entry.isEmpty()) { - if (it > entry.hash) { - return error.Unsorted; - } - it = entry.hash; - } - } - - for (keys, 0..) |key, i| try testing.expectEqual(i, map.get(key).?); - for (keys, 0..) |key, i| try testing.expectEqual(i, map.delete(key).?); - } -} - -test "HashMap: put, get, delete, grow" { - for (0..128) |seed| { - var rng = std.rand.DefaultPrng.init(seed); - - const keys = try testing.allocator.alloc(usize, 512); - defer testing.allocator.free(keys); - - for (keys) |*key| key.* = rng.next(); - - var map = try AutoHashMap(usize, usize, 50).initCapacity(testing.allocator, 16); - defer map.deinit(testing.allocator); - - try testing.expectEqual(@as(u6, 60), map.shift); - - for (keys, 0..) |key, i| try map.put(testing.allocator, key, i); - - try testing.expectEqual(@as(u6, 54), map.shift); - try testing.expectEqual(keys.len, map.len); - - var it: usize = 0; - for (map.slice()) |entry| { - if (!entry.isEmpty()) { - if (it > entry.hash) { - return error.Unsorted; - } - it = entry.hash; - } - } - - for (keys, 0..) |key, i| try testing.expectEqual(i, map.get(key).?); - for (keys, 0..) |key, i| try testing.expectEqual(i, map.delete(key).?); - } -} - -test "SortedHashMap: cmp" { - const prefix = [_]u8{'0'} ** 8 ++ [_]u8{'1'} ** 23; - const a = prefix ++ [_]u8{0}; - const b = prefix ++ [_]u8{1}; - - try testing.expect(SortedHashMap(void, 100).cmp(a, b) == .lt); - try testing.expect(SortedHashMap(void, 100).cmp(b, a) == .gt); - try testing.expect(SortedHashMap(void, 100).cmp(a, a) == .eq); - try testing.expect(SortedHashMap(void, 100).cmp(b, b) == .eq); - try testing.expect(SortedHashMap(void, 100).cmp([_]u8{'i'} ++ [_]u8{'0'} ** 31, [_]u8{'o'} ++ [_]u8{'0'} ** 31) == .lt); - try testing.expect(SortedHashMap(void, 100).cmp([_]u8{ 'h', 'i' } ++ [_]u8{'0'} ** 30, [_]u8{ 'h', 'o' } ++ [_]u8{'0'} ** 30) == .lt); -} - -test "SortedHashMap: put, get, delete, grow" { - for (0..128) |seed| { - var rng = std.rand.DefaultPrng.init(seed); - - const keys = try testing.allocator.alloc([32]u8, 512); - defer testing.allocator.free(keys); - - for (keys) |*key| rng.fill(key); - - var map = try SortedHashMap(usize, 50).initCapacity(testing.allocator, 16); - defer map.deinit(testing.allocator); - - try testing.expectEqual(@as(u6, 60), map.shift); - - for (keys, 0..) |key, i| try map.put(testing.allocator, key, i); - - try testing.expectEqual(@as(u6, 54), map.shift); - try testing.expectEqual(keys.len, map.len); - - var it = [_]u8{0} ** 32; - for (map.slice()) |entry| { - if (!entry.isEmpty()) { - if (!mem.order(u8, &it, &entry.hash).compare(.lte)) { - return error.Unsorted; - } - it = entry.hash; - } - } - - for (keys, 0..) |key, i| try testing.expectEqual(i, map.get(key).?); - for (keys, 0..) |key, i| try testing.expectEqual(i, map.delete(key).?); - } -} - -test "SortedHashMap: collision test" { - const prefix = [_]u8{22} ** 8 ++ [_]u8{1} ** 23; - - var map = try SortedHashMap(usize, 100).initCapacity(testing.allocator, 4); - defer map.deinit(testing.allocator); - - try map.put(testing.allocator, prefix ++ [_]u8{0}, 0); - try map.put(testing.allocator, prefix ++ [_]u8{1}, 1); - try map.put(testing.allocator, prefix ++ [_]u8{2}, 2); - try map.put(testing.allocator, prefix ++ [_]u8{3}, 3); - - var it = [_]u8{0} ** 32; - for (map.slice()) |entry| { - if (!entry.isEmpty()) { - if (!mem.order(u8, &it, &entry.hash).compare(.lte)) { - return error.Unsorted; - } - it = entry.hash; - } - } - - try testing.expectEqual(@as(usize, 0), map.get(prefix ++ [_]u8{0}).?); - try testing.expectEqual(@as(usize, 1), map.get(prefix ++ [_]u8{1}).?); - try testing.expectEqual(@as(usize, 2), map.get(prefix ++ [_]u8{2}).?); - try testing.expectEqual(@as(usize, 3), map.get(prefix ++ [_]u8{3}).?); - - try testing.expectEqual(@as(usize, 2), map.delete(prefix ++ [_]u8{2}).?); - try testing.expectEqual(@as(usize, 0), map.delete(prefix ++ [_]u8{0}).?); - try testing.expectEqual(@as(usize, 1), map.delete(prefix ++ [_]u8{1}).?); - try testing.expectEqual(@as(usize, 3), map.delete(prefix ++ [_]u8{3}).?); - - try map.put(testing.allocator, prefix ++ [_]u8{0}, 0); - try map.put(testing.allocator, prefix ++ [_]u8{2}, 2); - try map.put(testing.allocator, prefix ++ [_]u8{3}, 3); - try map.put(testing.allocator, prefix ++ [_]u8{1}, 1); - - it = [_]u8{0} ** 32; - for (map.slice()) |entry| { - if (!entry.isEmpty()) { - if (!mem.order(u8, &it, &entry.hash).compare(.lte)) { - return error.Unsorted; - } - it = entry.hash; - } - } - - try testing.expectEqual(@as(usize, 0), map.delete(prefix ++ [_]u8{0}).?); - try testing.expectEqual(@as(usize, 1), map.delete(prefix ++ [_]u8{1}).?); - try testing.expectEqual(@as(usize, 2), map.delete(prefix ++ [_]u8{2}).?); - try testing.expectEqual(@as(usize, 3), map.delete(prefix ++ [_]u8{3}).?); - - try map.put(testing.allocator, prefix ++ [_]u8{0}, 0); - try map.put(testing.allocator, prefix ++ [_]u8{2}, 2); - try map.put(testing.allocator, prefix ++ [_]u8{1}, 1); - try map.put(testing.allocator, prefix ++ [_]u8{3}, 3); - - it = [_]u8{0} ** 32; - for (map.slice()) |entry| { - if (!entry.isEmpty()) { - if (!mem.order(u8, &it, &entry.hash).compare(.lte)) { - return error.Unsorted; - } - it = entry.hash; - } - } - - try testing.expectEqual(@as(usize, 3), map.delete(prefix ++ [_]u8{3}).?); - try testing.expectEqual(@as(usize, 2), map.delete(prefix ++ [_]u8{2}).?); - try testing.expectEqual(@as(usize, 1), map.delete(prefix ++ [_]u8{1}).?); - try testing.expectEqual(@as(usize, 0), map.delete(prefix ++ [_]u8{0}).?); - - try map.put(testing.allocator, prefix ++ [_]u8{3}, 3); - try map.put(testing.allocator, prefix ++ [_]u8{0}, 0); - try map.put(testing.allocator, prefix ++ [_]u8{1}, 1); - try map.put(testing.allocator, prefix ++ [_]u8{2}, 2); - - it = [_]u8{0} ** 32; - for (map.slice()) |entry| { - if (!entry.isEmpty()) { - if (!mem.order(u8, &it, &entry.hash).compare(.lte)) { - return error.Unsorted; - } - it = entry.hash; - } - } - - try testing.expectEqual(@as(usize, 3), map.delete(prefix ++ [_]u8{3}).?); - try testing.expectEqual(@as(usize, 0), map.delete(prefix ++ [_]u8{0}).?); - try testing.expectEqual(@as(usize, 1), map.delete(prefix ++ [_]u8{1}).?); - try testing.expectEqual(@as(usize, 2), map.delete(prefix ++ [_]u8{2}).?); -} - -const bun = @import("bun"); -const assert = bun.assert; - -const std = @import("std"); -const math = std.math; -const mem = std.mem; -const testing = std.testing; diff --git a/src/collections/array_list.zig b/src/collections/array_list.zig deleted file mode 100644 index 5b35945fc484..000000000000 --- a/src/collections/array_list.zig +++ /dev/null @@ -1,425 +0,0 @@ -/// Managed `ArrayList` using an arbitrary `std.mem.Allocator`. -/// Prefer using a concrete type, like `ArrayListDefault` or `ArrayListIn(MimallocArena)`. -/// -/// NOTE: Unlike `std.ArrayList`, this type's `deinit` method calls `deinit` on each of the items. -pub fn ArrayList(comptime T: type) type { - return ArrayListIn(T, std.mem.Allocator); -} - -/// Managed `ArrayList` using the default allocator. No overhead compared to an unmanaged -/// `ArrayList`. -/// -/// NOTE: Unlike `std.ArrayList`, this type's `deinit` method calls `deinit` on each of the items. -pub fn ArrayListDefault(comptime T: type) type { - return ArrayListIn(T, bun.DefaultAllocator); -} - -/// Managed `ArrayList` using a specific kind of allocator. No overhead if `Allocator` is a -/// zero-sized type. -/// -/// NOTE: Unlike `std.ArrayList`, this type's `deinit` method calls `deinit` on each of the items. -pub fn ArrayListIn(comptime T: type, comptime Allocator: type) type { - return ArrayListAlignedIn(T, Allocator, null); -} - -/// Managed `ArrayListAligned` using an arbitrary `std.mem.Allocator`. -/// Prefer using a concrete type, like `ArrayListAlignedDefault` or -/// `ArrayListAlignedIn(MimallocArena)`. -/// -/// NOTE: Unlike `std.ArrayList`, this type's `deinit` method calls `deinit` on each of the items. -pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type { - return ArrayListAlignedIn(T, std.mem.Allocator, alignment); -} - -/// Managed `ArrayListAligned` using the default allocator. No overhead compared to an unmanaged -/// `ArrayListAligned`. -/// -/// NOTE: Unlike `std.ArrayList`, this type's `deinit` method calls `deinit` on each of the items. -pub fn ArrayListAlignedDefault(comptime T: type, comptime alignment: ?u29) type { - return ArrayListAlignedIn(T, bun.DefaultAllocator, alignment); -} - -/// Managed `ArrayListAligned` using a specific kind of allocator. No overhead if `Allocator` is a -/// zero-sized type. -/// -/// NOTE: Unlike `std.ArrayList`, this type's `deinit` method calls `deinit` on each of the items. -pub fn ArrayListAlignedIn( - comptime T: type, - comptime Allocator: type, - comptime alignment: ?std.mem.Alignment, -) type { - return struct { - const Self = @This(); - - #unmanaged: Unmanaged = .empty, - #allocator: Allocator, - - pub fn items(self: *const Self) Slice { - return self.#unmanaged.items; - } - - pub fn capacity(self: *const Self) usize { - return self.#unmanaged.capacity; - } - - pub const SentinelSlice = Unmanaged.SentinelSlice; - pub const Slice = Unmanaged.Slice; - pub const Unmanaged = std.ArrayListAlignedUnmanaged(T, alignment); - - pub fn init() Self { - return .initIn(bun.memory.initDefault(Allocator)); - } - - pub fn initIn(allocator_: Allocator) Self { - return .{ - .#unmanaged = .empty, - .#allocator = allocator_, - }; - } - - pub fn initCapacity(num: usize) AllocError!Self { - return .initCapacityIn(num, bun.memory.initDefault(Allocator)); - } - - pub fn initCapacityIn(num: usize, allocator_: Allocator) AllocError!Self { - return .{ - .#unmanaged = try .initCapacity(bun.allocators.asStd(allocator_), num), - .#allocator = allocator_, - }; - } - - /// NOTE: Unlike `std.ArrayList`, this method calls `deinit` on every item in the list, - /// if such a method exists. If you don't want that behavior, use `deinitShallow`. - pub fn deinit(self: *Self) void { - bun.memory.deinit(self.items()); - self.deinitShallow(); - } - - pub fn deinitShallow(self: *Self) void { - defer self.* = undefined; - self.#unmanaged.deinit(self.getStdAllocator()); - bun.memory.deinit(&self.#allocator); - } - - pub fn fromOwnedSlice(allocator_: Allocator, slice: Slice) Self { - return .{ - .#unmanaged = .fromOwnedSlice(slice), - .#allocator = allocator_, - }; - } - - pub fn fromOwnedSliceSentinel( - allocator_: Allocator, - comptime sentinel: T, - slice: [:sentinel]T, - ) Self { - return .{ - .#unmanaged = .fromOwnedSliceSentinel(sentinel, slice), - .#allocator = allocator_, - }; - } - - pub fn writer(self: *Self) Unmanaged.Writer { - return self.#unmanaged.writer(self.getStdAllocator()); - } - - /// Returns a borrowed version of the allocator. - pub fn allocator(self: *const Self) bun.allocators.Borrowed(Allocator) { - return bun.allocators.borrow(self.#allocator); - } - - /// This method empties `self`. - pub fn moveToUnmanaged(self: *Self) Unmanaged { - defer self.#unmanaged = .empty; - return self.#unmanaged; - } - - /// Unlike `moveToUnmanaged`, this method *invalidates* `self`. - pub fn intoUnmanagedWithAllocator(self: *Self) struct { Unmanaged, Allocator } { - defer self.* = undefined; - return .{ self.#unmanaged, self.#allocator }; - } - - /// The contents of `unmanaged` must have been allocated by `allocator`. - /// This function invalidates `unmanaged`; don't call `deinit` on it. - pub fn fromUnmanaged(allocator_: Allocator, unmanaged: Unmanaged) Self { - return .{ - .#unmanaged = unmanaged, - .#allocator = allocator_, - }; - } - - pub fn toOwnedSlice(self: *Self) AllocError!Slice { - return self.#unmanaged.toOwnedSlice(self.getStdAllocator()); - } - - /// Creates a copy of this `ArrayList` with *shallow* copies of its items. - /// - /// The returned list uses a default-initialized `Allocator`. If `Allocator` cannot be - /// default-initialized, use `cloneIn` instead. - /// - /// Be careful with this method if `T` has a `deinit` method. You will have to use - /// `deinitShallow` on one of the `ArrayList`s to prevent `deinit` from being called twice - /// on each element. - pub fn clone(self: *const Self) AllocError!Self { - return self.cloneIn(bun.memory.initDefault(Allocator)); - } - - /// Creates a copy of this `ArrayList` using the provided allocator, with *shallow* copies - /// of this list's items. - pub fn cloneIn( - self: *const Self, - allocator_: anytype, - ) AllocError!ArrayListAlignedIn(T, @TypeOf(allocator_), alignment) { - return .{ - .#unmanaged = try self.#unmanaged.clone(bun.allocators.asStd(allocator_)), - .#allocator = allocator_, - }; - } - - pub fn insert(self: *Self, i: usize, item: T) AllocError!void { - return self.#unmanaged.insert(self.getStdAllocator(), i, item); - } - - pub fn insertAssumeCapacity(self: *Self, i: usize, item: T) void { - self.#unmanaged.insertAssumeCapacity(i, item); - } - - /// Note that this creates *shallow* copies of `value`. - pub fn addManyAt(self: *Self, index: usize, value: T, count: usize) AllocError![]T { - const result = try self.#unmanaged.addManyAt(self.getStdAllocator(), index, count); - @memset(result, value); - return result; - } - - /// Note that this creates *shallow* copies of `value`. - pub fn addManyAtAssumeCapacity(self: *Self, index: usize, value: T, count: usize) []T { - const result = self.#unmanaged.addManyAt(index, count); - @memset(result, value); - return result; - } - - /// This method takes ownership of all elements in `new_items`. - pub fn insertSlice(self: *Self, index: usize, new_items: []const T) AllocError!void { - return self.#unmanaged.insertSlice(self.getStdAllocator(), index, new_items); - } - - /// This method `deinit`s the removed items. - /// This method takes ownership of all elements in `new_items`. - pub fn replaceRange( - self: *Self, - start: usize, - len: usize, - new_items: []const T, - ) AllocError!void { - bun.memory.deinit(self.items()[start .. start + len]); - return self.replaceRangeShallow(start, len, new_items); - } - - /// This method does *not* `deinit` the removed items. - /// This method takes ownership of all elements in `new_items`. - pub fn replaceRangeShallow( - self: *Self, - start: usize, - len: usize, - new_items: []const T, - ) AllocError!void { - return self.#unmanaged.replaceRange(self.getStdAllocator(), start, len, new_items); - } - - /// This method `deinit`s the removed items. - /// This method takes ownership of all elements in `new_items`. - pub fn replaceRangeAssumeCapacity( - self: *Self, - start: usize, - len: usize, - new_items: []const T, - ) void { - for (self.items()[start .. start + len]) |*item| { - bun.memory.deinit(item); - } - self.replaceRangeAssumeCapacityShallow(start, len, new_items); - } - - /// This method does *not* `deinit` the removed items. - /// This method takes ownership of all elements in `new_items`. - pub fn replaceRangeAssumeCapacityShallow( - self: *Self, - start: usize, - len: usize, - new_items: []const T, - ) void { - self.#unmanaged.replaceRangeAssumeCapacity(start, len, new_items); - } - - pub fn append(self: *Self, item: T) AllocError!void { - return self.#unmanaged.append(self.getStdAllocator(), item); - } - - pub fn appendAssumeCapacity(self: *Self, item: T) void { - self.#unmanaged.appendAssumeCapacity(item); - } - - pub fn orderedRemove(self: *Self, i: usize) T { - return self.#unmanaged.orderedRemove(i); - } - - pub fn swapRemove(self: *Self, i: usize) T { - return self.#unmanaged.swapRemove(i); - } - - /// This method takes ownership of all elements in `new_items`. - pub fn appendSlice(self: *Self, new_items: []const T) AllocError!void { - return self.#unmanaged.appendSlice(self.getStdAllocator(), new_items); - } - - /// This method takes ownership of all elements in `new_items`. - pub fn appendSliceAssumeCapacity(self: *Self, new_items: []const T) void { - self.#unmanaged.appendSliceAssumeCapacity(new_items); - } - - /// This method takes ownership of all elements in `new_items`. - pub fn appendUnalignedSlice(self: *Self, new_items: []align(1) const T) AllocError!void { - return self.#unmanaged.appendUnalignedSlice(self.getStdAllocator(), new_items); - } - - /// This method takes ownership of all elements in `new_items`. - pub fn appendUnalignedSliceAssumeCapacity(self: *Self, new_items: []align(1) const T) void { - self.#unmanaged.appendUnalignedSliceAssumeCapacity(new_items); - } - - /// Note that this creates *shallow* copies of `value`. - pub inline fn appendNTimes(self: *Self, value: T, n: usize) AllocError!void { - return self.#unmanaged.appendNTimes(self.getStdAllocator(), value, n); - } - - /// Note that this creates *shallow* copies of `value`. - pub inline fn appendNTimesAssumeCapacity(self: *Self, value: T, n: usize) void { - self.#unmanaged.appendNTimesAssumeCapacity(value, n); - } - - /// If `new_len` is less than the current length, this method will call `deinit` on the - /// removed items. - /// - /// If `new_len` is greater than the current length, note that this creates *shallow* copies - /// of `init_value`. - pub fn resize(self: *Self, init_value: T, new_len: usize) AllocError!void { - const len = self.items().len; - try self.resizeWithoutDeinit(init_value, new_len); - if (new_len < len) { - bun.memory.deinit(self.items().ptr[new_len..len]); - } - } - - /// If `new_len` is less than the current length, this method will *not* call `deinit` on - /// the removed items. - /// - /// If `new_len` is greater than the current length, note that this creates *shallow* copies - /// of `init_value`. - pub fn resizeWithoutDeinit(self: *Self, init_value: T, new_len: usize) AllocError!void { - const len = self.items().len; - try self.#unmanaged.resize(self.getStdAllocator(), new_len); - if (new_len > len) { - @memset(self.items()[len..], init_value); - } - } - - /// This method `deinit`s the removed items. - pub fn shrinkAndFree(self: *Self, new_len: usize) void { - self.prepareForDeepShrink(new_len); - self.shrinkAndFreeShallow(new_len); - } - - /// This method does *not* `deinit` the removed items. - pub fn shrinkAndFreeShallow(self: *Self, new_len: usize) void { - self.#unmanaged.shrinkAndFree(self.getStdAllocator(), new_len); - } - - /// This method `deinit`s the removed items. - pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { - self.prepareForDeepShrink(new_len); - self.shrinkRetainingCapacityShallow(new_len); - } - - /// This method does *not* `deinit` the removed items. - pub fn shrinkRetainingCapacityShallow(self: *Self, new_len: usize) void { - self.#unmanaged.shrinkRetainingCapacity(new_len); - } - - /// This method `deinit`s all items. - pub fn clearRetainingCapacity(self: *Self) void { - bun.memory.deinit(self.items()); - self.clearRetainingCapacityShallow(); - } - - /// This method does *not* `deinit` any items. - pub fn clearRetainingCapacityShallow(self: *Self) void { - self.#unmanaged.clearRetainingCapacity(); - } - - /// This method `deinit`s all items. - pub fn clearAndFree(self: *Self) void { - bun.memory.deinit(self.items()); - self.clearAndFreeShallow(); - } - - /// This method does *not* `deinit` any items. - pub fn clearAndFreeShallow(self: *Self) void { - self.#unmanaged.clearAndFree(self.getStdAllocator()); - } - - pub fn ensureTotalCapacity(self: *Self, new_capacity: usize) AllocError!void { - return self.#unmanaged.ensureTotalCapacity(self.getStdAllocator(), new_capacity); - } - - pub fn ensureTotalCapacityPrecise(self: *Self, new_capacity: usize) AllocError!void { - return self.#unmanaged.ensureTotalCapacityPrecise(self.getStdAllocator(), new_capacity); - } - - pub fn ensureUnusedCapacity(self: *Self, additional_count: usize) AllocError!void { - return self.#unmanaged.ensureUnusedCapacity(self.getStdAllocator(), additional_count); - } - - /// Note that this creates *shallow* copies of `init_value`. - pub fn expandToCapacity(self: *Self, init_value: T) void { - const len = self.items().len; - self.#unmanaged.expandToCapacity(); - @memset(self.items()[len..], init_value); - } - - pub fn pop(self: *Self) ?T { - return self.#unmanaged.pop(); - } - - pub fn getLast(self: *const Self) *T { - const items_ = self.items(); - return &items_[items_.len - 1]; - } - - pub fn getLastOrNull(self: *const Self) ?*T { - return if (self.isEmpty()) null else self.getLast(); - } - - pub fn isEmpty(self: *const Self) bool { - return self.items().len == 0; - } - - fn prepareForDeepShrink(self: *Self, new_len: usize) void { - const items_ = self.items(); - bun.assertf( - new_len <= items_.len, - "new_len ({d}) cannot exceed current len ({d})", - .{ new_len, items_.len }, - ); - bun.memory.deinit(items_[new_len..]); - } - - fn getStdAllocator(self: *const Self) std.mem.Allocator { - return bun.allocators.asStd(self.#allocator); - } - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const AllocError = std.mem.Allocator.Error; diff --git a/src/collections/baby_list.zig b/src/collections/baby_list.zig deleted file mode 100644 index 400ffdfe4b3b..000000000000 --- a/src/collections/baby_list.zig +++ /dev/null @@ -1,660 +0,0 @@ -/// This is like ArrayList except it stores the length and capacity as u32 -/// In practice, it is very unusual to have lengths above 4 GiB -pub fn BabyList(comptime Type: type) type { - const Origin = union(enum) { - owned, - borrowed: struct { - trace: if (traces_enabled) StoredTrace else void, - }, - }; - - return struct { - const Self = @This(); - - // NOTE: If you add, remove, or rename any public fields, you need to update - // `looksLikeListContainerType` in `meta.zig`. - - /// Don't access this field directly, as it's not safety-checked. Use `.slice()`, `.at()`, - /// or `.mut()`. - ptr: [*]Type = &.{}, - len: u32 = 0, - cap: u32 = 0, - #origin: if (safety_checks) Origin else void = if (safety_checks) .owned, - #allocator: bun.safety.CheckedAllocator = .{}, - - pub const Elem = Type; - - pub const empty: Self = .{}; - - pub fn initCapacity(allocator: std.mem.Allocator, len: usize) OOM!Self { - var this = initWithBuffer(try allocator.alloc(Type, len)); - this.#allocator.set(allocator); - return this; - } - - pub fn initOne(allocator: std.mem.Allocator, value: Type) OOM!Self { - var items = try allocator.alloc(Type, 1); - items[0] = value; - return .{ - .ptr = @as([*]Type, @ptrCast(items.ptr)), - .len = 1, - .cap = 1, - .#allocator = .init(allocator), - }; - } - - pub fn moveFromList(list_ptr: anytype) Self { - const ListType = std.meta.Child(@TypeOf(list_ptr)); - - if (comptime ListType == Self) { - @compileError("unnecessary call to `moveFromList`"); - } - - const unsupported_arg_msg = "unsupported argument to `moveFromList`: *" ++ - @typeName(ListType); - - const capacity = if (comptime @hasField(ListType, "capacity")) - list_ptr.capacity - else if (comptime @hasField(ListType, "cap")) - list_ptr.cap - else if (comptime std.meta.hasFn(ListType, "capacity")) - list_ptr.capacity() - else - @compileError(unsupported_arg_msg); - - const items = if (comptime std.meta.hasFn(ListType, "moveToUnmanaged")) - list_ptr.moveToUnmanaged().items - else if (comptime @hasField(ListType, "items")) - list_ptr.items - else if (comptime std.meta.hasFn(ListType, "slice")) - list_ptr.slice() - else - @compileError(unsupported_arg_msg); - - if (comptime Environment.allow_assert) { - bun.assert(items.len <= capacity); - } - - var this: Self = .{ - .ptr = items.ptr, - .len = @intCast(items.len), - .cap = @intCast(capacity), - }; - - const allocator = if (comptime @hasField(ListType, "allocator")) - list_ptr.allocator - else if (comptime std.meta.hasFn(ListType, "allocator")) - list_ptr.allocator(); - - if (comptime @TypeOf(allocator) == void) { - list_ptr.* = .empty; - } else { - this.#allocator.set(bun.allocators.asStd(allocator)); - // `moveToUnmanaged` already cleared the old list. - if (comptime !std.meta.hasFn(ListType, "moveToUnmanaged")) { - list_ptr.* = .init(allocator); - } - } - return this; - } - - /// Requirements: - /// - /// * `items` must be owned memory, allocated with some allocator. That same allocator must - /// be passed to methods that expect it, like `append`. - /// - /// * `items` must be the *entire* region of allocated memory. It cannot be a subslice. - /// If you really need an owned subslice, use `shrinkRetainingCapacity` followed by - /// `toOwnedSlice` on an `ArrayList`. - pub fn fromOwnedSlice(items: []Type) Self { - return .{ - .ptr = items.ptr, - .len = @intCast(items.len), - .cap = @intCast(items.len), - }; - } - - /// Same requirements as `fromOwnedSlice`. - pub fn initWithBuffer(buffer: []Type) Self { - return .{ - .ptr = buffer.ptr, - .len = 0, - .cap = @intCast(buffer.len), - }; - } - - /// Copies all elements of `items` into new memory. Creates shallow copies. - pub fn fromSlice(allocator: std.mem.Allocator, items: []const Type) OOM!Self { - const allocated = try allocator.alloc(Type, items.len); - bun.copy(Type, allocated, items); - - return Self{ - .ptr = allocated.ptr, - .len = @intCast(allocated.len), - .cap = @intCast(allocated.len), - .#allocator = .init(allocator), - }; - } - - /// This method invalidates the `BabyList`. Use `clearAndFree` if you want to empty the - /// list instead. - pub fn deinit(this: *Self, allocator: std.mem.Allocator) void { - this.assertOwned(); - this.listManaged(allocator).deinit(); - this.* = undefined; - } - - pub fn clearAndFree(this: *Self, allocator: std.mem.Allocator) void { - this.deinit(allocator); - this.* = .{}; - } - - pub fn clearRetainingCapacity(this: *Self) void { - this.len = 0; - } - - pub fn slice(this: Self) callconv(bun.callconv_inline) []Type { - return this.ptr[0..this.len]; - } - - /// Same as `.slice()`, with an explicit coercion to const. - pub fn sliceConst(this: Self) callconv(bun.callconv_inline) []const Type { - return this.slice(); - } - - pub fn at(this: Self, index: usize) callconv(bun.callconv_inline) *const Type { - bun.assert(index < this.len); - return &this.ptr[index]; - } - - pub fn mut(this: Self, index: usize) callconv(bun.callconv_inline) *Type { - bun.assert(index < this.len); - return &this.ptr[index]; - } - - pub fn first(this: Self) callconv(bun.callconv_inline) ?*Type { - return if (this.len > 0) &this.ptr[0] else null; - } - - pub fn last(this: Self) callconv(bun.callconv_inline) ?*Type { - return if (this.len > 0) &this.ptr[this.len - 1] else null; - } - - /// Empties the `BabyList`. - pub fn toOwnedSlice(this: *Self, allocator: std.mem.Allocator) OOM![]Type { - if ((comptime safety_checks) and this.len != this.cap) this.assertOwned(); - var list_ = this.listManaged(allocator); - const result = try list_.toOwnedSlice(); - this.* = .empty; - return result; - } - - pub fn moveToList(this: *Self) std.ArrayListUnmanaged(Type) { - this.assertOwned(); - defer this.* = .empty; - return this.list(); - } - - pub fn moveToListManaged(this: *Self, allocator: std.mem.Allocator) std.array_list.Managed(Type) { - this.assertOwned(); - defer this.* = .empty; - return this.listManaged(allocator); - } - - pub fn expandToCapacity(this: *Self) void { - this.len = this.cap; - } - - pub fn ensureTotalCapacity( - this: *Self, - allocator: std.mem.Allocator, - new_capacity: usize, - ) !void { - if ((comptime safety_checks) and new_capacity > this.cap) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.ensureTotalCapacity(new_capacity); - this.update(list_); - } - - pub fn ensureTotalCapacityPrecise( - this: *Self, - allocator: std.mem.Allocator, - new_capacity: usize, - ) !void { - if ((comptime safety_checks) and new_capacity > this.cap) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.ensureTotalCapacityPrecise(new_capacity); - this.update(list_); - } - - pub fn ensureUnusedCapacity( - this: *Self, - allocator: std.mem.Allocator, - count: usize, - ) OOM!void { - if ((comptime safety_checks) and count > this.cap - this.len) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.ensureUnusedCapacity(count); - this.update(list_); - } - - pub fn shrinkAndFree(this: *Self, allocator: std.mem.Allocator, new_len: usize) void { - if ((comptime safety_checks) and new_len < this.cap) this.assertOwned(); - var list_ = this.listManaged(allocator); - list_.shrinkAndFree(new_len); - this.update(list_); - } - - pub fn shrinkRetainingCapacity(this: *Self, new_len: usize) void { - bun.assertf( - new_len <= this.len, - "shrinkRetainingCapacity: new len ({d}) cannot exceed old ({d})", - .{ new_len, this.len }, - ); - this.len = @intCast(new_len); - } - - pub fn append(this: *Self, allocator: std.mem.Allocator, value: Type) OOM!void { - if ((comptime safety_checks) and this.len == this.cap) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.append(value); - this.update(list_); - } - - pub fn appendAssumeCapacity(this: *Self, value: Type) void { - bun.assert(this.cap > this.len); - this.ptr[this.len] = value; - this.len += 1; - } - - pub fn appendSlice(this: *Self, allocator: std.mem.Allocator, vals: []const Type) !void { - if ((comptime safety_checks) and this.cap - this.len < vals.len) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.appendSlice(vals); - this.update(list_); - } - - pub fn appendSliceAssumeCapacity(this: *Self, values: []const Type) void { - bun.assert(this.cap >= this.len + @as(u32, @intCast(values.len))); - const tail = this.ptr[this.len .. this.len + values.len]; - bun.copy(Type, tail, values); - this.len += @intCast(values.len); - bun.assert(this.cap >= this.len); - } - - pub fn pop(this: *Self) ?Type { - if (this.len == 0) return null; - this.len -= 1; - return this.ptr[this.len]; - } - - pub fn orderedRemove(this: *Self, index: usize) Type { - var l = this.list(); - defer this.update(l); - return l.orderedRemove(index); - } - - pub fn swapRemove(this: *Self, index: usize) Type { - var l = this.list(); - defer this.update(l); - return l.swapRemove(index); - } - - pub fn insert(this: *Self, allocator: std.mem.Allocator, index: usize, val: Type) OOM!void { - if ((comptime safety_checks) and this.len == this.cap) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.insert(index, val); - this.update(list_); - } - - pub fn insertSlice( - this: *Self, - allocator: std.mem.Allocator, - index: usize, - vals: []const Type, - ) OOM!void { - if ((comptime safety_checks) and this.cap - this.len < vals.len) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.insertSlice(index, vals); - this.update(list_); - } - - pub fn replaceRange( - allocator: std.mem.Allocator, - this: *Self, - start: usize, - len_: usize, - new_items: []const Type, - ) OOM!void { - var list_ = this.listManaged(allocator); - try list_.replaceRange(start, len_, new_items); - } - - pub fn clone(this: Self, allocator: std.mem.Allocator) OOM!Self { - var copy = try this.list().clone(allocator); - return .moveFromList(©); - } - - pub fn unusedCapacitySlice(this: Self) []Type { - return this.ptr[this.len..this.cap]; - } - - pub fn contains(this: Self, item: []const Type) bool { - return this.len > 0 and - @intFromPtr(item.ptr) >= @intFromPtr(this.ptr) and - @intFromPtr(item.ptr) < @intFromPtr(this.ptr) + this.len; - } - - pub fn sortAsc(this: *Self) void { - bun.strings.sortAsc(this.slice()); - } - - pub fn sort(this: *Self, comptime Context: type, context: Context) void { - std.sort.pdq(Type, this.slice(), context, Context.lessThan); - } - - pub fn writableSlice( - this: *Self, - allocator: std.mem.Allocator, - additional: usize, - ) OOM![]Type { - if ((comptime safety_checks) and additional > this.cap - this.len) this.assertOwned(); - var list_ = this.listManaged(allocator); - try list_.ensureUnusedCapacity(additional); - const prev_len = list_.items.len; - list_.items.len += additional; - const writable = list_.items[prev_len..]; - this.update(list_); - return writable; - } - - pub fn allocatedSlice(this: Self) []Type { - return this.ptr[0..this.cap]; - } - - pub fn memoryCost(this: Self) usize { - return this.cap * @sizeOf(Type); - } - - /// This method is available only for `BabyList(u8)`. - pub fn appendFmt( - this: *Self, - allocator: std.mem.Allocator, - comptime fmt: []const u8, - args: anytype, - ) OOM!void { - if ((comptime safety_checks) and this.len == this.cap) this.assertOwned(); - var list_ = this.listManaged(allocator); - const writer = list_.writer(); - try writer.print(fmt, args); - this.update(list_); - } - - /// This method is available only for `BabyList(u8)`. - pub fn write(this: *Self, allocator: std.mem.Allocator, str: []const u8) OOM!u32 { - if ((comptime safety_checks) and this.cap - this.len < str.len) this.assertOwned(); - if (comptime Type != u8) - @compileError("Unsupported for type " ++ @typeName(Type)); - const initial = this.len; - var list_ = this.listManaged(allocator); - try list_.appendSlice(str); - this.update(list_); - return this.len - initial; - } - - /// This method is available only for `BabyList(u8)`. - pub fn writeLatin1(this: *Self, allocator: std.mem.Allocator, str: []const u8) OOM!u32 { - if ((comptime safety_checks) and str.len > 0) this.assertOwned(); - if (comptime Type != u8) - @compileError("Unsupported for type " ++ @typeName(Type)); - const initial = this.len; - const old = this.listManaged(allocator); - const new = try strings.allocateLatin1IntoUTF8WithList(old, old.items.len, str); - this.update(new); - return this.len - initial; - } - - /// This method is available only for `BabyList(u8)`. Invalid characters are replaced with - /// replacement character - pub fn writeUTF16(this: *Self, allocator: std.mem.Allocator, str: []const u16) OOM!u32 { - if ((comptime safety_checks) and str.len > 0) this.assertOwned(); - if (comptime Type != u8) - @compileError("Unsupported for type " ++ @typeName(Type)); - - const initial_len = this.len; - - var list_ = this.listManaged(allocator); - { - defer this.update(list_); - - // Maximum UTF-16 length is 3 times the UTF-8 length + 2 - const length_estimate = if (list_.unusedCapacitySlice().len <= (str.len * 3 + 2)) - // This length is an estimate. `str` isn't validated and might contain invalid - // sequences. If it does simdutf will assume they require 2 characters instead - // of 3. - bun.simdutf.length.utf8.from.utf16.le(str) - else - str.len; - - try list_.ensureUnusedCapacity(length_estimate); - - try strings.convertUTF16ToUTF8Append(&list_, str); - } - - return this.len - initial_len; - } - - /// This method is available only for `BabyList(u8)`. - pub fn writeTypeAsBytesAssumeCapacity(this: *Self, comptime Int: type, int: Int) void { - if (comptime Type != u8) - @compileError("Unsupported for type " ++ @typeName(Type)); - bun.assert(this.cap >= this.len + @sizeOf(Int)); - @as([*]align(1) Int, @ptrCast(this.ptr[this.len .. this.len + @sizeOf(Int)]))[0] = int; - this.len += @sizeOf(Int); - } - - pub fn parse(input: *bun.css.Parser) bun.css.Result(Self) { - return switch (input.parseCommaSeparated(Type, bun.css.generic.parseFor(Type))) { - .result => |v| return .{ .result = Self{ - .ptr = v.items.ptr, - .len = @intCast(v.items.len), - .cap = @intCast(v.capacity), - } }, - .err => |e| return .{ .err = e }, - }; - } - - pub fn toCss(this: *const Self, dest: *bun.css.Printer) bun.css.PrintErr!void { - return bun.css.to_css.fromBabyList(Type, this, dest); - } - - pub fn eql(lhs: *const Self, rhs: *const Self) bool { - if (lhs.len != rhs.len) return false; - for (lhs.sliceConst(), rhs.sliceConst()) |*a, *b| { - if (!bun.css.generic.eql(Type, a, b)) return false; - } - return true; - } - - pub fn deepClone(this: Self, allocator: std.mem.Allocator) !Self { - if (!@hasDecl(Type, "deepClone")) { - @compileError("Unsupported type for BabyList.deepClone(): " ++ @typeName(Type)); - } - - var list_ = try initCapacity(allocator, this.len); - for (this.slice()) |item| { - const clone_result = item.deepClone(allocator); - const cloned_item = switch (comptime @typeInfo(@TypeOf(clone_result))) { - .error_union => try clone_result, - else => clone_result, - }; - list_.appendAssumeCapacity(cloned_item); - } - return list_; - } - - /// Same as `deepClone` but calls `bun.outOfMemory` instead of returning an error. - /// `Type.deepClone` must not return any error except `error.OutOfMemory`. - pub fn deepCloneInfallible(this: Self, allocator: std.mem.Allocator) Self { - return bun.handleOom(this.deepClone(allocator)); - } - - /// Avoid using this function. It creates a `BabyList` that will immediately invoke - /// illegal behavior if you call any method that could allocate or free memory. On top of - /// that, if `items` points to read-only memory, any attempt to modify a list element (which - /// is very easy given how many methods return non-const pointers and slices) will also - /// invoke illegal behavior. - /// - /// To find an alternative: - /// - /// 1. Determine how the resulting `BabyList` is being used. Is it stored in a struct field? - /// Is it passed to a function? - /// - /// 2. Determine whether that struct field or function parameter expects the list to be - /// mutable. Does it potentially call any methods that could allocate or free, like - /// `append` or `deinit`? - /// - /// 3. If the list is expected to be mutable, don't use this function, because the returned - /// list will invoke illegal behavior if mutated. Use `fromSlice` or another allocating - /// function instead. - /// - /// 4. If the list is *not* expected to be mutable, don't use a `BabyList` at all. Change - /// the field or parameter to be a plain slice instead. - /// - /// Requirements: - /// - /// * Methods that could potentially free, remap, or resize `items` cannot be called. - pub fn fromBorrowedSliceDangerous(items: []const Type) Self { - var this: Self = .fromOwnedSlice(@constCast(items)); - if (comptime safety_checks) this.#origin = .{ .borrowed = .{ - .trace = if (traces_enabled) .capture(@returnAddress()), - } }; - return this; - } - - /// Transfers ownership of this `BabyList` to a new allocator. - /// - /// This method is valid only if both the old allocator and new allocator are - /// `MimallocArena`s. See `bun.safety.CheckedAllocator.transferOwnership`. - pub fn transferOwnership(this: *Self, new_allocator: anytype) void { - this.#allocator.transferOwnership(new_allocator); - } - - pub fn format( - this: Self, - writer: *std.Io.Writer, - ) !void { - return writer.print( - "BabyList({s}){{{f}}}", - .{ @typeName(Type), this.list() }, - ); - } - - fn assertOwned(this: *Self) void { - if ((comptime !safety_checks) or this.#origin == .owned) return; - if (comptime traces_enabled) { - bun.Output.note("borrowed BabyList created here:", .{}); - bun.crash_handler.dumpStackTrace( - this.#origin.borrowed.trace.trace(), - .{ .frame_count = 10, .stop_at_jsc_llint = true }, - ); - } - std.debug.panic( - "cannot perform this operation on a BabyList that doesn't own its data", - .{}, - ); - } - - fn list(this: Self) std.ArrayListUnmanaged(Type) { - return .{ - .items = this.slice(), - .capacity = this.cap, - }; - } - - fn listManaged(this: *Self, allocator: std.mem.Allocator) std.array_list.Managed(Type) { - this.#allocator.set(allocator); - var list_ = this.list(); - return list_.toManaged(allocator); - } - - fn update(this: *Self, list_: anytype) void { - this.ptr = list_.items.ptr; - this.len = @intCast(list_.items.len); - this.cap = @intCast(list_.capacity); - if (comptime Environment.allow_assert) { - bun.assert(this.len <= this.cap); - } - } - - pub const looksLikeContainerTypeBabyList = Type; - }; -} - -pub const ByteList = BabyList(u8); - -pub const OffsetByteList = struct { - const Self = @This(); - - head: u32 = 0, - byte_list: ByteList = .{}, - - pub fn init(head: u32, byte_list: ByteList) Self { - return .{ - .head = head, - .byte_list = byte_list, - }; - } - - pub fn write(self: *Self, allocator: std.mem.Allocator, bytes: []const u8) !void { - _ = try self.byte_list.write(allocator, bytes); - } - - pub fn slice(self: *const Self) []u8 { - return self.byte_list.slice()[0..self.head]; - } - - pub fn remaining(self: *const Self) []u8 { - return self.byte_list.slice()[self.head..]; - } - - pub fn consume(self: *Self, bytes: u32) void { - self.head +|= bytes; - if (self.head >= self.byte_list.len) { - self.head = 0; - self.byte_list.len = 0; - } - } - - pub fn len(self: *const Self) u32 { - return self.byte_list.len - self.head; - } - - pub fn clear(self: *Self) void { - self.head = 0; - self.byte_list.len = 0; - } - - /// This method invalidates `self`. Use `clearAndFree` to reset to empty instead. - pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { - self.byte_list.deinit(allocator); - self.* = undefined; - } - - pub fn clearAndFree(self: *Self, allocator: std.mem.Allocator) void { - self.deinit(allocator); - self.* = .{}; - } -}; - -pub const safety_checks = Environment.ci_assert; - -const std = @import("std"); - -const bun = @import("bun"); -const OOM = bun.OOM; -const strings = bun.strings; -const StoredTrace = bun.crash_handler.StoredTrace; - -const Environment = bun.Environment; -const traces_enabled = Environment.isDebug; diff --git a/src/collections/bit_set.zig b/src/collections/bit_set.zig deleted file mode 100644 index 1565a8842a47..000000000000 --- a/src/collections/bit_set.zig +++ /dev/null @@ -1,1968 +0,0 @@ -//! This is a fork of Zig standard library bit_set.zig -//! - https://github.com/ziglang/zig/pull/14129 -//! - AutoBitset which optimally chooses between a dynamic or static bitset. -//! Prefer our fork over std.bit_set. -//! -//! This file defines several variants of bit sets. A bit set -//! is a densely stored set of integers with a known maximum, -//! in which each integer gets a single bit. Bit sets have very -//! fast presence checks, update operations, and union and intersection -//! operations. However, if the number of possible items is very -//! large and the number of actual items in a given set is usually -//! small, they may be less memory efficient than an array set. -//! -//! There are five variants defined here: -//! -//! IntegerBitSet: -//! A bit set with static size, which is backed by a single integer. -//! This set is good for sets with a small size, but may generate -//! inefficient code for larger sets, especially in debug mode. -//! -//! ArrayBitSet: -//! A bit set with static size, which is backed by an array of usize. -//! This set is good for sets with a larger size, but may use -//! more bytes than necessary if your set is small. -//! -//! StaticBitSet: -//! Picks either IntegerBitSet or ArrayBitSet depending on the requested -//! size. The interfaces of these two types match exactly, except for fields. -//! -//! DynamicBitSet: -//! A bit set with runtime-known size, backed by an allocated slice -//! of usize. -//! -//! DynamicBitSetUnmanaged: -//! A variant of DynamicBitSet which does not store a pointer to its -//! allocator, in order to save space. - -/// Returns the optimal static bit set type for the specified number -/// of elements. The returned type will perform no allocations, -/// can be copied by value, and does not require deinitialization. -/// Both possible implementations fulfill the same interface. -pub fn StaticBitSet(comptime size: usize) type { - if (size <= @bitSizeOf(usize)) { - return IntegerBitSet(size); - } else { - return ArrayBitSet(usize, size); - } -} - -/// A bit set with static size, which is backed by a single integer. -/// This set is good for sets with a small size, but may generate -/// inefficient code for larger sets, especially in debug mode. -pub fn IntegerBitSet(comptime size: u16) type { - return packed struct { - const Self = @This(); - - // TODO: Make this a comptime field once those are fixed - /// The number of items in this bit set - pub const bit_length: usize = size; - - /// The integer type used to represent a mask in this bit set - pub const MaskInt = std.meta.Int(.unsigned, size); - - /// The integer type used to shift a mask in this bit set - pub const ShiftInt = std.math.Log2Int(MaskInt); - - /// The bit mask, as a single integer - mask: MaskInt, - - /// Creates a bit set with no elements present. - pub fn initEmpty() Self { - return .{ .mask = 0 }; - } - - /// Creates a bit set with all elements present. - pub fn initFull() Self { - return .{ .mask = ~@as(MaskInt, 0) }; - } - - /// Returns the number of bits in this bit set - pub fn capacity(self: Self) callconv(bun.callconv_inline) usize { - _ = self; - return bit_length; - } - - /// Returns true if the bit at the specified index - /// is present in the set, false otherwise. - pub fn isSet(self: Self, index: usize) bool { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - return (self.mask & maskBit(index)) != 0; - } - - /// Returns the total number of set bits in this bit set. - pub fn count(self: Self) usize { - return @popCount(self.mask); - } - - /// Changes the value of the specified bit of the bit - /// set to match the passed boolean. - pub fn setValue(self: *Self, index: usize, value: bool) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - if (MaskInt == u0) return; - const bit = maskBit(index); - const new_bit = bit & std.math.boolMask(MaskInt, value); - self.mask = (self.mask & ~bit) | new_bit; - } - - /// Adds a specific bit to the bit set - pub fn set(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - self.mask |= maskBit(index); - } - - /// Changes the value of all bits in the specified range to - /// match the passed boolean. - pub fn setRangeValue(self: *Self, range: Range, value: bool) void { - if (comptime Environment.allow_assert) { - bun.assert(range.end <= bit_length); - bun.assert(range.start <= range.end); - } - if (range.start == range.end) return; - if (MaskInt == u0) return; - - const start_bit = @as(ShiftInt, @intCast(range.start)); - - var mask = std.math.boolMask(MaskInt, true) << start_bit; - if (range.end != bit_length) { - const end_bit = @as(ShiftInt, @intCast(range.end)); - mask &= std.math.boolMask(MaskInt, true) >> @as(ShiftInt, @truncate(@as(usize, @bitSizeOf(MaskInt)) - @as(usize, end_bit))); - } - self.mask &= ~mask; - - mask = std.math.boolMask(MaskInt, value) << start_bit; - if (range.end != bit_length) { - const end_bit = @as(ShiftInt, @intCast(range.end)); - mask &= std.math.boolMask(MaskInt, value) >> @as(ShiftInt, @truncate(@as(usize, @bitSizeOf(MaskInt)) - @as(usize, end_bit))); - } - self.mask |= mask; - } - - /// Removes a specific bit from the bit set - pub fn unset(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - // Workaround for #7953 - if (MaskInt == u0) return; - self.mask &= ~maskBit(index); - } - - /// Flips a specific bit in the bit set - pub fn toggle(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - self.mask ^= maskBit(index); - } - - /// Flips all bits in this bit set which are present - /// in the toggles bit set. - pub fn toggleSet(self: *Self, toggles: Self) void { - self.mask ^= toggles.mask; - } - - /// Flips every bit in the bit set. - pub fn toggleAll(self: *Self) void { - self.mask = ~self.mask; - } - - /// Performs a union of two bit sets, and stores the - /// result in the first one. Bits in the result are - /// set if the corresponding bits were set in either input. - pub fn setUnion(self: *Self, other: Self) void { - self.mask |= other.mask; - } - - /// Performs an intersection of two bit sets, and stores - /// the result in the first one. Bits in the result are - /// set if the corresponding bits were set in both inputs. - pub fn setIntersection(self: *Self, other: Self) void { - self.mask &= other.mask; - } - - /// Finds the index of the first set bit. - /// If no bits are set, returns null. - pub fn findFirstSet(self: Self) ?usize { - const mask = self.mask; - if (mask == 0) return null; - return @ctz(mask); - } - - /// Finds the index of the first unset bit. - /// If all bits are set, returns null. - pub fn findFirstUnset(self: Self) ?usize { - const mask = ~self.mask; - if (mask == 0) return null; - return @ctz(mask); - } - - /// Finds the index of the first set bit, and unsets it. - /// If no bits are set, returns null. - pub fn toggleFirstSet(self: *Self) ?usize { - const mask = self.mask; - if (mask == 0) return null; - const index = @ctz(mask); - self.mask = mask & (mask - 1); - return index; - } - - /// Returns true iff every corresponding bit in both - /// bit sets are the same. - pub fn eql(self: Self, other: Self) bool { - return bit_length == 0 or self.mask == other.mask; - } - - /// Returns true iff the first bit set is the subset - /// of the second one. - pub fn subsetOf(self: Self, other: Self) bool { - return self.intersectWith(other).eql(self); - } - - /// Returns true iff the first bit set is the superset - /// of the second one. - pub fn supersetOf(self: Self, other: Self) bool { - return other.subsetOf(self); - } - - /// Returns the complement bit sets. Bits in the result - /// are set if the corresponding bits were not set. - pub fn complement(self: Self) Self { - var result = self; - result.toggleAll(); - return result; - } - - /// Returns the union of two bit sets. Bits in the - /// result are set if the corresponding bits were set - /// in either input. - pub fn unionWith(self: Self, other: Self) Self { - var result = self; - result.setUnion(other); - return result; - } - - /// Returns the intersection of two bit sets. Bits in - /// the result are set if the corresponding bits were - /// set in both inputs. - pub fn intersectWith(self: Self, other: Self) Self { - var result = self; - result.setIntersection(other); - return result; - } - - /// Returns the xor of two bit sets. Bits in the - /// result are set if the corresponding bits were - /// not the same in both inputs. - pub fn xorWith(self: Self, other: Self) Self { - var result = self; - result.toggleSet(other); - return result; - } - - /// Returns the difference of two bit sets. Bits in - /// the result are set if set in the first but not - /// set in the second set. - pub fn differenceWith(self: Self, other: Self) Self { - var result = self; - result.setIntersection(other.complement()); - return result; - } - - /// Iterates through the items in the set, according to the options. - /// The default options (.{}) will iterate indices of set bits in - /// ascending order. Modifications to the underlying bit set may - /// or may not be observed by the iterator. - pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) { - return .{ - .bits_remain = switch (options.kind) { - .set => self.mask, - .unset => ~self.mask, - }, - }; - } - - pub fn Iterator(comptime options: IteratorOptions) type { - return SingleWordIterator(options.direction); - } - - fn SingleWordIterator(comptime direction: IteratorOptions.Direction) type { - return struct { - const IterSelf = @This(); - // all bits which have not yet been iterated over - bits_remain: MaskInt, - - /// Returns the index of the next unvisited set bit - /// in the bit set, in ascending order. - pub fn next(self: *IterSelf) ?usize { - if (self.bits_remain == 0) return null; - - switch (direction) { - .forward => { - const next_index = @ctz(self.bits_remain); - self.bits_remain &= self.bits_remain - 1; - return next_index; - }, - .reverse => { - const leading_zeroes = @clz(self.bits_remain); - const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes; - self.bits_remain &= (@as(MaskInt, 1) << @as(ShiftInt, @intCast(top_bit))) - 1; - return top_bit; - }, - } - } - }; - } - - fn maskBit(index: usize) MaskInt { - if (MaskInt == u0) return 0; - return @as(MaskInt, 1) << @as(ShiftInt, @intCast(index)); - } - fn boolMaskBit(index: usize, value: bool) MaskInt { - if (MaskInt == u0) return 0; - return @as(MaskInt, @intFromBool(value)) << @as(ShiftInt, @intCast(index)); - } - }; -} - -/// A bit set with static size, which is backed by an array of usize. -/// This set is good for sets with a larger size, but may use -/// more bytes than necessary if your set is small. -pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type { - const mask_info: std.builtin.Type = @typeInfo(MaskIntType); - - // Make sure the mask int is indeed an int - if (mask_info != .int) @compileError("ArrayBitSet can only operate on integer masks, but was passed " ++ @typeName(MaskIntType)); - - // It must also be unsigned. - if (mask_info.int.signedness != .unsigned) @compileError("ArrayBitSet requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType)); - - // And it must not be empty. - if (MaskIntType == u0) - @compileError("ArrayBitSet requires a sized integer for its mask int. u0 does not work."); - - const byte_size = std.mem.byte_size_in_bits; - - // We use shift and truncate to decompose indices into mask indices and bit indices. - // This operation requires that the mask has an exact power of two number of bits. - if (!std.math.isPowerOfTwo(@bitSizeOf(MaskIntType))) { - var desired_bits = std.math.ceilPowerOfTwoAssert(usize, @bitSizeOf(MaskIntType)); - if (desired_bits < byte_size) desired_bits = byte_size; - const FixedMaskType = std.meta.Int(.unsigned, desired_bits); - @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++ - ", which is not a power of two. Please round this up to a power of two integer size (i.e. " ++ @typeName(FixedMaskType) ++ ")."); - } - - // Make sure the integer has no padding bits. - // Those would be wasteful here and are probably a mistake by the user. - // This case may be hit with small powers of two, like u4. - if (@bitSizeOf(MaskIntType) != @sizeOf(MaskIntType) * byte_size) { - var desired_bits = @sizeOf(MaskIntType) * byte_size; - desired_bits = std.math.ceilPowerOfTwoAssert(usize, desired_bits); - const FixedMaskType = std.meta.Int(.unsigned, desired_bits); - @compileError("ArrayBitSet was passed integer type " ++ @typeName(MaskIntType) ++ - ", which contains padding bits. Please round this up to an unpadded integer size (i.e. " ++ @typeName(FixedMaskType) ++ ")."); - } - - return extern struct { - const Self = @This(); - - // TODO: Make this a comptime field once those are fixed - /// The number of items in this bit set - pub const bit_length: usize = size; - - /// The integer type used to represent a mask in this bit set - pub const MaskInt = MaskIntType; - - /// The integer type used to shift a mask in this bit set - pub const ShiftInt = std.math.Log2Int(MaskInt); - - // bits in one mask - const mask_len = @bitSizeOf(MaskInt); - // total number of masks - const num_masks = (size + mask_len - 1) / mask_len; - // padding bits in the last mask (may be 0) - const last_pad_bits = mask_len * num_masks - size; - // Mask of valid bits in the last mask. - // All functions will ensure that the invalid - // bits in the last mask are zero. - pub const last_item_mask = ~@as(MaskInt, 0) >> last_pad_bits; - - /// The bit masks, ordered with lower indices first. - /// Padding bits at the end are undefined. - masks: [num_masks]MaskInt, - - /// Creates a bit set with no elements present. - pub fn initEmpty() Self { - return .{ .masks = [_]MaskInt{0} ** num_masks }; - } - - /// Creates a bit set with all elements present. - pub fn initFull() Self { - if (num_masks == 0) { - return .{ .masks = .{} }; - } else { - return .{ .masks = [_]MaskInt{~@as(MaskInt, 0)} ** (num_masks - 1) ++ [_]MaskInt{last_item_mask} }; - } - } - - /// Returns the number of bits in this bit set - pub fn capacity(self: Self) callconv(bun.callconv_inline) usize { - _ = self; - return bit_length; - } - - /// Returns true if the bit at the specified index - /// is present in the set, false otherwise. - pub fn isSet(self: *const Self, index: usize) bool { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - if (num_masks == 0) return false; // doesn't compile in this case - return (self.masks[maskIndex(index)] & maskBit(index)) != 0; - } - - /// Returns the total number of set bits in this bit set. - pub fn count(self: *const Self) usize { - var total: usize = 0; - for (self.masks) |mask| { - total += @popCount(mask); - } - return total; - } - - /// Changes the value of the specified bit of the bit - /// set to match the passed boolean. - pub fn setValue(self: *Self, index: usize, value: bool) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - if (num_masks == 0) return; // doesn't compile in this case - const bit = maskBit(index); - const mask_index = maskIndex(index); - const new_bit = bit & std.math.boolMask(MaskInt, value); - self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit; - } - - /// Adds a specific bit to the bit set - pub fn set(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - if (num_masks == 0) return; // doesn't compile in this case - self.masks[maskIndex(index)] |= maskBit(index); - } - - /// Changes the value of all bits in the specified range to - /// match the passed boolean. - pub fn setRangeValue(self: *Self, range: Range, value: bool) void { - if (comptime Environment.allow_assert) { - bun.assert(range.end <= bit_length); - bun.assert(range.start <= range.end); - } - if (range.start == range.end) return; - if (num_masks == 0) return; - - const start_mask_index = maskIndex(range.start); - const start_bit = @as(ShiftInt, @truncate(range.start)); - - const end_mask_index = maskIndex(range.end); - const end_bit = @as(ShiftInt, @truncate(range.end)); - - if (start_mask_index == end_mask_index) { - var mask1 = std.math.boolMask(MaskInt, true) << start_bit; - var mask2 = std.math.boolMask(MaskInt, true) >> (mask_len - 1) - (end_bit - 1); - self.masks[start_mask_index] &= ~(mask1 & mask2); - - mask1 = std.math.boolMask(MaskInt, value) << start_bit; - mask2 = std.math.boolMask(MaskInt, value) >> (mask_len - 1) - (end_bit - 1); - self.masks[start_mask_index] |= mask1 & mask2; - } else { - var bulk_mask_index: usize = 0; - if (start_bit > 0) { - self.masks[start_mask_index] = - (self.masks[start_mask_index] & ~(std.math.boolMask(MaskInt, true) << start_bit)) | - (std.math.boolMask(MaskInt, value) << start_bit); - bulk_mask_index = start_mask_index + 1; - } else { - bulk_mask_index = start_mask_index; - } - - while (bulk_mask_index < end_mask_index) : (bulk_mask_index += 1) { - self.masks[bulk_mask_index] = std.math.boolMask(MaskInt, value); - } - - if (end_bit > 0) { - self.masks[end_mask_index] = - (self.masks[end_mask_index] & (std.math.boolMask(MaskInt, true) << end_bit)) | - (std.math.boolMask(MaskInt, value) >> ((@bitSizeOf(MaskInt) - 1) - (end_bit - 1))); - } - } - } - - /// Removes a specific bit from the bit set - pub fn unset(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - if (num_masks == 0) return; // doesn't compile in this case - self.masks[maskIndex(index)] &= ~maskBit(index); - } - - /// Flips a specific bit in the bit set - pub fn toggle(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < bit_length); - if (num_masks == 0) return; // doesn't compile in this case - self.masks[maskIndex(index)] ^= maskBit(index); - } - - /// Flips all bits in this bit set which are present - /// in the toggles bit set. - pub fn toggleSet(self: *Self, toggles: *const Self) void { - const other = &toggles.masks; - for (self.masks, other) |*mask, b| { - mask.* ^= b; - } - } - - /// Flips every bit in the bit set. - pub fn toggleAll(self: *Self) void { - for (self.masks) |*mask| { - mask.* = ~mask.*; - } - - // Zero the padding bits - if (num_masks > 0) { - self.masks[num_masks - 1] &= last_item_mask; - } - } - - /// Sets all bits - pub fn setAll(self: *Self, value: bool) void { - @memset(&self.masks, if (value) std.math.maxInt(MaskInt) else 0); - - // Zero the padding bits - if (num_masks > 0) { - self.masks[num_masks - 1] &= last_item_mask; - } - } - - /// Performs a union of two bit sets, and stores the - /// result in the first one. Bits in the result are - /// set if the corresponding bits were set in either input. - pub fn setUnion(self: *Self, other: *const Self) void { - for (&self.masks, other[0..self.masks.len]) |*mask, alt| { - mask.* |= alt; - } - } - - /// Performs an intersection of two bit sets, and stores - /// the result in the first one. Bits in the result are - /// set if the corresponding bits were set in both inputs. - pub fn setIntersection(self: *Self, other: *const Self) void { - for (&self.masks, other.masks[0..self.masks.len]) |*mask, alt| { - mask.* &= alt; - } - } - - /// Finds the index of the first set bit. - /// If no bits are set, returns null. - pub fn findFirstSet(self: *const Self) ?usize { - var offset: usize = 0; - const mask = for (self.masks) |mask| { - if (mask != 0) break mask; - offset += @bitSizeOf(MaskInt); - } else return null; - return offset + @ctz(mask); - } - - /// Finds the index of the first set bit, and unsets it. - /// If no bits are set, returns null. - pub fn toggleFirstSet(self: *Self) ?usize { - var offset: usize = 0; - const mask = for (&self.masks) |*mask| { - if (mask.* != 0) break mask; - offset += @bitSizeOf(MaskInt); - } else return null; - const index = @ctz(mask.*); - mask.* &= (mask.* - 1); - return offset + index; - } - - /// Returns true iff every corresponding bit in both - /// bit sets are the same. - pub fn eql(self: *const Self, other: *const Self) bool { - var i: usize = 0; - return while (i < num_masks) : (i += 1) { - if (self.masks[i] != other.masks[i]) { - break false; - } - } else true; - } - - /// Returns true iff the first bit set is the subset - /// of the second one. - pub fn subsetOf(self: *const Self, other: *const Self) bool { - return self.intersectWith(other).eql(self); - } - - /// Returns true iff the first bit set is the superset - /// of the second one. - pub fn supersetOf(self: *const Self, other: *const Self) bool { - return other.subsetOf(self); - } - - /// Returns the complement bit sets. Bits in the result - /// are set if the corresponding bits were not set. - pub fn complement(self: *const Self) Self { - var result = self.*; - result.toggleAll(); - return result; - } - - /// Returns the union of two bit sets. Bits in the - /// result are set if the corresponding bits were set - /// in either input. - pub fn unionWith(self: *const Self, other: *const Self) Self { - var result = self.*; - result.setUnion(other); - return result; - } - - /// Returns the intersection of two bit sets. Bits in - /// the result are set if the corresponding bits were - /// set in both inputs. - pub fn intersectWith(self: *const Self, other: *const Self) Self { - var result = self.*; - result.setIntersection(other); - return result; - } - - pub fn hasIntersection(self: *const Self, other: *const Self) bool { - for (self.masks, other.masks) |a, b| { - if (a & b != 0) return true; - } - - return false; - } - - /// Returns the xor of two bit sets. Bits in the - /// result are set if the corresponding bits were - /// not the same in both inputs. - pub fn xorWith(self: *const Self, other: *const Self) Self { - var result = self.*; - result.toggleSet(other); - return result; - } - - /// Returns the difference of two bit sets. Bits in - /// the result are set if set in the first but not - /// set in the second set. - pub fn differenceWith(self: *const Self, other: *const Self) Self { - var result = self.*; - result.setIntersection(&other.complement()); - return result; - } - - /// Iterates through the items in the set, according to the options. - /// The default options (.{}) will iterate indices of set bits in - /// ascending order. Modifications to the underlying bit set may - /// or may not be observed by the iterator. - pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) { - return Iterator(options).init(&self.masks, last_item_mask); - } - - pub fn Iterator(comptime options: IteratorOptions) type { - return BitSetIterator(MaskInt, options); - } - - fn maskBit(index: usize) callconv(bun.callconv_inline) MaskInt { - return @as(MaskInt, 1) << @as(ShiftInt, @truncate(index)); - } - fn maskIndex(index: usize) callconv(bun.callconv_inline) usize { - return index >> @bitSizeOf(ShiftInt); - } - fn boolMaskBit(index: usize, value: bool) callconv(bun.callconv_inline) MaskInt { - return @as(MaskInt, @intFromBool(value)) << @as(ShiftInt, @intCast(index)); - } - }; -} - -/// A bit set with runtime-known size, backed by an allocated slice -/// of usize. The allocator must be tracked externally by the user. -pub const DynamicBitSetUnmanaged = struct { - const Self = @This(); - - /// The integer type used to represent a mask in this bit set - pub const MaskInt = usize; - - /// The integer type used to shift a mask in this bit set - pub const ShiftInt = std.math.Log2Int(MaskInt); - - /// The number of valid items in this bit set - bit_length: usize = 0, - - /// The bit masks, ordered with lower indices first. - /// Padding bits at the end must be zeroed. - masks: [*]MaskInt = empty_masks_ptr, - // This pointer is one usize after the actual allocation. - // That slot holds the size of the true allocation, which - // is needed by Zig's allocator interface in case a shrink - // fails. - - // Don't modify this value. Ideally it would go in const data so - // modifications would cause a bus error, but the only way - // to discard a const qualifier is through ptrToInt, which - // cannot currently round trip at comptime. - var empty_masks_data = [_]MaskInt{ 0, undefined }; - const empty_masks_ptr = empty_masks_data[1..2]; - - pub const empty: Self = .{ - .bit_length = 0, - .masks = empty_masks_ptr, - }; - - /// Do not resize the bitsets! - /// - /// Single buffer for multiple bitsets of equal length. Does not - /// implement all methods of DynamicBitSetUnmanaged and should - /// be used carefully. - pub const List = struct { - buf: []MaskInt, - n: usize, - bit_length: usize, - - pub fn initEmpty(allocator: Allocator, n: usize, bit_length: usize) !List { - const masks = numMasks(bit_length); - const single_bitset_buf_size = masks + 1; - - const buf = try allocator.alloc(MaskInt, single_bitset_buf_size * n); - - const fill_value = std.math.boolMask(MaskInt, false); - @memset(buf, fill_value); - - for (0..n) |i| { - buf[i * single_bitset_buf_size] = single_bitset_buf_size; - } - - return List{ - .buf = buf, - .n = n, - .bit_length = bit_length, - }; - } - - pub fn deinit(this: List, allocator: Allocator) void { - allocator.free(this.buf); - } - - pub fn at(this: List, i: usize) Self { - const num_masks = numMasks(this.bit_length); - const single_bitset_buf_size = num_masks + 1; - - const offset = (single_bitset_buf_size * i); - - return Self{ - .bit_length = this.bit_length, - .masks = this.buf[offset..].ptr + 1, - }; - } - - pub fn set(this: List, i: usize, j: usize) void { - var bitset = this.at(i); - bitset.set(j); - } - - pub fn setUnion(this: List, i: usize, other: Self) void { - var bitset = this.at(i); - bitset.setUnion(other); - } - }; - - /// Creates a bit set with no elements present. - /// If bit_length is not zero, deinit must eventually be called. - pub fn initEmpty(allocator: Allocator, bit_length: usize) !Self { - var self = Self{}; - try self.resize(allocator, bit_length, false); - return self; - } - - /// Creates a bit set with all elements present. - /// If bit_length is not zero, deinit must eventually be called. - pub fn initFull(allocator: Allocator, bit_length: usize) !Self { - var self = Self{}; - try self.resize(allocator, bit_length, true); - return self; - } - - /// Resizes to a new bit_length. If the new length is larger - /// than the old length, fills any added bits with `fill`. - /// If new_len is not zero, deinit must eventually be called. - pub fn resize(self: *@This(), allocator: Allocator, new_len: usize, fill: bool) !void { - const old_len = self.bit_length; - - const old_masks = numMasks(old_len); - const new_masks = numMasks(new_len); - - const old_allocation = (self.masks - 1)[0..(self.masks - 1)[0]]; - - if (new_masks == 0) { - if (comptime Environment.allow_assert) bun.assert(new_len == 0); - allocator.free(old_allocation); - self.masks = empty_masks_ptr; - self.bit_length = 0; - return; - } - - if (old_allocation.len != new_masks + 1) realloc: { - // If realloc fails, it may mean one of two things. - // If we are growing, it means we are out of memory. - // If we are shrinking, it means the allocator doesn't - // want to move the allocation. This means we need to - // hold on to the extra 8 bytes required to be able to free - // this allocation properly. - const new_allocation = allocator.realloc(old_allocation, new_masks + 1) catch |err| { - if (new_masks + 1 > old_allocation.len) return err; - break :realloc; - }; - - new_allocation[0] = new_allocation.len; - self.masks = new_allocation.ptr + 1; - } - - // If we increased in size, we need to set any new bits - // to the fill value. - if (new_len > old_len) { - // set the padding bits in the old last item to 1 - if (fill and old_masks > 0) { - const old_padding_bits = old_masks * @bitSizeOf(MaskInt) - old_len; - const old_mask = (~@as(MaskInt, 0)) >> @as(ShiftInt, @intCast(old_padding_bits)); - self.masks[old_masks - 1] |= ~old_mask; - } - - // fill in any new masks - if (new_masks > old_masks) { - const fill_value = std.math.boolMask(MaskInt, fill); - @memset(self.masks[old_masks..new_masks], fill_value); - } - } - - // Zero out the padding bits - if (new_len > 0) { - const padding_bits = new_masks * @bitSizeOf(MaskInt) - new_len; - const last_item_mask = (~@as(MaskInt, 0)) >> @as(ShiftInt, @intCast(padding_bits)); - self.masks[new_masks - 1] &= last_item_mask; - } - - // And finally, save the new length. - self.bit_length = new_len; - } - - /// deinitializes the array and releases its memory. - /// The passed allocator must be the same one used for - /// init* or resize in the past. - pub fn deinit(self: *Self, allocator: Allocator) void { - self.resize(allocator, 0, false) catch unreachable; - } - - /// Creates a duplicate of this bit set, using the new allocator. - pub fn clone(self: *const Self, new_allocator: Allocator) !Self { - const num_masks = numMasks(self.bit_length); - var copy = Self{}; - try copy.resize(new_allocator, self.bit_length, false); - bun.copy(MaskInt, copy.masks[0..num_masks], self.masks[0..num_masks]); - return copy; - } - - /// Returns the number of bits in this bit set - pub fn capacity(self: Self) callconv(bun.callconv_inline) usize { - return self.bit_length; - } - - /// Returns true if the bit at the specified index - /// is present in the set, false otherwise. - pub fn isSet(self: Self, index: usize) bool { - if (comptime Environment.allow_assert) bun.assert(index < self.bit_length); - return (self.masks[maskIndex(index)] & maskBit(index)) != 0; - } - - pub fn isSetAllowOutOfBound(self: Self, index: usize, out_of_bounds: bool) bool { - if (index >= self.bit_length) return out_of_bounds; - return (self.masks[maskIndex(index)] & maskBit(index)) != 0; - } - - pub fn bytes(self: Self) []const u8 { - return std.mem.sliceAsBytes(self.masks[0..numMasks(self.bit_length)]); - } - - /// Returns the total number of set bits in this bit set. - pub fn count(self: Self) usize { - const num_masks = (self.bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt); - var total: usize = 0; - for (self.masks[0..num_masks]) |mask| { - // Note: This is where we depend on padding bits being zero - total += @popCount(mask); - } - return total; - } - - pub fn hasIntersection(self: Self, other: Self) bool { - const num_masks = (self.bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt); - for (self.masks[0..num_masks], other.masks[0..num_masks]) |mask, other_mask| { - if ((mask & other_mask) != 0) return true; - } - - return false; - } - - /// Changes the value of the specified bit of the bit - /// set to match the passed boolean. - pub fn setValue(self: *Self, index: usize, value: bool) void { - if (comptime Environment.allow_assert) bun.assert(index < self.bit_length); - const bit = maskBit(index); - const mask_index = maskIndex(index); - const new_bit = bit & std.math.boolMask(MaskInt, value); - self.masks[mask_index] = (self.masks[mask_index] & ~bit) | new_bit; - } - - /// Adds a specific bit to the bit set - pub fn set(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < self.bit_length); - self.masks[maskIndex(index)] |= maskBit(index); - } - - /// Changes the value of all bits in the specified range to - /// match the passed boolean. - pub fn setRangeValue(self: *Self, range: Range, value: bool) void { - if (comptime Environment.allow_assert) bun.assert(range.end <= self.bit_length); - if (comptime Environment.allow_assert) bun.assert(range.start <= range.end); - if (range.start == range.end) return; - - const start_mask_index = maskIndex(range.start); - const start_bit = @as(ShiftInt, @truncate(range.start)); - - const end_mask_index = maskIndex(range.end); - const end_bit = @as(ShiftInt, @truncate(range.end)); - - if (start_mask_index == end_mask_index) { - var mask1 = std.math.boolMask(MaskInt, true) << start_bit; - var mask2 = std.math.boolMask(MaskInt, true) >> (@bitSizeOf(MaskInt) - 1) - (end_bit - 1); - self.masks[start_mask_index] &= ~(mask1 & mask2); - - mask1 = std.math.boolMask(MaskInt, value) << start_bit; - mask2 = std.math.boolMask(MaskInt, value) >> (@bitSizeOf(MaskInt) - 1) - (end_bit - 1); - self.masks[start_mask_index] |= mask1 & mask2; - } else { - var bulk_mask_index: usize = 0; - if (start_bit > 0) { - self.masks[start_mask_index] = - (self.masks[start_mask_index] & ~(std.math.boolMask(MaskInt, true) << start_bit)) | - (std.math.boolMask(MaskInt, value) << start_bit); - bulk_mask_index = start_mask_index + 1; - } else { - bulk_mask_index = start_mask_index; - } - - for (self.masks[bulk_mask_index..end_mask_index]) |*mask| { - mask.* = std.math.boolMask(MaskInt, value); - } - - if (end_bit > 0) { - self.masks[end_mask_index] = - (self.masks[end_mask_index] & (std.math.boolMask(MaskInt, true) << end_bit)) | - (std.math.boolMask(MaskInt, value) >> ((@bitSizeOf(MaskInt) - 1) - (end_bit - 1))); - } - } - } - - /// Removes a specific bit from the bit set - pub fn unset(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < self.bit_length); - self.masks[maskIndex(index)] &= ~maskBit(index); - } - - /// Flips a specific bit in the bit set - pub fn toggle(self: *Self, index: usize) void { - if (comptime Environment.allow_assert) bun.assert(index < self.bit_length); - self.masks[maskIndex(index)] ^= maskBit(index); - } - - /// Flips all bits in this bit set which are present - /// in the toggles bit set. Both sets must have the - /// same bit_length. - pub fn toggleSet(self: *Self, toggles: Self) void { - if (comptime Environment.allow_assert) bun.assert(toggles.bit_length == self.bit_length); - const bit_length = self.bit_length; - if (bit_length == 0) return; - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks], toggles.masks[0..num_masks]) |*mask, other_mask| { - mask.* ^= other_mask; - } - - const padding_bits = num_masks * @bitSizeOf(MaskInt) - bit_length; - const last_item_mask = (~@as(MaskInt, 0)) >> @as(ShiftInt, @intCast(padding_bits)); - self.masks[num_masks - 1] &= last_item_mask; - } - - pub fn setAll(self: *Self, value: bool) void { - const bit_length = self.bit_length; - if (bit_length == 0) return; - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks]) |*mask| { - mask.* = std.math.boolMask(MaskInt, value); - } - - const padding_bits = num_masks * @bitSizeOf(MaskInt) - bit_length; - const last_item_mask = (~@as(MaskInt, 0)) >> @as(ShiftInt, @intCast(padding_bits)); - self.masks[num_masks - 1] &= last_item_mask; - } - - /// Flips every bit in the bit set. - pub fn toggleAll(self: *Self) void { - const bit_length = self.bit_length; - // avoid underflow if bit_length is zero - if (bit_length == 0) return; - - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks]) |*mask| { - mask.* = ~mask.*; - } - - const padding_bits = num_masks * @bitSizeOf(MaskInt) - bit_length; - const last_item_mask = (~@as(MaskInt, 0)) >> @as(ShiftInt, @intCast(padding_bits)); - self.masks[num_masks - 1] &= last_item_mask; - } - - pub fn copyInto(self: *Self, other: Self) void { - const bit_length = self.bit_length; - // avoid underflow if bit_length is zero - if (bit_length == 0) return; - - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks], other.masks) |*mask, other_mask| { - mask.* = other_mask; - } - - const padding_bits = num_masks * @bitSizeOf(MaskInt) - bit_length; - const last_item_mask = (~@as(MaskInt, 0)) >> @as(ShiftInt, @intCast(padding_bits)); - self.masks[num_masks - 1] &= last_item_mask; - } - - /// Performs a union of two bit sets, and stores the - /// result in the first one. Bits in the result are - /// set if the corresponding bits were set in either input. - /// The two sets must both be the same bit_length. - pub fn setUnion(self: *Self, other: Self) void { - if (comptime Environment.allow_assert) bun.assert(other.bit_length == self.bit_length); - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks], other.masks) |*mask, other_mask| { - mask.* |= other_mask; - } - } - - /// Performs an intersection of two bit sets, and stores - /// the result in the first one. Bits in the result are - /// set if the corresponding bits were set in both inputs. - /// The two sets must both be the same bit_length. - pub fn setIntersection(self: *Self, other: Self) void { - if (comptime Environment.allow_assert) bun.assert(other.bit_length == self.bit_length); - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks], other.masks) |*mask, other_mask| { - mask.* &= other_mask; - } - } - - pub fn setExcludeTwo(self: *Self, other: Self, third: Self) void { - if (comptime Environment.allow_assert) bun.assert(other.bit_length == self.bit_length); - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks], other.masks[0..num_masks], third.masks[0..num_masks]) |*mask, other_mask, third_mask| { - mask.* &= ~other_mask; - mask.* &= ~third_mask; - } - } - - pub fn setExclude(self: *Self, other: Self) void { - if (comptime Environment.allow_assert) bun.assert(other.bit_length == self.bit_length); - const num_masks = numMasks(self.bit_length); - for (self.masks[0..num_masks], other.masks) |*mask, other_mask| { - mask.* &= ~other_mask; - } - } - - /// Finds the index of the first set bit. - /// If no bits are set, returns null. - pub fn findFirstSet(self: Self) ?usize { - var offset: usize = 0; - var mask = self.masks; - while (offset < self.bit_length) { - if (mask[0] != 0) break; - mask += 1; - offset += @bitSizeOf(MaskInt); - } else return null; - return offset + @ctz(mask[0]); - } - - /// Finds the index of the first set bit, and unsets it. - /// If no bits are set, returns null. - pub fn toggleFirstSet(self: *Self) ?usize { - var offset: usize = 0; - var mask = self.masks; - while (offset < self.bit_length) { - if (mask[0] != 0) break; - mask += 1; - offset += @bitSizeOf(MaskInt); - } else return null; - const index = @ctz(mask[0]); - mask[0] &= (mask[0] - 1); - return offset + index; - } - - /// Returns true iff every corresponding bit in both - /// bit sets are the same. - pub fn eql(self: Self, other: Self) bool { - if (self.bit_length != other.bit_length) { - return false; - } - const num_masks = numMasks(self.bit_length); - var i: usize = 0; - return while (i < num_masks) : (i += 1) { - if (self.masks[i] != other.masks[i]) { - break false; - } - } else true; - } - - /// Returns true iff the first bit set is the subset - /// of the second one. - pub fn subsetOf(self: Self, other: Self) bool { - if (self.bit_length != other.bit_length) { - return false; - } - const num_masks = numMasks(self.bit_length); - var i: usize = 0; - return while (i < num_masks) : (i += 1) { - if (self.masks[i] & other.masks[i] != self.masks[i]) { - break false; - } - } else true; - } - - /// Returns true iff the first bit set is the superset - /// of the second one. - pub fn supersetOf(self: Self, other: Self) bool { - if (self.bit_length != other.bit_length) { - return false; - } - const num_masks = numMasks(self.bit_length); - var i: usize = 0; - return while (i < num_masks) : (i += 1) { - if (self.masks[i] & other.masks[i] != other.masks[i]) { - break false; - } - } else true; - } - - /// Iterates through the items in the set, according to the options. - /// The default options (.{}) will iterate indices of set bits in - /// ascending order. Modifications to the underlying bit set may - /// or may not be observed by the iterator. Resizing the underlying - /// bit set invalidates the iterator. - pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) { - const num_masks = numMasks(self.bit_length); - const padding_bits = num_masks * @bitSizeOf(MaskInt) - self.bit_length; - const last_item_mask = (~@as(MaskInt, 0)) >> @as(ShiftInt, @intCast(padding_bits)); - return Iterator(options).init(self.masks[0..num_masks], last_item_mask); - } - - pub fn Iterator(comptime options: IteratorOptions) type { - return BitSetIterator(MaskInt, options); - } - - fn maskBit(index: usize) MaskInt { - return @as(MaskInt, 1) << @as(ShiftInt, @truncate(index)); - } - fn maskIndex(index: usize) usize { - return index >> @bitSizeOf(ShiftInt); - } - fn boolMaskBit(index: usize, value: bool) MaskInt { - return @as(MaskInt, @intFromBool(value)) << @as(ShiftInt, @intCast(index)); - } - fn numMasks(bit_length: usize) usize { - return (bit_length + (@bitSizeOf(MaskInt) - 1)) / @bitSizeOf(MaskInt); - } -}; - -pub const AutoBitSet = union(enum) { - pub const Static = ArrayBitSet(usize, (@bitSizeOf(DynamicBitSetUnmanaged) - 1)); - - static: Static, - dynamic: DynamicBitSetUnmanaged, - - pub fn needsDynamic(bit_length: usize) callconv(bun.callconv_inline) bool { - return bit_length > Static.bit_length; - } - - pub fn initEmpty(allocator: Allocator, bit_length: usize) !AutoBitSet { - if (bit_length <= Static.bit_length) { - return AutoBitSet{ .static = Static.initEmpty() }; - } else { - return AutoBitSet{ .dynamic = try DynamicBitSetUnmanaged.initEmpty(allocator, bit_length) }; - } - } - - pub fn isSet(this: *const AutoBitSet, index: usize) bool { - return switch (std.meta.activeTag(this.*)) { - .static => this.static.isSet(index), - .dynamic => this.dynamic.isSet(index), - }; - } - - /// Are any of the bits in `this` also set in `other`? - pub fn hasIntersection(this: *const AutoBitSet, other: *const AutoBitSet) bool { - if (std.meta.activeTag(this.*) != std.meta.activeTag(other.*)) { - return false; - } - - return switch (std.meta.activeTag(this.*)) { - .static => this.static.hasIntersection(&other.static), - .dynamic => this.dynamic.hasIntersection(other.dynamic), - }; - } - - pub fn clone(this: *const AutoBitSet, allocator: std.mem.Allocator) !AutoBitSet { - return switch (std.meta.activeTag(this.*)) { - .static => AutoBitSet{ .static = this.static }, - .dynamic => AutoBitSet{ .dynamic = try this.dynamic.clone(allocator) }, - }; - } - - pub fn set(this: *AutoBitSet, index: usize) void { - switch (std.meta.activeTag(this.*)) { - .static => this.static.set(index), - .dynamic => this.dynamic.set(index), - } - } - - pub fn unset(this: *AutoBitSet, index: usize) void { - switch (std.meta.activeTag(this.*)) { - .static => this.static.unset(index), - .dynamic => this.dynamic.unset(index), - } - } - - pub fn rawBytes(this: *const AutoBitSet) []const u8 { - return switch (std.meta.activeTag(this.*)) { - .static => std.mem.asBytes(&this.static.masks), - .dynamic => this.dynamic.bytes(), - }; - } - - pub fn bytes(this: *const AutoBitSet, _: usize) []const u8 { - return this.rawBytes(); - } - - pub fn eql(this: *const AutoBitSet, b: *const AutoBitSet) bool { - return bun.strings.eqlLong(this.rawBytes(), b.rawBytes(), true); - } - - pub fn hash(this: *const AutoBitSet) u64 { - return bun.hash(this.rawBytes()); - } - - pub fn forEach(this: *const AutoBitSet, comptime Ctx: type, ctx: *Ctx, comptime Function: fn (*Ctx, usize) void) void { - return switch (std.meta.activeTag(this.*)) { - .static => { - var iter = this.static.iterator(.{}); - while (iter.next()) |index| { - Function(ctx, index); - } - }, - .dynamic => { - var iter = this.dynamic.iterator(.{}); - while (iter.next()) |index| { - Function(ctx, index); - } - }, - }; - } - - pub fn setAll(this: *AutoBitSet, value: bool) void { - switch (this.*) { - inline else => |*bitset| bitset.setAll(value), - } - } - - pub fn count(this: *const AutoBitSet) usize { - return switch (this.*) { - inline else => |*bitset| bitset.count(), - }; - } - - pub fn findFirstSet(this: *const AutoBitSet) ?usize { - return switch (this.*) { - inline else => |*bitset| bitset.findFirstSet(), - }; - } - - pub fn iterator(this: *const AutoBitSet, comptime options: IteratorOptions) Iterator(options) { - return switch (this.*) { - .static => |*s| .{ .static = s.iterator(options) }, - .dynamic => |*d| .{ .dynamic = d.iterator(options) }, - }; - } - - pub fn Iterator(comptime options: IteratorOptions) type { - return union(enum) { - static: Static.Iterator(options), - dynamic: DynamicBitSetUnmanaged.Iterator(options), - - pub fn next(self: *@This()) ?usize { - return switch (self.*) { - inline else => |*it| it.next(), - }; - } - }; - } - - pub fn deinit(this: *AutoBitSet, allocator: std.mem.Allocator) void { - switch (std.meta.activeTag(this.*)) { - .static => {}, - .dynamic => { - this.dynamic.deinit(allocator); - }, - } - } -}; - -/// A bit set with runtime-known size, backed by an allocated slice -/// of usize. Thin wrapper around DynamicBitSetUnmanaged which keeps -/// track of the allocator instance. -pub const DynamicBitSet = struct { - const Self = @This(); - - /// The integer type used to represent a mask in this bit set - pub const MaskInt = usize; - - /// The integer type used to shift a mask in this bit set - pub const ShiftInt = std.math.Log2Int(MaskInt); - - /// The allocator used by this bit set - allocator: Allocator, - - /// The number of valid items in this bit set - unmanaged: DynamicBitSetUnmanaged = .{}, - - /// Creates a bit set with no elements present. - pub fn initEmpty(allocator: Allocator, bit_length: usize) !Self { - return Self{ - .unmanaged = try DynamicBitSetUnmanaged.initEmpty(allocator, bit_length), - .allocator = allocator, - }; - } - - /// Creates a bit set with all elements present. - pub fn initFull(allocator: Allocator, bit_length: usize) !Self { - return Self{ - .unmanaged = try DynamicBitSetUnmanaged.initFull(allocator, bit_length), - .allocator = allocator, - }; - } - - /// Resizes to a new length. If the new length is larger - /// than the old length, fills any added bits with `fill`. - pub fn resize(self: *@This(), new_len: usize, fill: bool) !void { - try self.unmanaged.resize(self.allocator, new_len, fill); - } - - /// deinitializes the array and releases its memory. - /// The passed allocator must be the same one used for - /// init* or resize in the past. - pub fn deinit(self: *Self) void { - self.unmanaged.deinit(self.allocator); - } - - /// Creates a duplicate of this bit set, using the new allocator. - pub fn clone(self: *const Self, new_allocator: Allocator) !Self { - return Self{ - .unmanaged = try self.unmanaged.clone(new_allocator), - .allocator = new_allocator, - }; - } - - /// Returns the number of bits in this bit set - pub fn capacity(self: Self) callconv(bun.callconv_inline) usize { - return self.unmanaged.capacity(); - } - - /// Returns true if the bit at the specified index - /// is present in the set, false otherwise. - pub fn isSet(self: Self, index: usize) bool { - return self.unmanaged.isSet(index); - } - - /// Returns the total number of set bits in this bit set. - pub fn count(self: Self) usize { - return self.unmanaged.count(); - } - - /// Changes the value of the specified bit of the bit - /// set to match the passed boolean. - pub fn setValue(self: *Self, index: usize, value: bool) void { - self.unmanaged.setValue(index, value); - } - - /// Adds a specific bit to the bit set - pub fn set(self: *Self, index: usize) void { - self.unmanaged.set(index); - } - - /// Changes the value of all bits in the specified range to - /// match the passed boolean. - pub fn setRangeValue(self: *Self, range: Range, value: bool) void { - self.unmanaged.setRangeValue(range, value); - } - - /// Removes a specific bit from the bit set - pub fn unset(self: *Self, index: usize) void { - self.unmanaged.unset(index); - } - - /// Flips a specific bit in the bit set - pub fn toggle(self: *Self, index: usize) void { - self.unmanaged.toggle(index); - } - - /// Flips all bits in this bit set which are present - /// in the toggles bit set. Both sets must have the - /// same bit_length. - pub fn toggleSet(self: *Self, toggles: Self) void { - self.unmanaged.toggleSet(toggles.unmanaged); - } - - /// Flips every bit in the bit set. - pub fn toggleAll(self: *Self) void { - self.unmanaged.toggleAll(); - } - - /// Performs a union of two bit sets, and stores the - /// result in the first one. Bits in the result are - /// set if the corresponding bits were set in either input. - /// The two sets must both be the same bit_length. - pub fn setUnion(self: *Self, other: Self) void { - self.unmanaged.setUnion(other.unmanaged); - } - - /// Performs an intersection of two bit sets, and stores - /// the result in the first one. Bits in the result are - /// set if the corresponding bits were set in both inputs. - /// The two sets must both be the same bit_length. - pub fn setIntersection(self: *Self, other: Self) void { - self.unmanaged.setIntersection(other.unmanaged); - } - - /// Finds the index of the first set bit. - /// If no bits are set, returns null. - pub fn findFirstSet(self: Self) ?usize { - return self.unmanaged.findFirstSet(); - } - - /// Finds the index of the first set bit, and unsets it. - /// If no bits are set, returns null. - pub fn toggleFirstSet(self: *Self) ?usize { - return self.unmanaged.toggleFirstSet(); - } - - /// Returns true iff every corresponding bit in both - /// bit sets are the same. - pub fn eql(self: Self, other: Self) bool { - return self.unmanaged.eql(other.unmanaged); - } - - /// Iterates through the items in the set, according to the options. - /// The default options (.{}) will iterate indices of set bits in - /// ascending order. Modifications to the underlying bit set may - /// or may not be observed by the iterator. Resizing the underlying - /// bit set invalidates the iterator. - pub fn iterator(self: *const Self, comptime options: IteratorOptions) Iterator(options) { - return self.unmanaged.iterator(options); - } - - pub const Iterator = DynamicBitSetUnmanaged.Iterator; -}; - -/// Options for configuring an iterator over a bit set -pub const IteratorOptions = struct { - /// determines which bits should be visited - kind: Type = .set, - /// determines the order in which bit indices should be visited - direction: Direction = .forward, - - pub const Type = enum { - /// visit indexes of set bits - set, - /// visit indexes of unset bits - unset, - }; - - pub const Direction = enum { - /// visit indices in ascending order - forward, - /// visit indices in descending order. - /// Note that this may be slightly more expensive than forward iteration. - reverse, - }; -}; - -// The iterator is reusable between several bit set types -pub fn BitSetIterator(comptime MaskInt: type, comptime options: IteratorOptions) type { - const ShiftInt = std.math.Log2Int(MaskInt); - const kind = options.kind; - const direction = options.direction; - return struct { - const Self = @This(); - - // all bits which have not yet been iterated over - bits_remain: MaskInt, - // all words which have not yet been iterated over - words_remain: []const MaskInt, - // the offset of the current word - bit_offset: usize, - // the mask of the last word - last_word_mask: MaskInt, - - fn init(masks: []const MaskInt, last_word_mask: MaskInt) Self { - if (masks.len == 0) { - return Self{ - .bits_remain = 0, - .words_remain = &[_]MaskInt{}, - .last_word_mask = last_word_mask, - .bit_offset = 0, - }; - } else { - var result = Self{ - .bits_remain = 0, - .words_remain = masks, - .last_word_mask = last_word_mask, - .bit_offset = if (direction == .forward) 0 else (masks.len - 1) * @bitSizeOf(MaskInt), - }; - result.nextWord(true); - return result; - } - } - - /// Returns the index of the next unvisited set bit - /// in the bit set, in ascending order. - pub fn next(self: *Self) ?usize { - while (self.bits_remain == 0) { - if (self.words_remain.len == 0) return null; - self.nextWord(false); - switch (direction) { - .forward => self.bit_offset += @bitSizeOf(MaskInt), - .reverse => self.bit_offset -= @bitSizeOf(MaskInt), - } - } - - switch (direction) { - .forward => { - const next_index = @ctz(self.bits_remain) + self.bit_offset; - self.bits_remain &= self.bits_remain - 1; - return next_index; - }, - .reverse => { - const leading_zeroes = @clz(self.bits_remain); - const top_bit = (@bitSizeOf(MaskInt) - 1) - leading_zeroes; - const no_top_bit_mask = (@as(MaskInt, 1) << @as(ShiftInt, @intCast(top_bit))) - 1; - self.bits_remain &= no_top_bit_mask; - return top_bit + self.bit_offset; - }, - } - } - - // Load the next word. Don't call this if there - // isn't a next word. If the next word is the - // last word, mask off the padding bits so we - // don't visit them. - fn nextWord(self: *Self, comptime is_first_word: bool) callconv(bun.callconv_inline) void { - var word = switch (direction) { - .forward => self.words_remain[0], - .reverse => self.words_remain[self.words_remain.len - 1], - }; - switch (kind) { - .set => {}, - .unset => { - word = ~word; - if ((direction == .reverse and is_first_word) or - (direction == .forward and self.words_remain.len == 1)) - { - word &= self.last_word_mask; - } - }, - } - switch (direction) { - .forward => self.words_remain = self.words_remain[1..], - .reverse => self.words_remain.len -= 1, - } - self.bits_remain = word; - } - }; -} - -/// A range of indices within a bitset. -pub const Range = struct { - /// The index of the first bit of interest. - start: usize, - /// The index immediately after the last bit of interest. - end: usize, -}; - -// ---------------- Tests ----------------- - -fn testEql(empty: anytype, full: anytype, len: usize) !void { - try testing.expect(empty.eql(empty)); - try testing.expect(full.eql(full)); - switch (len) { - 0 => { - try testing.expect(empty.eql(full)); - try testing.expect(full.eql(empty)); - }, - else => { - try testing.expect(!empty.eql(full)); - try testing.expect(!full.eql(empty)); - }, - } -} - -fn testSubsetOf(empty: anytype, full: anytype, even: anytype, odd: anytype, len: usize) !void { - try testing.expect(empty.subsetOf(empty)); - try testing.expect(empty.subsetOf(full)); - try testing.expect(full.subsetOf(full)); - switch (len) { - 0 => { - try testing.expect(even.subsetOf(odd)); - try testing.expect(odd.subsetOf(even)); - }, - 1 => { - try testing.expect(!even.subsetOf(odd)); - try testing.expect(odd.subsetOf(even)); - }, - else => { - try testing.expect(!even.subsetOf(odd)); - try testing.expect(!odd.subsetOf(even)); - }, - } -} - -fn testSupersetOf(empty: anytype, full: anytype, even: anytype, odd: anytype, len: usize) !void { - try testing.expect(full.supersetOf(full)); - try testing.expect(full.supersetOf(empty)); - try testing.expect(empty.supersetOf(empty)); - switch (len) { - 0 => { - try testing.expect(even.supersetOf(odd)); - try testing.expect(odd.supersetOf(even)); - }, - 1 => { - try testing.expect(even.supersetOf(odd)); - try testing.expect(!odd.supersetOf(even)); - }, - else => { - try testing.expect(!even.supersetOf(odd)); - try testing.expect(!odd.supersetOf(even)); - }, - } -} - -fn testBitSet(a: anytype, b: anytype, len: usize) !void { - try testing.expectEqual(len, a.capacity()); - try testing.expectEqual(len, b.capacity()); - const needs_ptr = @hasField(std.meta.Child(@TypeOf(a)), "masks") and @typeInfo(@TypeOf(@field(a, "masks"))) != .pointer; - - { - for (0..len) |i| { - a.setValue(i, i & 1 == 0); - b.setValue(i, i & 2 == 0); - } - } - - try testing.expectEqual((len + 1) / 2, a.count()); - try testing.expectEqual((len + 3) / 4 + (len + 2) / 4, b.count()); - - { - var iter = a.iterator(.{}); - var i: usize = 0; - while (i < len) : (i += 2) { - try testing.expectEqual(@as(?usize, i), iter.next()); - } - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - } - a.toggleAll(); - { - var iter = a.iterator(.{}); - var i: usize = 1; - while (i < len) : (i += 2) { - try testing.expectEqual(@as(?usize, i), iter.next()); - } - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - } - - { - var iter = b.iterator(.{ .kind = .unset }); - var i: usize = 2; - while (i < len) : (i += 4) { - try testing.expectEqual(@as(?usize, i), iter.next()); - if (i + 1 < len) { - try testing.expectEqual(@as(?usize, i + 1), iter.next()); - } - } - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - } - - { - for (0..len) |i| { - try testing.expectEqual(i & 1 != 0, a.isSet(i)); - try testing.expectEqual(i & 2 == 0, b.isSet(i)); - } - } - - if (comptime needs_ptr) { - a.setUnion(b); - } else { - a.setUnion(b.*); - } - - { - var i: usize = 0; - while (i < len) : (i += 1) { - try testing.expectEqual(i & 1 != 0 or i & 2 == 0, a.isSet(i)); - try testing.expectEqual(i & 2 == 0, b.isSet(i)); - } - - i = len; - var set = a.iterator(.{ .direction = .reverse }); - var unset = a.iterator(.{ .kind = .unset, .direction = .reverse }); - while (i > 0) { - i -= 1; - if (i & 1 != 0 or i & 2 == 0) { - try testing.expectEqual(@as(?usize, i), set.next()); - } else { - try testing.expectEqual(@as(?usize, i), unset.next()); - } - } - try testing.expectEqual(@as(?usize, null), set.next()); - try testing.expectEqual(@as(?usize, null), set.next()); - try testing.expectEqual(@as(?usize, null), set.next()); - try testing.expectEqual(@as(?usize, null), unset.next()); - try testing.expectEqual(@as(?usize, null), unset.next()); - try testing.expectEqual(@as(?usize, null), unset.next()); - } - - if (comptime needs_ptr) { - a.toggleSet(b); - } else { - a.toggleSet(b.*); - } - { - try testing.expectEqual(len / 4, a.count()); - - for (0..len) |i| { - try testing.expectEqual(i & 1 != 0 and i & 2 != 0, a.isSet(i)); - try testing.expectEqual(i & 2 == 0, b.isSet(i)); - if (i & 1 == 0) { - a.set(i); - } else { - a.unset(i); - } - } - } - - if (comptime needs_ptr) { - a.setIntersection(b); - } else { - a.setIntersection(b.*); - } - { - try testing.expectEqual((len + 3) / 4, a.count()); - - for (0..len) |i| { - try testing.expectEqual(i & 1 == 0 and i & 2 == 0, a.isSet(i)); - try testing.expectEqual(i & 2 == 0, b.isSet(i)); - } - } - - if (comptime needs_ptr) { - a.toggleSet(a); - } else { - a.toggleSet(a.*); - } - { - var iter = a.iterator(.{}); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(usize, 0), a.count()); - } - { - var iter = a.iterator(.{ .direction = .reverse }); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(?usize, null), iter.next()); - try testing.expectEqual(@as(usize, 0), a.count()); - } - - const test_bits = [_]usize{ - 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 22, 31, 32, 63, 64, - 66, 95, 127, 160, 192, 1000, - }; - for (test_bits) |i| { - if (i < a.capacity()) { - a.set(i); - } - } - - for (test_bits) |i| { - if (i < a.capacity()) { - try testing.expectEqual(@as(?usize, i), a.findFirstSet()); - try testing.expectEqual(@as(?usize, i), a.toggleFirstSet()); - } - } - try testing.expectEqual(@as(?usize, null), a.findFirstSet()); - try testing.expectEqual(@as(?usize, null), a.toggleFirstSet()); - try testing.expectEqual(@as(?usize, null), a.findFirstSet()); - try testing.expectEqual(@as(?usize, null), a.toggleFirstSet()); - try testing.expectEqual(@as(usize, 0), a.count()); - - a.setRangeValue(.{ .start = 0, .end = len }, false); - try testing.expectEqual(@as(usize, 0), a.count()); - - a.setRangeValue(.{ .start = 0, .end = len }, true); - try testing.expectEqual(len, a.count()); - - a.setRangeValue(.{ .start = 0, .end = len }, false); - a.setRangeValue(.{ .start = 0, .end = 0 }, true); - try testing.expectEqual(@as(usize, 0), a.count()); - - a.setRangeValue(.{ .start = len, .end = len }, true); - try testing.expectEqual(@as(usize, 0), a.count()); - - if (len >= 1) { - a.setRangeValue(.{ .start = 0, .end = len }, false); - a.setRangeValue(.{ .start = 0, .end = 1 }, true); - try testing.expectEqual(@as(usize, 1), a.count()); - try testing.expect(a.isSet(0)); - - a.setRangeValue(.{ .start = 0, .end = len }, false); - a.setRangeValue(.{ .start = 0, .end = len - 1 }, true); - try testing.expectEqual(len - 1, a.count()); - try testing.expect(!a.isSet(len - 1)); - - a.setRangeValue(.{ .start = 0, .end = len }, false); - a.setRangeValue(.{ .start = 1, .end = len }, true); - try testing.expectEqual(@as(usize, len - 1), a.count()); - try testing.expect(!a.isSet(0)); - - a.setRangeValue(.{ .start = 0, .end = len }, false); - a.setRangeValue(.{ .start = len - 1, .end = len }, true); - try testing.expectEqual(@as(usize, 1), a.count()); - try testing.expect(a.isSet(len - 1)); - - if (len >= 4) { - a.setRangeValue(.{ .start = 0, .end = len }, false); - a.setRangeValue(.{ .start = 1, .end = len - 2 }, true); - try testing.expectEqual(@as(usize, len - 3), a.count()); - try testing.expect(!a.isSet(0)); - try testing.expect(a.isSet(1)); - try testing.expect(a.isSet(len - 3)); - try testing.expect(!a.isSet(len - 2)); - try testing.expect(!a.isSet(len - 1)); - } - } -} - -fn fillEven(set: anytype, len: usize) void { - for (0..len) |i| { - set.setValue(i, i & 1 == 0); - } -} - -fn fillOdd(set: anytype, len: usize) void { - for (0..len) |i| { - set.setValue(i, i & 1 == 1); - } -} - -fn testPureBitSet(comptime Set: type) !void { - var empty_ = Set.initEmpty(); - var full_ = Set.initFull(); - const needs_ptr = @hasField(Set, "masks") and @typeInfo(@TypeOf(empty_.masks)) != .pointer; - - var even_ = even: { - var bit_set = Set.initEmpty(); - fillEven(&bit_set, Set.bit_length); - break :even bit_set; - }; - - var odd_ = odd: { - var bit_set = Set.initEmpty(); - fillOdd(&bit_set, Set.bit_length); - break :odd bit_set; - }; - - var empty = if (needs_ptr) &empty_ else empty_; - var full = if (needs_ptr) &full_ else full_; - var even = if (needs_ptr) &even_ else even_; - var odd = if (needs_ptr) &odd_ else odd_; - - try testSubsetOf(empty, full, even, odd, Set.bit_length); - try testSupersetOf(empty, full, even, odd, Set.bit_length); - - try testing.expect(empty.complement().eql(full)); - try testing.expect(full.complement().eql(empty)); - try testing.expect(even.complement().eql(odd)); - try testing.expect(odd.complement().eql(even)); - - try testing.expect(empty.unionWith(empty).eql(empty)); - try testing.expect(empty.unionWith(full).eql(full)); - try testing.expect(full.unionWith(full).eql(full)); - try testing.expect(full.unionWith(empty).eql(full)); - try testing.expect(even.unionWith(odd).eql(full)); - try testing.expect(odd.unionWith(even).eql(full)); - - try testing.expect(empty.intersectWith(empty).eql(empty)); - try testing.expect(empty.intersectWith(full).eql(empty)); - try testing.expect(full.intersectWith(full).eql(full)); - try testing.expect(full.intersectWith(empty).eql(empty)); - try testing.expect(even.intersectWith(odd).eql(empty)); - try testing.expect(odd.intersectWith(even).eql(empty)); - - try testing.expect(empty.xorWith(empty).eql(empty)); - try testing.expect(empty.xorWith(full).eql(full)); - try testing.expect(full.xorWith(full).eql(empty)); - try testing.expect(full.xorWith(empty).eql(full)); - try testing.expect(even.xorWith(odd).eql(full)); - try testing.expect(odd.xorWith(even).eql(full)); - - try testing.expect(empty.differenceWith(empty).eql(empty)); - try testing.expect(empty.differenceWith(full).eql(empty)); - try testing.expect(full.differenceWith(full).eql(empty)); - try testing.expect(full.differenceWith(empty).eql(full)); - try testing.expect(full.differenceWith(odd).eql(even)); - try testing.expect(full.differenceWith(even).eql(odd)); -} - -fn testStaticBitSet(comptime Set: type, comptime Container: @Type(.enum_literal)) !void { - var a = Set.initEmpty(); - var b = Set.initFull(); - try testing.expectEqual(@as(usize, 0), a.count()); - try testing.expectEqual(@as(usize, Set.bit_length), b.count()); - - if (comptime Container == .ArrayBitSet) { - try testEql(&a, &b, Set.bit_length); - } else { - try testEql(a, b, Set.bit_length); - } - - try testBitSet(&a, &b, Set.bit_length); - - try testPureBitSet(Set); -} - -const bun = @import("bun"); -const Environment = bun.Environment; - -const std = @import("std"); -const testing = std.testing; -const Allocator = std.mem.Allocator; diff --git a/src/collections/collections.zig b/src/collections/collections.zig deleted file mode 100644 index dd6edcff3586..000000000000 --- a/src/collections/collections.zig +++ /dev/null @@ -1,17 +0,0 @@ -pub const MultiArrayList = @import("./multi_array_list.zig").MultiArrayList; -pub const baby_list = @import("./baby_list.zig"); -pub const BabyList = baby_list.BabyList; -pub const ByteList = baby_list.ByteList; // alias of BabyList(u8) -pub const OffsetByteList = baby_list.OffsetByteList; -pub const bit_set = @import("./bit_set.zig"); -pub const AutoBitSet = bit_set.AutoBitSet; -pub const HiveArray = @import("./hive_array.zig").HiveArray; -pub const BoundedArray = @import("./bounded_array.zig").BoundedArray; - -pub const array_list = @import("./array_list.zig"); -pub const ArrayList = array_list.ArrayList; // any `std.mem.Allocator` -pub const ArrayListDefault = array_list.ArrayListDefault; // always default allocator (no overhead) -pub const ArrayListIn = array_list.ArrayListIn; // specific type of generic allocator -pub const ArrayListAligned = array_list.ArrayListAligned; -pub const ArrayListAlignedDefault = array_list.ArrayListAlignedDefault; -pub const ArrayListAlignedIn = array_list.ArrayListAlignedIn; diff --git a/src/collections/comptime_string_map.zig b/src/collections/comptime_string_map.zig deleted file mode 100644 index 0a1b0a35ffa3..000000000000 --- a/src/collections/comptime_string_map.zig +++ /dev/null @@ -1,553 +0,0 @@ -/// Comptime string map optimized for small sets of disparate string keys. -/// Works by separating the keys by length at comptime and only checking strings of -/// equal length at runtime. -/// -/// `kvs` expects a list literal containing list literals or an array/slice of structs -/// where `.@"0"` is the `[]const u8` key and `.@"1"` is the associated value of type `V`. -/// TODO: https://github.com/ziglang/zig/issues/4335 -pub fn ComptimeStringMapWithKeyType(comptime KeyType: type, comptime V: type, comptime kvs_list: anytype) type { - const KV = struct { - key: []const KeyType, - value: V, - }; - - const precomputed = comptime blk: { - @setEvalBranchQuota(99999); - - var sorted_kvs: [kvs_list.len]KV = undefined; - const lenAsc = (struct { - fn lenAsc(context: void, a: KV, b: KV) bool { - _ = context; - if (a.key.len != b.key.len) { - return a.key.len < b.key.len; - } - // https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-processing-an-unsorted-array - @setEvalBranchQuota(999999); - return std.mem.order(KeyType, a.key, b.key) == .lt; - } - }).lenAsc; - if (KeyType == u8) { - for (kvs_list, 0..) |kv, i| { - if (V != void) { - sorted_kvs[i] = .{ .key = kv.@"0", .value = kv.@"1" }; - } else { - sorted_kvs[i] = .{ .key = kv.@"0", .value = {} }; - } - } - } else { - @compileError("Not implemented for this key type"); - } - std.sort.pdq(KV, &sorted_kvs, {}, lenAsc); - const min_len = sorted_kvs[0].key.len; - const max_len = sorted_kvs[sorted_kvs.len - 1].key.len; - var len_indexes: [max_len + 1]usize = undefined; - var len: usize = 0; - var i: usize = 0; - - while (len <= max_len) : (len += 1) { - @setEvalBranchQuota(99999); - - // find the first keyword len == len - while (len > sorted_kvs[i].key.len) { - i += 1; - } - len_indexes[len] = i; - } - break :blk .{ - .min_len = min_len, - .max_len = max_len, - .sorted_kvs = sorted_kvs, - .len_indexes = len_indexes, - }; - }; - - return struct { - const len_indexes = precomputed.len_indexes; - pub const kvs = precomputed.sorted_kvs; - - const keys_list: []const []const KeyType = blk: { - var k: [kvs.len][]const KeyType = undefined; - for (kvs, 0..) |kv, i| { - k[i] = kv.key; - } - const final = k; - break :blk &final; - }; - - pub const Value = V; - - pub fn keys() []const []const KeyType { - return keys_list; - } - - pub fn has(str: []const KeyType) bool { - return get(str) != null; - } - - pub fn getWithLength(str: []const KeyType, comptime len: usize) ?V { - const end = comptime brk: { - var i = len_indexes[len]; - @setEvalBranchQuota(99999); - - while (i < kvs.len and kvs[i].key.len == len) : (i += 1) {} - - break :brk i; - }; - - // This benchmarked faster for both small and large lists of strings than using a big switch statement - // But only so long as the keys are a sorted list. - inline for (len_indexes[len]..end) |i| { - if (strings.eqlComptimeCheckLenWithType(KeyType, str, kvs[i].key, false)) { - return kvs[i].value; - } - } - - return null; - } - - pub fn getWithLengthAndEql(str: anytype, comptime len: usize, comptime eqls: anytype) ?V { - const end = comptime brk: { - var i = len_indexes[len]; - @setEvalBranchQuota(99999); - - while (i < kvs.len and kvs[i].key.len == len) : (i += 1) {} - - break :brk i; - }; - - // This benchmarked faster for both small and large lists of strings than using a big switch statement - // But only so long as the keys are a sorted list. - inline for (len_indexes[len]..end) |i| { - if (eqls(str, kvs[i].key)) { - return kvs[i].value; - } - } - - return null; - } - - pub fn getWithLengthAndEqlList(str: anytype, comptime len: usize, comptime eqls: anytype) ?V { - const end = comptime brk: { - var i = len_indexes[len]; - @setEvalBranchQuota(99999); - - while (i < kvs.len and kvs[i].key.len == len) : (i += 1) {} - - break :brk i; - }; - - const start = comptime len_indexes[len]; - const range = comptime keys()[start..end]; - if (eqls(str, range)) |k| { - return kvs[start + k].value; - } - - return null; - } - - pub fn get(str: []const KeyType) ?V { - if (str.len < precomputed.min_len or str.len > precomputed.max_len) - return null; - - comptime var i: usize = precomputed.min_len; - inline while (i <= precomputed.max_len) : (i += 1) { - if (str.len == i) { - return getWithLength(str, i); - } - } - - return null; - } - - /// Returns the index of the key in the sorted list of keys. - pub fn indexOf(str: []const KeyType) ?usize { - if (str.len < precomputed.min_len or str.len > precomputed.max_len) - return null; - - comptime var len: usize = precomputed.min_len; - inline while (len <= precomputed.max_len) : (len += 1) { - if (str.len == len) { - const end = comptime brk: { - var i = len_indexes[len]; - @setEvalBranchQuota(99999); - - while (i < kvs.len and kvs[i].key.len == len) : (i += 1) {} - - break :brk i; - }; - - // This benchmarked faster for both small and large lists of strings than using a big switch statement - // But only so long as the keys are a sorted list. - inline for (len_indexes[len]..end) |i| { - if (strings.eqlComptimeCheckLenWithType(KeyType, str, kvs[i].key, false)) { - return i; - } - } - - return null; - } - } - return null; - } - - /// Throws if toString() throws. Typed `anytype` so `collections/` has - /// no JSC references; the body lives in `jsc/comptime_string_map_jsc.zig`. - pub fn fromJS(globalThis: anytype, input: anytype) bun.JSError!?V { - return @import("../jsc/comptime_string_map_jsc.zig").fromJS(@This(), globalThis, input); - } - - /// Throws if toString() throws. - pub fn fromJSCaseInsensitive(globalThis: anytype, input: anytype) bun.JSError!?V { - return @import("../jsc/comptime_string_map_jsc.zig").fromJSCaseInsensitive(@This(), globalThis, input); - } - - pub fn fromString(str: bun.String) ?V { - return getWithEql(str, bun.String.eqlComptime); - } - - pub fn getASCIIICaseInsensitive(input: anytype) ?V { - return getWithEqlLowercase(input, bun.strings.eqlComptimeIgnoreLen); - } - - pub fn getWithEqlLowercase(input: anytype, comptime eql: anytype) ?V { - const Input = @TypeOf(input); - const length = if (@hasField(Input, "len")) input.len else input.length(); - if (length < precomputed.min_len or length > precomputed.max_len) - return null; - - comptime var i: usize = precomputed.min_len; - inline while (i <= precomputed.max_len) : (i += 1) { - if (length == i) { - const lowerbuf: [i]u8 = brk: { - var buf: [i]u8 = undefined; - for (input, &buf) |c, *j| { - j.* = std.ascii.toLower(c); - } - break :brk buf; - }; - - return getWithLengthAndEql(&lowerbuf, i, eql); - } - } - - return null; - } - - pub fn getWithEql(input: anytype, comptime eql: anytype) ?V { - const Input = @TypeOf(input); - const length = if (@hasField(Input, "len")) input.len else input.length(); - if (length < precomputed.min_len or length > precomputed.max_len) - return null; - - comptime var i: usize = precomputed.min_len; - inline while (i <= precomputed.max_len) : (i += 1) { - if (length == i) { - return getWithLengthAndEql(input, i, eql); - } - } - - return null; - } - - pub fn getAnyCase(input: anytype) ?V { - return getCaseInsensitiveWithEql(input, bun.strings.eqlComptimeIgnoreLen); - } - - pub fn getCaseInsensitiveWithEql(input: anytype, comptime eql: anytype) ?V { - const Input = @TypeOf(input); - const length = if (@hasField(Input, "len")) input.len else input.length(); - if (length < precomputed.min_len or length > precomputed.max_len) - return null; - - comptime var i: usize = precomputed.min_len; - inline while (i <= precomputed.max_len) : (i += 1) { - if (length == i) { - const lowercased: [i]u8 = brk: { - var buf: [i]u8 = undefined; - for (input[0..i], &buf) |c, *b| { - b.* = switch (c) { - 'A'...'Z' => c + 32, - else => c, - }; - } - break :brk buf; - }; - return getWithLengthAndEql(&lowercased, i, eql); - } - } - - return null; - } - - pub fn getWithEqlList(input: anytype, comptime eql: anytype) ?V { - const Input = @TypeOf(input); - const length = if (@hasField(Input, "len")) input.len else input.length(); - if (length < precomputed.min_len or length > precomputed.max_len) - return null; - - comptime var i: usize = precomputed.min_len; - inline while (i <= precomputed.max_len) : (i += 1) { - if (length == i) { - return getWithLengthAndEqlList(input, i, eql); - } - } - - return null; - } - - /// Lookup the first-defined string key for a given value. - /// - /// Linear search. - pub fn getKey(value: V) ?[]const KeyType { - inline for (kvs) |kv| { - if (kv.value == value) return kv.key; - } - - return null; - } - }; -} - -pub fn ComptimeStringMap(comptime V: type, comptime kvs_list: anytype) type { - return ComptimeStringMapWithKeyType(u8, V, kvs_list); -} - -pub fn ComptimeStringMap16(comptime V: type, comptime kvs_list: anytype) type { - return ComptimeStringMapWithKeyType(u16, V, kvs_list); -} - -const TestEnum = enum { - A, - B, - C, - D, - E, -}; - -test "ComptimeStringMap list literal of list literals" { - const map = ComptimeStringMap(TestEnum, .{ - .{ "these", .D }, - .{ "have", .A }, - .{ "nothing", .B }, - .{ "incommon", .C }, - .{ "samelen", .E }, - }); - - try testMap(map); -} - -test "ComptimeStringMap array of structs" { - const KV = struct { - @"0": []const u8, - @"1": TestEnum, - }; - const map = ComptimeStringMap(TestEnum, [_]KV{ - .{ .@"0" = "these", .@"1" = .D }, - .{ .@"0" = "have", .@"1" = .A }, - .{ .@"0" = "nothing", .@"1" = .B }, - .{ .@"0" = "incommon", .@"1" = .C }, - .{ .@"0" = "samelen", .@"1" = .E }, - }); - - try testMap(map); -} - -test "ComptimeStringMap slice of structs" { - const KV = struct { - @"0": []const u8, - @"1": TestEnum, - }; - const slice: []const KV = &[_]KV{ - .{ .@"0" = "these", .@"1" = .D }, - .{ .@"0" = "have", .@"1" = .A }, - .{ .@"0" = "nothing", .@"1" = .B }, - .{ .@"0" = "incommon", .@"1" = .C }, - .{ .@"0" = "samelen", .@"1" = .E }, - }; - const map = ComptimeStringMap(TestEnum, slice); - - try testMap(map); -} - -fn testMap(comptime map: anytype) !void { - try std.testing.expectEqual(TestEnum.A, map.get("have").?); - try std.testing.expectEqual(TestEnum.B, map.get("nothing").?); - try std.testing.expect(null == map.get("missing")); - try std.testing.expectEqual(TestEnum.D, map.get("these").?); - try std.testing.expectEqual(TestEnum.E, map.get("samelen").?); - - try std.testing.expect(!map.has("missing")); - try std.testing.expect(map.has("these")); -} - -test "ComptimeStringMap void value type, slice of structs" { - const KV = struct { - @"0": []const u8, - }; - const slice: []const KV = &[_]KV{ - .{ .@"0" = "these" }, - .{ .@"0" = "have" }, - .{ .@"0" = "nothing" }, - .{ .@"0" = "incommon" }, - .{ .@"0" = "samelen" }, - }; - const map = ComptimeStringMap(void, slice); - - try testSet(map); -} - -test "ComptimeStringMap void value type, list literal of list literals" { - const map = ComptimeStringMap(void, .{ - .{"these"}, - .{"have"}, - .{"nothing"}, - .{"incommon"}, - .{"samelen"}, - }); - - try testSet(map); -} - -fn testSet(comptime map: anytype) !void { - try std.testing.expectEqual({}, map.get("have").?); - try std.testing.expectEqual({}, map.get("nothing").?); - try std.testing.expect(null == map.get("missing")); - try std.testing.expectEqual({}, map.get("these").?); - try std.testing.expectEqual({}, map.get("samelen").?); - - try std.testing.expect(!map.has("missing")); - try std.testing.expect(map.has("these")); -} - -const TestEnum2 = enum { - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, - P, - Q, - R, - S, - T, - U, - V, - W, - X, - Y, - FZ, - FA, - FB, - FC, - FD, - FE, - FF, - FG, - FH, - FI, - FJ, - FK, - FL, - - pub const map = ComptimeStringMap(TestEnum2, .{ - .{ "these", .A }, - .{ "have", .B }, - .{ "nothing", .C }, - .{ "nothinz", .D }, - .{ "nothinc", .E }, - .{ "nothina", .F }, - .{ "nothinb", .G }, - .{ "nothiaa", .H }, - .{ "nothaaa", .I }, - .{ "notaaaa", .J }, - .{ "noaaaaa", .K }, - .{ "naaaaaa", .L }, - .{ "incommon", .M }, - .{ "ancommon", .N }, - .{ "ab1ommon", .O }, - .{ "ab2ommon", .P }, - .{ "ab3ommon", .Q }, - .{ "ab4ommon", .R }, - .{ "ab5ommon", .S }, - .{ "ab6ommon", .T }, - .{ "ab7ommon", .U }, - .{ "ab8ommon", .V }, - .{ "ab9ommon", .W }, - .{ "abAommon", .X }, - .{ "abBommon", .Y }, - .{ "abCommon", .FZ }, - .{ "abZommon", .FA }, - .{ "abEommon", .FB }, - .{ "abFommon", .FC }, - .{ "ab10omon", .FD }, - .{ "ab11omon", .FE }, - .{ "ab12omon", .FF }, - .{ "ab13omon", .FG }, - .{ "ab14omon", .FH }, - .{ "ab15omon", .FI }, - .{ "ab16omon", .FJ }, - .{ "ab16omon1", .FH }, - .{ "samelen", .FK }, - .{ "0", .FL }, - .{ "00", .FL }, - }); - - pub const official = std.ComptimeStringMap(TestEnum2, .{ - .{ "these", .A }, - .{ "have", .B }, - .{ "naaaaaa", .L }, - .{ "noaaaaa", .K }, - .{ "notaaaa", .J }, - .{ "nothaaa", .I }, - .{ "nothiaa", .H }, - .{ "nothina", .F }, - .{ "nothinb", .G }, - .{ "nothinc", .E }, - .{ "nothing", .C }, - .{ "nothinz", .D }, - .{ "incommon", .M }, - .{ "ancommon", .N }, - .{ "ab1ommon", .O }, - .{ "ab2ommon", .P }, - .{ "ab3ommon", .Q }, - .{ "ab4ommon", .R }, - .{ "ab5ommon", .S }, - .{ "ab6ommon", .T }, - .{ "ab7ommon", .U }, - .{ "ab8ommon", .V }, - .{ "ab9ommon", .W }, - .{ "abAommon", .X }, - .{ "abBommon", .Y }, - .{ "abCommon", .FZ }, - .{ "abZommon", .FA }, - .{ "abEommon", .FB }, - .{ "abFommon", .FC }, - .{ "ab10omon", .FD }, - .{ "ab11omon", .FE }, - .{ "ab12omon", .FF }, - .{ "ab13omon", .FG }, - .{ "ab14omon", .FH }, - .{ "ab15omon", .FI }, - .{ "ab16omon", .FJ }, - .{ "samelen", .FK }, - .{ "ab16omon1", .FH }, - .{ "0", .FL }, - .{ "00", .FL }, - }); -}; - -const bun = @import("bun"); -const strings = bun.strings; - -const std = @import("std"); -const mem = std.mem; diff --git a/src/collections/hive_array.zig b/src/collections/hive_array.zig deleted file mode 100644 index cf1d45b4e524..000000000000 --- a/src/collections/hive_array.zig +++ /dev/null @@ -1,187 +0,0 @@ -/// An array that efficiently tracks which elements are in use. -/// The pointers are intended to be stable -/// Sorta related to https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0447r15.html -pub fn HiveArray(comptime T: type, comptime capacity: u16) type { - return struct { - const Self = @This(); - - buffer: [capacity]T, - used: bun.bit_set.IntegerBitSet(capacity), - - pub const size = capacity; - - /// This is deliberately a `var` instead of a `const`. - /// - /// https://github.com/ziglang/zig/issues/22462 - /// https://github.com/ziglang/zig/issues/21988 - pub var empty: Self = .{ - .buffer = undefined, - .used = .initEmpty(), - }; - - pub fn init() Self { - return .{ - .buffer = undefined, - .used = .initEmpty(), - }; - } - - pub fn get(self: *Self) ?*T { - const index = self.used.findFirstUnset() orelse return null; - self.used.set(index); - const ret = &self.buffer[index]; - bun.asan.unpoison(@ptrCast(ret), @sizeOf(T)); - return ret; - } - - pub fn at(self: *Self, index: u16) *T { - assert(index < capacity); - const ret = &self.buffer[index]; - bun.asan.assertUnpoisoned(@ptrCast(ret)); - return ret; - } - - pub fn indexOf(self: *const Self, value: *const T) ?u32 { - bun.asan.assertUnpoisoned(@ptrCast(value)); - const start = &self.buffer; - const end = @as([*]const T, @ptrCast(start)) + capacity; - if (!(@intFromPtr(value) >= @intFromPtr(start) and @intFromPtr(value) < @intFromPtr(end))) - return null; - - // aligned to the size of T - const index = (@intFromPtr(value) - @intFromPtr(start)) / @sizeOf(T); - assert(index < capacity); - assert(&self.buffer[index] == value); - return @as(u32, @intCast(index)); - } - - pub fn in(self: *const Self, value: *const T) bool { - bun.asan.assertUnpoisoned(@ptrCast(value)); - const start = &self.buffer; - const end = @as([*]const T, @ptrCast(start)) + capacity; - return (@intFromPtr(value) >= @intFromPtr(start) and @intFromPtr(value) < @intFromPtr(end)); - } - - pub fn put(self: *Self, value: *T) bool { - const index = self.indexOf(value) orelse return false; - - assert(self.used.isSet(index)); - assert(&self.buffer[index] == value); - - value.* = undefined; - bun.asan.poison(value, @sizeOf(T)); - - self.used.unset(index); - return true; - } - - pub const Fallback = struct { - hive: if (capacity > 0) Self else void, - allocator: std.mem.Allocator, - - pub const This = @This(); - - pub fn init(allocator: std.mem.Allocator) This { - return .{ - .allocator = allocator, - .hive = if (comptime capacity > 0) Self.empty, - }; - } - - pub fn get(self: *This) *T { - const value = getImpl(self); - return value; - } - - fn getImpl(self: *This) *T { - if (comptime capacity > 0) { - if (self.hive.get()) |value| { - return value; - } - } - - return bun.handleOom(self.allocator.create(T)); - } - - pub fn getAndSeeIfNew(self: *This, new: *bool) *T { - if (comptime capacity > 0) { - if (self.hive.get()) |value| { - new.* = false; - return value; - } - } - - return bun.handleOom(self.allocator.create(T)); - } - - pub fn tryGet(self: *This) OOM!*T { - if (comptime capacity > 0) { - if (self.hive.get()) |value| { - return value; - } - } - - return try self.allocator.create(T); - } - - pub fn in(self: *const This, value: *const T) bool { - if (comptime capacity > 0) { - if (self.hive.in(value)) return true; - } - - return false; - } - - pub fn put(self: *This, value: *T) void { - if (comptime capacity > 0) { - if (self.hive.put(value)) return; - } - - self.allocator.destroy(value); - } - }; - }; -} - -test "HiveArray" { - const size = 64; - - // Choose an integer with a weird alignment - const Int = u127; - - var a = HiveArray(Int, size).init(); - - { - const b = a.get().?; - try testing.expect(a.get().? != b); - try testing.expectEqual(a.indexOf(b), 0); - try testing.expect(a.put(b)); - try testing.expect(a.get().? == b); - const c = a.get().?; - c.* = 123; - var d: Int = 12345; - try testing.expect(a.put(&d) == false); - try testing.expect(a.in(&d) == false); - } - - a.used = @TypeOf(a.used).initEmpty(); - { - for (0..size) |i| { - const b = a.get().?; - try testing.expectEqual(a.indexOf(b), i); - try testing.expect(a.put(b)); - try testing.expect(a.get().? == b); - } - for (0..size) |_| { - try testing.expect(a.get() == null); - } - } -} - -const bun = @import("bun"); -const OOM = bun.OOM; -const assert = bun.assert; - -const std = @import("std"); -const mem = std.mem; -const testing = std.testing; diff --git a/src/collections/identity_context.zig b/src/collections/identity_context.zig deleted file mode 100644 index 171c253540ef..000000000000 --- a/src/collections/identity_context.zig +++ /dev/null @@ -1,37 +0,0 @@ -pub fn IdentityContext(comptime Key: type) type { - return struct { - pub fn hash(_: @This(), key: Key) u64 { - return switch (comptime @typeInfo(Key)) { - .@"enum" => @intFromEnum(key), - .int => key, - else => @compileError("unexpected identity context type"), - }; - } - - pub fn eql(_: @This(), a: Key, b: Key) bool { - return a == b; - } - }; -} - -/// When storing hashes as keys in a hash table, we don't want to hash the hashes or else we increase the chance of collisions. This is also marginally faster since it means hashing less stuff. -/// `ArrayIdentityContext` and `IdentityContext` are distinct because ArrayHashMap expects u32 hashes but HashMap expects u64 hashes. -pub const ArrayIdentityContext = struct { - pub fn hash(_: @This(), key: u32) u32 { - return key; - } - - pub fn eql(_: @This(), a: u32, b: u32, _: usize) bool { - return a == b; - } - - pub const U64 = struct { - pub fn hash(_: @This(), key: u64) u32 { - return @truncate(key); - } - - pub fn eql(_: @This(), a: u64, b: u64, _: usize) bool { - return a == b; - } - }; -}; diff --git a/src/collections/linear_fifo.zig b/src/collections/linear_fifo.zig deleted file mode 100644 index c53ce701e7f3..000000000000 --- a/src/collections/linear_fifo.zig +++ /dev/null @@ -1,588 +0,0 @@ -// clone of zig stdlib -// except, this one vectorizes - -// FIFO of fixed size items -// Usually used for e.g. byte buffers - -pub const LinearFifoBufferType = union(enum) { - /// The buffer is internal to the fifo; it is of the specified size. - Static: usize, - - /// The buffer is passed as a slice to the initialiser. - Slice, - - /// The buffer is managed dynamically using a `mem.Allocator`. - Dynamic, - - fn BufferType(comptime buffer_type: @This(), comptime T: type) type { - return if (buffer_type == .Static) [buffer_type.Static]T else []T; - } -}; - -pub fn LinearFifo( - comptime T: type, - comptime buffer_type: LinearFifoBufferType, -) type { - const BufferType = buffer_type.BufferType(T); - return struct { - const powers_of_two = switch (buffer_type) { - .Static => std.math.isPowerOfTwo(buffer_type.Static), - .Slice => false, // Any size slice could be passed in - .Dynamic => true, // This could be configurable in future - }; - - allocator: if (buffer_type == .Dynamic) Allocator else void, - buf: BufferType, - head: usize, - count: usize, - - const Self = @This(); - pub const Reader = std.Io.GenericReader(*Self, error{}, readFn); - pub const Writer = std.Io.GenericWriter(*Self, error{OutOfMemory}, appendWrite); - - // Type of Self argument for slice operations. - // If buffer is inline (Static) then we need to ensure we haven't - // returned a slice into a copy on the stack - const SliceSelfArg = if (buffer_type == .Static) *Self else Self; - - pub const init = switch (buffer_type) { - .Static => initStatic, - .Slice => initSlice, - .Dynamic => initDynamic, - }; - - fn initStatic() Self { - return .{ - .allocator = {}, - .buf = undefined, - .head = 0, - .count = 0, - }; - } - - fn initSlice(buf: []T) Self { - return .{ - .allocator = {}, - .buf = buf, - .head = 0, - .count = 0, - }; - } - - fn initDynamic(allocator: Allocator) Self { - return .{ - .allocator = allocator, - .buf = &[_]T{}, - .head = 0, - .count = 0, - }; - } - - pub fn deinit(self: Self) void { - if (buffer_type == .Dynamic) self.allocator.free(self.buf); - } - - pub fn realign(self: *Self) void { - if (self.buf.len - self.head >= self.count) { - // this copy overlaps - bun.copy(T, self.buf[0..self.count], self.buf[self.head..][0..self.count]); - self.head = 0; - } else { - var tmp: [std.heap.page_size_min / 2 / @sizeOf(T)]T = undefined; - - while (self.head != 0) { - const n = @min(self.head, tmp.len); - const m = self.buf.len - n; - bun.copy(T, tmp[0..n], self.buf[0..n]); - // this middle copy overlaps; the others here don't - bun.copy(T, self.buf[0..m], self.buf[n..][0..m]); - bun.copy(T, self.buf[m..], tmp[0..n]); - self.head -= n; - } - } - { // set unused area to undefined - const unused = mem.sliceAsBytes(self.buf[self.count..]); - @memset(unused, undefined); - } - } - - /// Reduce allocated capacity to `size`. - pub fn shrink(self: *Self, size: usize) void { - assert(size >= self.count); - if (buffer_type == .Dynamic) { - self.realign(); - self.buf = self.allocator.realloc(self.buf, size) catch |e| switch (e) { - error.OutOfMemory => return, // no problem, capacity is still correct then. - }; - } - } - - pub const ensureCapacity = @compileError("deprecated; call `ensureUnusedCapacity` or `ensureTotalCapacity`"); - - /// Ensure that the buffer can fit at least `size` items - pub fn ensureTotalCapacity(self: *Self, size: usize) !void { - if (self.buf.len >= size) return; - if (buffer_type == .Dynamic) { - self.realign(); - const new_size = if (powers_of_two) math.ceilPowerOfTwo(usize, size) catch return error.OutOfMemory else size; - const buf = try self.allocator.alloc(T, new_size); - if (self.count > 0) { - var new_bytes = std.mem.sliceAsBytes(buf); - const old_bytes = std.mem.sliceAsBytes(self.readableSlice(0)); - @memcpy(new_bytes[0..old_bytes.len], old_bytes); - } - self.allocator.free(self.buf); - self.head = 0; - self.buf = buf; - } else { - return error.OutOfMemory; - } - } - - /// Makes sure at least `size` items are unused - pub fn ensureUnusedCapacity(self: *Self, size: usize) error{OutOfMemory}!void { - if (self.writableLength() >= size) return; - - return try self.ensureTotalCapacity(math.add(usize, self.count, size) catch return error.OutOfMemory); - } - - /// Returns number of items currently in fifo - pub fn readableLength(self: Self) usize { - return self.count; - } - - /// Returns a writable slice from the 'read' end of the fifo - fn readableSliceMut(self: SliceSelfArg, offset: usize) []T { - if (offset > self.count) return &[_]T{}; - - var start = self.head + offset; - if (start >= self.buf.len) { - start -= self.buf.len; - return self.buf[start .. start + (self.count - offset)]; - } else { - const end = @min(self.head + self.count, self.buf.len); - return self.buf[start..end]; - } - } - - /// Returns a readable slice from `offset` - pub fn readableSlice(self: SliceSelfArg, offset: usize) []const T { - return self.readableSliceMut(offset); - } - - /// Discard first `count` items in the fifo - pub fn discard(self: *Self, count: usize) void { - assert(count <= self.count); - - if (comptime bun.Environment.allow_assert) { - // set old range to undefined. Note: may be wrapped around - const slice = self.readableSliceMut(0); - if (slice.len >= count) { - const unused = mem.sliceAsBytes(slice[0..count]); - @memset(unused, undefined); - } else { - const unused = mem.sliceAsBytes(slice[0..]); - @memset(unused, undefined); - const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]); - @memset(unused2, undefined); - } - } - - var head = self.head + count; - if (powers_of_two) { - // Note it is safe to do a wrapping subtract as - // bitwise & with all 1s is a noop - head &= self.buf.len -% 1; - } else { - head %= self.buf.len; - } - self.head = head; - self.count -= count; - } - - /// Read the next item from the fifo - pub fn readItem(self: *Self) ?T { - if (self.count == 0) return null; - - const c = self.buf[self.head]; - self.discard(1); - return c; - } - - /// Read data from the fifo into `dst`, returns number of items copied. - pub fn read(self: *Self, dst: []T) usize { - var dst_left = dst; - - while (dst_left.len > 0) { - const slice = self.readableSlice(0); - if (slice.len == 0) break; - const n = @min(slice.len, dst_left.len); - bun.copy(T, dst_left, slice[0..n]); - self.discard(n); - dst_left = dst_left[n..]; - } - - return dst.len - dst_left.len; - } - - /// Same as `read` except it returns an error union - /// The purpose of this function existing is to match `std.io.Reader` API. - fn readFn(self: *Self, dest: []u8) error{}!usize { - return self.read(dest); - } - - pub fn reader(self: *Self) Reader { - return .{ .context = self }; - } - - /// Returns number of items available in fifo - pub fn writableLength(self: Self) usize { - return self.buf.len - self.count; - } - - /// Returns the first section of writable buffer - /// Note that this may be of length 0 - pub fn writableSlice(self: SliceSelfArg, offset: usize) []T { - if (offset > self.buf.len) return &[_]T{}; - - const tail = self.head + offset + self.count; - if (tail < self.buf.len) { - return self.buf[tail..]; - } else { - return self.buf[tail - self.buf.len ..][0 .. self.writableLength() - offset]; - } - } - - /// Returns a writable buffer of at least `size` items, allocating memory as needed. - /// Use `fifo.update` once you've written data to it. - pub fn writableWithSize(self: *Self, size: usize) ![]T { - try self.ensureUnusedCapacity(size); - - // try to avoid realigning buffer - var slice = self.writableSlice(0); - - if (slice.len < size) { - self.realign(); - slice = self.writableSlice(0); - } - - bun.assert(slice.len >= size); - return slice[0..size]; - } - - /// Update the tail location of the buffer (usually follows use of writable/writableWithSize) - pub fn update(self: *Self, count: usize) void { - assert(self.count + count <= self.buf.len); - self.count += count; - } - - /// Appends the data in `src` to the fifo. - /// You must have ensured there is enough space. - pub fn writeAssumeCapacity(self: *Self, src: []const T) void { - assert(self.writableLength() >= src.len); - - var src_left = src; - while (src_left.len > 0) { - const writable_slice = self.writableSlice(0); - assert(writable_slice.len != 0); - const n = @min(writable_slice.len, src_left.len); - bun.copy(T, writable_slice, src_left[0..n]); - self.update(n); - src_left = src_left[n..]; - } - } - - /// Write a single item to the fifo - pub fn writeItem(self: *Self, item: T) !void { - try self.ensureUnusedCapacity(1); - return self.writeItemAssumeCapacity(item); - } - - pub fn writeItemAssumeCapacity(self: *Self, item: T) void { - var tail = self.head + self.count; - if (powers_of_two) { - tail &= self.buf.len - 1; - } else { - tail %= self.buf.len; - } - self.buf[tail] = item; - self.update(1); - } - - /// Appends the data in `src` to the fifo. - /// Allocates more memory as necessary - pub fn write(self: *Self, src: []const T) !void { - try self.ensureUnusedCapacity(src.len); - - return self.writeAssumeCapacity(src); - } - - /// Same as `write` except it returns the number of bytes written, which is always the same - /// as `bytes.len`. The purpose of this function existing is to match `std.io.Writer` API. - fn appendWrite(self: *Self, bytes: []const u8) error{OutOfMemory}!usize { - try self.write(bytes); - return bytes.len; - } - - pub fn writer(self: *Self) Writer { - return .{ .context = self }; - } - - /// Make `count` items available before the current read location - fn rewind(self: *Self, count: usize) void { - assert(self.writableLength() >= count); - - var head = self.head + (self.buf.len - count); - if (powers_of_two) { - head &= self.buf.len - 1; - } else { - head %= self.buf.len; - } - self.head = head; - self.count += count; - } - - /// Place data back into the read stream - pub fn unget(self: *Self, src: []const T) !void { - try self.ensureUnusedCapacity(src.len); - - self.rewind(src.len); - - const slice = self.readableSliceMut(0); - if (src.len < slice.len) { - bun.copy(T, slice, src); - } else { - bun.copy(T, slice, src[0..slice.len]); - const slice2 = self.readableSliceMut(slice.len); - bun.copy(T, slice2, src[slice.len..]); - } - } - - /// Returns the item at `offset`. - /// Asserts offset is within bounds. - pub fn peekItem(self: Self, offset: usize) T { - assert(offset < self.count); - - var index = self.head + offset; - if (powers_of_two) { - index &= self.buf.len - 1; - } else { - index %= self.buf.len; - } - return self.buf[index]; - } - - /// Returns the item at `offset`. - /// Asserts offset is within bounds. - pub fn peekItemMut(self: *Self, offset: usize) *T { - assert(offset < self.count); - - var index = self.head + offset; - if (powers_of_two) { - index &= self.buf.len - 1; - } else { - index %= self.buf.len; - } - return &self.buf[index]; - } - - /// Remove one item at `offset` and MOVE all items after it up one. - pub fn orderedRemoveItem(self: *Self, offset: usize) void { - if (offset == 0) return self.discard(1); - - assert(offset < self.count); - - if (self.buf.len - self.head >= self.count) { - // If it doesnt overflow past the end, there is one copy to be done - const rest = self.buf[self.head + offset ..]; - bun.copy(T, rest[0 .. rest.len - 1], rest[1..]); - } else { - var index = self.head + offset; - if (powers_of_two) { - index &= self.buf.len - 1; - } else { - index %= self.buf.len; - } - if (index < self.head) { - // If the item to remove is before the head, one slice is moved. - const rest = self.buf[index .. self.count - self.head]; - bun.copy(T, rest[0 .. rest.len - 1], rest[1..]); - } else { - // The items before and after the head have to be shifted - const wrap = self.buf[0]; - const right = self.buf[index..]; - bun.copy(T, right[0 .. right.len - 1], right[1..]); - self.buf[self.buf.len - 1] = wrap; - const left = self.buf[0 .. self.head - self.count]; - bun.copy(T, left[0 .. left.len - 1], left[1..]); - } - } - self.count -= 1; - } - - /// Pump data from a reader into a writer - /// stops when reader returns 0 bytes (EOF) - /// Buffer size must be set before calling; a buffer length of 0 is invalid. - pub fn pump(self: *Self, src_reader: anytype, dest_writer: *std.Io.Writer) !void { - assert(self.buf.len > 0); - while (true) { - if (self.writableLength() > 0) { - const n = try src_reader.read(self.writableSlice(0)); - if (n == 0) break; // EOF - self.update(n); - } - self.discard(try dest_writer.write(self.readableSlice(0))); - } - // flush remaining data - while (self.readableLength() > 0) { - self.discard(try dest_writer.write(self.readableSlice(0))); - } - } - }; -} - -test "LinearFifo(u8, .Dynamic) discard(0) from empty buffer should not error on overflow" { - var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); - defer fifo.deinit(); - - // If overflow is not explicitly allowed this will crash in debug / safe mode - fifo.discard(0); -} - -test "LinearFifo(u8, .Dynamic)" { - var fifo = LinearFifo(u8, .Dynamic).init(testing.allocator); - defer fifo.deinit(); - - try fifo.write("HELLO"); - try testing.expectEqual(@as(usize, 5), fifo.readableLength()); - try testing.expectEqualSlices(u8, "HELLO", fifo.readableSlice(0)); - - { - for (0..5) |i| { - try fifo.write(&[_]u8{fifo.peekItem(i)}); - } - try testing.expectEqual(@as(usize, 10), fifo.readableLength()); - try testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0)); - } - - { - try testing.expectEqual(@as(u8, 'H'), fifo.readItem().?); - try testing.expectEqual(@as(u8, 'E'), fifo.readItem().?); - try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?); - try testing.expectEqual(@as(u8, 'L'), fifo.readItem().?); - try testing.expectEqual(@as(u8, 'O'), fifo.readItem().?); - } - try testing.expectEqual(@as(usize, 5), fifo.readableLength()); - - { // Writes that wrap around - try testing.expectEqual(@as(usize, 11), fifo.writableLength()); - try testing.expectEqual(@as(usize, 6), fifo.writableSlice(0).len); - fifo.writeAssumeCapacity("6 FifoType.init(), - .Slice => FifoType.init(buf[0..]), - .Dynamic => FifoType.init(testing.allocator), - }; - defer fifo.deinit(); - - try fifo.write(&[_]T{ 0, 1, 1, 0, 1 }); - try testing.expectEqual(@as(usize, 5), fifo.readableLength()); - - { - try testing.expectEqual(@as(T, 0), fifo.readItem().?); - try testing.expectEqual(@as(T, 1), fifo.readItem().?); - try testing.expectEqual(@as(T, 1), fifo.readItem().?); - try testing.expectEqual(@as(T, 0), fifo.readItem().?); - try testing.expectEqual(@as(T, 1), fifo.readItem().?); - try testing.expectEqual(@as(usize, 0), fifo.readableLength()); - } - - { - try fifo.writeItem(1); - try fifo.writeItem(1); - try fifo.writeItem(1); - try testing.expectEqual(@as(usize, 3), fifo.readableLength()); - } - - { - var readBuf: [3]T = undefined; - const n = fifo.read(&readBuf); - try testing.expectEqual(@as(usize, 3), n); // NOTE: It should be the number of items. - } - } - } -} - -const bun = @import("bun"); - -const std = @import("std"); -const math = std.math; -const testing = std.testing; - -const debug = std.debug; -const assert = debug.assert; - -const mem = std.mem; -const Allocator = mem.Allocator; diff --git a/src/collections/multi_array_list.zig b/src/collections/multi_array_list.zig deleted file mode 100644 index 9621dfc7ec39..000000000000 --- a/src/collections/multi_array_list.zig +++ /dev/null @@ -1,647 +0,0 @@ -/// Copy of `std.MultiArrayList` with the following changes: -/// -/// * Added `zero` method to zero-initialize memory. -/// * Added `memoryCost` method, which returns the memory usage in bytes. -/// -/// Synchronized with std as of Zig 0.14.1. -/// -/// A MultiArrayList stores a list of a struct or tagged union type. -/// Instead of storing a single list of items, MultiArrayList -/// stores separate lists for each field of the struct or -/// lists of tags and bare unions. -/// This allows for memory savings if the struct or union has padding, -/// and also improves cache usage if only some fields or just tags -/// are needed for a computation. The primary API for accessing fields is -/// the `slice()` function, which computes the start pointers -/// for the array of each field. From the slice you can call -/// `.items(.)` to obtain a slice of field values. -/// For unions you can call `.items(.tags)` or `.items(.data)`. -pub fn MultiArrayList(comptime T: type) type { - return struct { - bytes: [*]align(@alignOf(T)) u8 = undefined, - len: usize = 0, - capacity: usize = 0, - #allocator: bun.safety.CheckedAllocator = .{}, - - pub const empty: Self = .{ - .bytes = undefined, - .len = 0, - .capacity = 0, - }; - - const Elem = switch (@typeInfo(T)) { - .@"struct" => T, - .@"union" => |u| struct { - pub const Bare = @Type(.{ .@"union" = .{ - .layout = u.layout, - .tag_type = null, - .fields = u.fields, - .decls = &.{}, - } }); - pub const Tag = - u.tag_type orelse @compileError("MultiArrayList does not support untagged unions"); - tags: Tag, - data: Bare, - - pub fn fromT(outer: T) @This() { - const tag = meta.activeTag(outer); - return .{ - .tags = tag, - .data = switch (tag) { - inline else => |t| @unionInit(Bare, @tagName(t), @field(outer, @tagName(t))), - }, - }; - } - pub fn toT(tag: Tag, bare: Bare) T { - return switch (tag) { - inline else => |t| @unionInit(T, @tagName(t), @field(bare, @tagName(t))), - }; - } - }, - else => @compileError("MultiArrayList only supports structs and tagged unions"), - }; - - pub const Field = meta.FieldEnum(Elem); - - /// A MultiArrayList.Slice contains cached start pointers for each field in the list. - /// These pointers are not normally stored to reduce the size of the list in memory. - /// If you are accessing multiple fields, call slice() first to compute the pointers, - /// and then get the field arrays from the slice. - pub const Slice = struct { - /// This array is indexed by the field index which can be obtained - /// by using @intFromEnum() on the Field enum - ptrs: [fields.len][*]u8, - len: usize, - capacity: usize, - - pub const empty: Slice = .{ - .ptrs = undefined, - .len = 0, - .capacity = 0, - }; - - pub fn items(self: Slice, comptime field: Field) []FieldType(field) { - const F = FieldType(field); - if (self.capacity == 0) { - return &[_]F{}; - } - const byte_ptr = self.ptrs[@intFromEnum(field)]; - const casted_ptr: [*]F = if (@sizeOf(F) == 0) - undefined - else - @ptrCast(@alignCast(byte_ptr)); - return casted_ptr[0..self.len]; - } - - pub fn set(self: *Slice, index: usize, elem: T) void { - const e = switch (@typeInfo(T)) { - .@"struct" => elem, - .@"union" => Elem.fromT(elem), - else => unreachable, - }; - inline for (fields, 0..) |field_info, i| { - self.items(@as(Field, @enumFromInt(i)))[index] = @field(e, field_info.name); - } - } - - pub fn get(self: Slice, index: usize) T { - var result: Elem = undefined; - inline for (fields, 0..) |field_info, i| { - @field(result, field_info.name) = self.items(@as(Field, @enumFromInt(i)))[index]; - } - return switch (@typeInfo(T)) { - .@"struct" => result, - .@"union" => Elem.toT(result.tags, result.data), - else => unreachable, - }; - } - - pub fn toMultiArrayList(self: Slice) Self { - if (self.ptrs.len == 0 or self.capacity == 0) { - return .{}; - } - const unaligned_ptr = self.ptrs[sizes.fields[0]]; - const aligned_ptr: [*]align(@alignOf(Elem)) u8 = @alignCast(unaligned_ptr); - return .{ - .bytes = aligned_ptr, - .len = self.len, - .capacity = self.capacity, - }; - } - - pub fn deinit(self: *Slice, gpa: Allocator) void { - var other = self.toMultiArrayList(); - other.deinit(gpa); - self.* = undefined; - } - - /// This function is used in the debugger pretty formatters in tools/ to fetch the - /// child field order and entry type to facilitate fancy debug printing for this type. - fn dbHelper(self: *Slice, child: *Elem, field: *Field, entry: *Entry) void { - _ = self; - _ = child; - _ = field; - _ = entry; - } - }; - - const Self = @This(); - - const fields = meta.fields(Elem); - /// `sizes.bytes` is an array of @sizeOf each T field. Sorted by alignment, descending. - /// `sizes.fields` is an array mapping from `sizes.bytes` array index to field index. - const sizes = blk: { - const Data = struct { - size: usize, - size_index: usize, - alignment: usize, - }; - var data: [fields.len]Data = undefined; - for (fields, 0..) |field_info, i| { - data[i] = .{ - .size = @sizeOf(field_info.type), - .size_index = i, - .alignment = if (@sizeOf(field_info.type) == 0) 1 else field_info.alignment, - }; - } - const Sort = struct { - fn lessThan(context: void, lhs: Data, rhs: Data) bool { - _ = context; - return lhs.alignment > rhs.alignment; - } - }; - @setEvalBranchQuota(3 * fields.len * std.math.log2(fields.len)); - mem.sort(Data, &data, {}, Sort.lessThan); - var sizes_bytes: [fields.len]usize = undefined; - var field_indexes: [fields.len]usize = undefined; - for (data, 0..) |elem, i| { - sizes_bytes[i] = elem.size; - field_indexes[i] = elem.size_index; - } - break :blk .{ - .bytes = sizes_bytes, - .fields = field_indexes, - }; - }; - - /// Release all allocated memory. - pub fn deinit(self: *Self, gpa: Allocator) void { - self.#allocator.assertEq(gpa); - gpa.free(self.allocatedBytes()); - self.* = undefined; - } - - /// The caller owns the returned memory. Empties this MultiArrayList. - pub fn toOwnedSlice(self: *Self) Slice { - const result = self.slice(); - self.* = .{}; - return result; - } - - /// Compute pointers to the start of each field of the array. - /// If you need to access multiple fields, calling this may - /// be more efficient than calling `items()` multiple times. - pub fn slice(self: Self) Slice { - var result: Slice = .{ - .ptrs = undefined, - .len = self.len, - .capacity = self.capacity, - }; - var ptr: [*]u8 = self.bytes; - for (sizes.bytes, sizes.fields) |field_size, i| { - result.ptrs[i] = ptr; - ptr += field_size * self.capacity; - } - return result; - } - - /// Get the slice of values for a specified field. - /// If you need multiple fields, consider calling slice() - /// instead. - pub fn items(self: Self, comptime field: Field) []FieldType(field) { - return self.slice().items(field); - } - - /// Overwrite one array element with new data. - pub fn set(self: *Self, index: usize, elem: T) void { - var slices = self.slice(); - slices.set(index, elem); - } - - /// Obtain all the data for one array element. - pub fn get(self: Self, index: usize) T { - return self.slice().get(index); - } - - /// Extend the list by 1 element. Allocates more memory as necessary. - pub fn append(self: *Self, gpa: Allocator, elem: T) !void { - self.#allocator.set(gpa); - try self.ensureUnusedCapacity(gpa, 1); - self.appendAssumeCapacity(elem); - } - - /// Extend the list by 1 element, but asserting `self.capacity` - /// is sufficient to hold an additional item. - pub fn appendAssumeCapacity(self: *Self, elem: T) void { - assert(self.len < self.capacity); - self.len += 1; - self.set(self.len - 1, elem); - } - - /// Extend the list by 1 element, returning the newly reserved - /// index with uninitialized data. - /// Allocates more memory as necesasry. - pub fn addOne(self: *Self, allocator: Allocator) Allocator.Error!usize { - self.#allocator.set(allocator); - try self.ensureUnusedCapacity(allocator, 1); - return self.addOneAssumeCapacity(); - } - - /// Extend the list by 1 element, asserting `self.capacity` - /// is sufficient to hold an additional item. Returns the - /// newly reserved index with uninitialized data. - pub fn addOneAssumeCapacity(self: *Self) usize { - assert(self.len < self.capacity); - const index = self.len; - self.len += 1; - return index; - } - - /// Remove and return the last element from the list, or return `null` if list is empty. - /// Invalidates pointers to fields of the removed element. - pub fn pop(self: *Self) ?T { - if (self.len == 0) return null; - const val = self.get(self.len - 1); - self.len -= 1; - return val; - } - - /// Inserts an item into an ordered list. Shifts all elements - /// after and including the specified index back by one and - /// sets the given index to the specified element. May reallocate - /// and invalidate iterators. - pub fn insert(self: *Self, gpa: Allocator, index: usize, elem: T) !void { - self.#allocator.set(gpa); - try self.ensureUnusedCapacity(gpa, 1); - self.insertAssumeCapacity(index, elem); - } - - /// Inserts an item into an ordered list which has room for it. - /// Shifts all elements after and including the specified index - /// back by one and sets the given index to the specified element. - /// Will not reallocate the array, does not invalidate iterators. - pub fn insertAssumeCapacity(self: *Self, index: usize, elem: T) void { - assert(self.len < self.capacity); - assert(index <= self.len); - self.len += 1; - const entry = switch (@typeInfo(T)) { - .@"struct" => elem, - .@"union" => Elem.fromT(elem), - else => unreachable, - }; - const slices = self.slice(); - inline for (fields, 0..) |field_info, field_index| { - const field_slice = slices.items(@as(Field, @enumFromInt(field_index))); - var i: usize = self.len - 1; - while (i > index) : (i -= 1) { - field_slice[i] = field_slice[i - 1]; - } - field_slice[index] = @field(entry, field_info.name); - } - } - - pub fn appendListAssumeCapacity(self: *Self, other: Self) void { - const offset = self.len; - self.len += other.len; - const other_slice = other.slice(); - const this_slice = self.slice(); - inline for (fields, 0..) |field_info, i| { - if (@sizeOf(field_info.type) != 0) { - const field = @as(Field, @enumFromInt(i)); - @memcpy(this_slice.items(field)[offset..], other_slice.items(field)); - } - } - } - - /// Remove the specified item from the list, swapping the last - /// item in the list into its position. Fast, but does not - /// retain list ordering. - pub fn swapRemove(self: *Self, index: usize) void { - const slices = self.slice(); - inline for (fields, 0..) |_, i| { - const field_slice = slices.items(@as(Field, @enumFromInt(i))); - field_slice[index] = field_slice[self.len - 1]; - field_slice[self.len - 1] = undefined; - } - self.len -= 1; - } - - /// Remove the specified item from the list, shifting items - /// after it to preserve order. - pub fn orderedRemove(self: *Self, index: usize) void { - const slices = self.slice(); - inline for (fields, 0..) |_, field_index| { - const field_slice = slices.items(@as(Field, @enumFromInt(field_index))); - var i = index; - while (i < self.len - 1) : (i += 1) { - field_slice[i] = field_slice[i + 1]; - } - field_slice[i] = undefined; - } - self.len -= 1; - } - - /// Adjust the list's length to `new_len`. - /// Does not initialize added items, if any. - pub fn resize(self: *Self, gpa: Allocator, new_len: usize) !void { - self.#allocator.set(gpa); - try self.ensureTotalCapacity(gpa, new_len); - self.len = new_len; - } - - /// Attempt to reduce allocated capacity to `new_len`. - /// If `new_len` is greater than zero, this may fail to reduce the capacity, - /// but the data remains intact and the length is updated to new_len. - pub fn shrinkAndFree(self: *Self, gpa: Allocator, new_len: usize) void { - self.#allocator.set(gpa); - if (new_len == 0) return clearAndFree(self, gpa); - - assert(new_len <= self.capacity); - assert(new_len <= self.len); - - const other_bytes = gpa.alignedAlloc( - u8, - .fromByteUnits(@alignOf(Elem)), - capacityInBytes(new_len), - ) catch { - const self_slice = self.slice(); - inline for (fields, 0..) |field_info, i| { - if (@sizeOf(field_info.type) != 0) { - const field = @as(Field, @enumFromInt(i)); - const dest_slice = self_slice.items(field)[new_len..]; - // We use memset here for more efficient codegen in safety-checked, - // valgrind-enabled builds. Otherwise the valgrind client request - // will be repeated for every element. - @memset(dest_slice, undefined); - } - } - self.len = new_len; - return; - }; - var other = Self{ - .bytes = other_bytes.ptr, - .capacity = new_len, - .len = new_len, - }; - self.len = new_len; - const self_slice = self.slice(); - const other_slice = other.slice(); - inline for (fields, 0..) |field_info, i| { - if (@sizeOf(field_info.type) != 0) { - const field = @as(Field, @enumFromInt(i)); - @memcpy(other_slice.items(field), self_slice.items(field)); - } - } - gpa.free(self.allocatedBytes()); - self.* = other; - } - - pub fn clearAndFree(self: *Self, gpa: Allocator) void { - self.#allocator.set(gpa); - gpa.free(self.allocatedBytes()); - self.* = .{}; - } - - /// Reduce length to `new_len`. - /// Invalidates pointers to elements `items[new_len..]`. - /// Keeps capacity the same. - pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void { - self.len = new_len; - } - - /// Invalidates all element pointers. - pub fn clearRetainingCapacity(self: *Self) void { - self.len = 0; - } - - /// Modify the array so that it can hold at least `new_capacity` items. - /// Implements super-linear growth to achieve amortized O(1) append operations. - /// Invalidates element pointers if additional memory is needed. - pub fn ensureTotalCapacity(self: *Self, gpa: Allocator, new_capacity: usize) Allocator.Error!void { - if (self.capacity >= new_capacity) return; - return self.setCapacity(gpa, growCapacity(self.capacity, new_capacity)); - } - - const init_capacity = init: { - var max = 1; - for (fields) |field| max = @as(comptime_int, @max(max, @sizeOf(field.type))); - break :init @as(comptime_int, @max(1, std.atomic.cache_line / max)); - }; - - /// Called when memory growth is necessary. Returns a capacity larger than - /// minimum that grows super-linearly. - fn growCapacity(current: usize, minimum: usize) usize { - var new = current; - while (true) { - new +|= new / 2 + init_capacity; - if (new >= minimum) - return new; - } - } - - /// Modify the array so that it can hold at least `additional_count` **more** items. - /// Invalidates pointers if additional memory is needed. - pub fn ensureUnusedCapacity(self: *Self, gpa: Allocator, additional_count: usize) !void { - self.#allocator.set(gpa); - return self.ensureTotalCapacity(gpa, self.len + additional_count); - } - - /// Modify the array so that it can hold exactly `new_capacity` items. - /// Invalidates pointers if additional memory is needed. - /// `new_capacity` must be greater or equal to `len`. - pub fn setCapacity(self: *Self, gpa: Allocator, new_capacity: usize) !void { - self.#allocator.set(gpa); - assert(new_capacity >= self.len); - const new_bytes = try gpa.alignedAlloc( - u8, - .fromByteUnits(@alignOf(Elem)), - capacityInBytes(new_capacity), - ); - if (self.len == 0) { - gpa.free(self.allocatedBytes()); - self.bytes = new_bytes.ptr; - self.capacity = new_capacity; - return; - } - var other = Self{ - .bytes = new_bytes.ptr, - .capacity = new_capacity, - .len = self.len, - }; - const self_slice = self.slice(); - const other_slice = other.slice(); - inline for (fields, 0..) |field_info, i| { - if (@sizeOf(field_info.type) != 0) { - const field = @as(Field, @enumFromInt(i)); - @memcpy(other_slice.items(field), self_slice.items(field)); - } - } - gpa.free(self.allocatedBytes()); - self.* = other; - } - - /// Create a copy of this list with a new backing store, - /// using the specified allocator. - pub fn clone(self: Self, gpa: Allocator) !Self { - var result = Self{}; - errdefer result.deinit(gpa); - try result.ensureTotalCapacity(gpa, self.len); - result.len = self.len; - const self_slice = self.slice(); - const result_slice = result.slice(); - inline for (fields, 0..) |field_info, i| { - if (@sizeOf(field_info.type) != 0) { - const field = @as(Field, @enumFromInt(i)); - @memcpy(result_slice.items(field), self_slice.items(field)); - } - } - return result; - } - - /// `ctx` has the following method: - /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` - fn sortInternal(self: Self, a: usize, b: usize, ctx: anytype, comptime mode: std.sort.Mode) void { - const sort_context: struct { - sub_ctx: @TypeOf(ctx), - slice: Slice, - - pub fn swap(sc: @This(), a_index: usize, b_index: usize) void { - inline for (fields, 0..) |field_info, i| { - if (@sizeOf(field_info.type) != 0) { - const field: Field = @enumFromInt(i); - const ptr = sc.slice.items(field); - mem.swap(field_info.type, &ptr[a_index], &ptr[b_index]); - } - } - } - - pub fn lessThan(sc: @This(), a_index: usize, b_index: usize) bool { - return sc.sub_ctx.lessThan(a_index, b_index); - } - } = .{ - .sub_ctx = ctx, - .slice = self.slice(), - }; - - switch (mode) { - .stable => mem.sortContext(a, b, sort_context), - .unstable => mem.sortUnstableContext(a, b, sort_context), - } - } - - /// This function guarantees a stable sort, i.e the relative order of equal elements is preserved during sorting. - /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability - /// If this guarantee does not matter, `sortUnstable` might be a faster alternative. - /// `ctx` has the following method: - /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` - pub fn sort(self: Self, ctx: anytype) void { - self.sortInternal(0, self.len, ctx, .stable); - } - - /// Sorts only the subsection of items between indices `a` and `b` (excluding `b`) - /// This function guarantees a stable sort, i.e the relative order of equal elements is preserved during sorting. - /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability - /// If this guarantee does not matter, `sortSpanUnstable` might be a faster alternative. - /// `ctx` has the following method: - /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` - pub fn sortSpan(self: Self, a: usize, b: usize, ctx: anytype) void { - self.sortInternal(a, b, ctx, .stable); - } - - /// This function does NOT guarantee a stable sort, i.e the relative order of equal elements may change during sorting. - /// Due to the weaker guarantees of this function, this may be faster than the stable `sort` method. - /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability - /// `ctx` has the following method: - /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` - pub fn sortUnstable(self: Self, ctx: anytype) void { - self.sortInternal(0, self.len, ctx, .unstable); - } - - /// Sorts only the subsection of items between indices `a` and `b` (excluding `b`) - /// This function does NOT guarantee a stable sort, i.e the relative order of equal elements may change during sorting. - /// Due to the weaker guarantees of this function, this may be faster than the stable `sortSpan` method. - /// Read more about stable sorting here: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability - /// `ctx` has the following method: - /// `fn lessThan(ctx: @TypeOf(ctx), a_index: usize, b_index: usize) bool` - pub fn sortSpanUnstable(self: Self, a: usize, b: usize, ctx: anytype) void { - self.sortInternal(a, b, ctx, .unstable); - } - - pub fn capacityInBytes(capacity: usize) usize { - comptime var elem_bytes: usize = 0; - inline for (sizes.bytes) |size| elem_bytes += size; - return elem_bytes * capacity; - } - - fn allocatedBytes(self: Self) []align(@alignOf(Elem)) u8 { - return self.bytes[0..capacityInBytes(self.capacity)]; - } - - /// Returns the amount of memory used by this list, in bytes. - pub fn memoryCost(self: Self) usize { - return capacityInBytes(self.capacity); - } - - /// Zero-initialize all allocated memory. - pub fn zero(self: Self) void { - @memset(self.allocatedBytes(), 0); - } - - fn FieldType(comptime field: Field) type { - return @FieldType(Elem, @tagName(field)); - } - - const Entry = entry: { - var entry_fields: [fields.len]std.builtin.Type.StructField = undefined; - for (&entry_fields, sizes.fields) |*entry_field, i| entry_field.* = .{ - .name = fields[i].name ++ "_ptr", - .type = *fields[i].type, - .default_value_ptr = null, - .is_comptime = fields[i].is_comptime, - .alignment = fields[i].alignment, - }; - break :entry @Type(.{ .@"struct" = .{ - .layout = .@"extern", - .fields = &entry_fields, - .decls = &.{}, - .is_tuple = false, - } }); - }; - /// This function is used in the debugger pretty formatters in tools/ to fetch the - /// child field order and entry type to facilitate fancy debug printing for this type. - fn dbHelper(self: *Self, child: *Elem, field: *Field, entry: *Entry) void { - _ = self; - _ = child; - _ = field; - _ = entry; - } - - comptime { - if (builtin.zig_backend == .stage2_llvm and !builtin.strip_debug_info) { - _ = &dbHelper; - _ = &Slice.dbHelper; - } - } - }; -} - -const builtin = @import("builtin"); - -const bun = @import("bun"); -const assert = bun.assert; - -const std = @import("std"); -const meta = std.meta; - -const mem = std.mem; -const Allocator = mem.Allocator; diff --git a/src/collections/pool.zig b/src/collections/pool.zig deleted file mode 100644 index edfce07a6dde..000000000000 --- a/src/collections/pool.zig +++ /dev/null @@ -1,262 +0,0 @@ -fn SinglyLinkedList(comptime T: type, comptime Parent: type) type { - return struct { - const Self = @This(); - - /// Node inside the linked list wrapping the actual data. - pub const Node = struct { - next: ?*Node = null, - allocator: std.mem.Allocator, - data: T, - - pub const Data = T; - - /// Insert a new node after the current one. - /// - /// Arguments: - /// new_node: Pointer to the new node to insert. - pub fn insertAfter(node: *Node, new_node: *Node) void { - new_node.next = node.next; - node.next = new_node; - } - - /// Remove a node from the list. - /// - /// Arguments: - /// node: Pointer to the node to be removed. - /// Returns: - /// node removed - pub fn removeNext(node: *Node) ?*Node { - const next_node = node.next orelse return null; - node.next = next_node.next; - return next_node; - } - - /// Iterate over the singly-linked list from this node, until the final node is found. - /// This operation is O(N). - pub fn findLast(node: *Node) *Node { - var it = node; - while (true) { - it = it.next orelse return it; - } - } - - /// Iterate over each next node, returning the count of all nodes except the starting one. - /// This operation is O(N). - pub fn countChildren(node: *const Node) usize { - var count: usize = 0; - var it: ?*const Node = node.next; - while (it) |n| : (it = n.next) { - count += 1; - } - return count; - } - - pub inline fn release(node: *Node) void { - Parent.release(node); - } - }; - - first: ?*Node = null, - - /// Insert a new node at the head. - /// - /// Arguments: - /// new_node: Pointer to the new node to insert. - pub fn prepend(list: *Self, new_node: *Node) void { - new_node.next = list.first; - list.first = new_node; - } - - /// Remove a node from the list. - /// - /// Arguments: - /// node: Pointer to the node to be removed. - pub fn remove(list: *Self, node: *Node) void { - if (list.first == node) { - list.first = node.next; - } else { - var current_elm = list.first.?; - while (current_elm.next != node) { - current_elm = current_elm.next.?; - } - current_elm.next = node.next; - } - } - - /// Remove and return the first node in the list. - /// - /// Returns: - /// A pointer to the first node in the list. - pub fn popFirst(list: *Self) ?*Node { - const first = list.first orelse return null; - list.first = first.next; - return first; - } - - /// Iterate over all nodes, returning the count. - /// This operation is O(N). - pub fn len(list: Self) usize { - if (list.first) |n| { - return 1 + n.countChildren(); - } else { - return 0; - } - } - }; -} - -const log_allocations = false; - -pub fn ObjectPool( - comptime Type: type, - comptime Init: (?fn (allocator: std.mem.Allocator) anyerror!Type), - comptime threadsafe: bool, - comptime max_count: comptime_int, -) type { - return struct { - const Pool = @This(); - const LinkedList = SinglyLinkedList(Type, Pool); - pub const List = LinkedList; - pub const Node = LinkedList.Node; - const MaxCountInt = std.math.IntFittingRange(0, max_count); - const DataStruct = struct { - list: LinkedList = undefined, - loaded: bool = false, - count: MaxCountInt = 0, - }; - - // We want this to be global - // but we don't want to create 3 global variables per pool - // instead, we create one global variable per pool - const DataStructNonThreadLocal = if (threadsafe) void else DataStruct; - const DataStructThreadLocal = if (!threadsafe) void else DataStruct; - threadlocal var data_threadlocal: DataStructThreadLocal = DataStructThreadLocal{}; - var data__: DataStructNonThreadLocal = DataStructNonThreadLocal{}; - inline fn data() *DataStruct { - if (comptime threadsafe) { - return &data_threadlocal; - } - - if (comptime !threadsafe) { - return &data__; - } - - unreachable; - } - - pub fn full() bool { - if (comptime max_count == 0) return false; - return data().loaded and data().count >= max_count; - } - - pub fn has() bool { - return data().loaded and data().list.first != null; - } - - pub fn push(allocator: std.mem.Allocator, pooled: Type) void { - if (comptime @import("../bun_core/env.zig").allow_assert) - bun.assert(!full()); - - const new_node = allocator.create(LinkedList.Node) catch unreachable; - new_node.* = LinkedList.Node{ - .allocator = allocator, - .data = pooled, - }; - release(new_node); - } - - pub fn getIfExists() ?*LinkedList.Node { - if (!data().loaded) { - return null; - } - - var node = data().list.popFirst() orelse return null; - if (std.meta.hasFn(Type, "reset")) node.data.reset(); - if (comptime max_count > 0) data().count -|= 1; - - return node; - } - - pub fn first(allocator: std.mem.Allocator) *Type { - return &get(allocator).data; - } - - pub fn get(allocator: std.mem.Allocator) *LinkedList.Node { - if (data().loaded) { - if (data().list.popFirst()) |node| { - if (comptime std.meta.hasFn(Type, "reset")) node.data.reset(); - if (comptime max_count > 0) data().count -|= 1; - return node; - } - } - - if (comptime log_allocations) std.fs.File.stderr().writeAll(comptime std.fmt.comptimePrint("Allocate {s} - {d} bytes\n", .{ @typeName(Type), @sizeOf(Type) })) catch {}; - - const new_node = allocator.create(LinkedList.Node) catch unreachable; - new_node.* = LinkedList.Node{ - .allocator = allocator, - .data = if (comptime Init) |init_| - (init_( - allocator, - ) catch unreachable) - else - undefined, - }; - - return new_node; - } - - pub fn releaseValue(value: *Type) void { - @as(*LinkedList.Node, @fieldParentPtr("data", value)).release(); - } - - pub fn release(node: *LinkedList.Node) void { - if (comptime max_count > 0) { - if (data().count >= max_count) { - if (comptime log_allocations) std.fs.File.stderr().writeAll(comptime std.fmt.comptimePrint("Free {s} - {d} bytes\n", .{ @typeName(Type), @sizeOf(Type) })) catch {}; - destroyNode(node); - return; - } - } - - if (comptime max_count > 0) data().count +|= 1; - - if (data().loaded) { - data().list.prepend(node); - return; - } - - data().list = LinkedList{ .first = node }; - data().loaded = true; - } - - pub fn deleteAll() void { - var dat = data(); - if (!dat.loaded) { - return; - } - dat.loaded = false; - dat.count = 0; - var next = dat.list.first; - dat.list.first = null; - while (next) |node| { - next = node.next; - destroyNode(node); - } - } - - fn destroyNode(node: *LinkedList.Node) void { - // TODO: Once a generic-allocator version of `BabyList` is added, change - // `ByteListPool` in `bun.js/webcore.zig` to use a managed default-allocator - // `ByteList` instead, and then get rid of the special-casing for `ByteList` - // here. This will fix a memory leak. - if (comptime Type != bun.ByteList) { - bun.memory.deinit(&node.data); - } - node.allocator.destroy(node); - } - }; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/crash_handler/CPUFeatures.zig b/src/crash_handler/CPUFeatures.zig deleted file mode 100644 index 29e4a6e04028..000000000000 --- a/src/crash_handler/CPUFeatures.zig +++ /dev/null @@ -1,71 +0,0 @@ -const CPUFeatures = @This(); - -flags: Flags, - -extern "c" fn bun_cpu_features() u8; - -pub const Flags = switch (@import("builtin").cpu.arch) { - .x86_64 => packed struct(u8) { - none: bool, - - sse42: bool, - popcnt: bool, - avx: bool, - avx2: bool, - avx512: bool, - - padding: u2 = 0, - }, - .aarch64 => packed struct(u8) { - none: bool, - - neon: bool, - fp: bool, - aes: bool, - crc32: bool, - atomics: bool, - sve: bool, - - padding: u1 = 0, - }, - else => unreachable, -}; - -pub fn format(features: @This(), writer: *std.Io.Writer) !void { - var is_first = true; - inline for (@typeInfo(Flags).@"struct".fields) |field| brk: { - if (comptime (bun.strings.eql(field.name, "padding") or - bun.strings.eql(field.name, "none"))) - break :brk; - - if (@field(features.flags, field.name)) { - if (!is_first) - try writer.writeAll(" "); - is_first = false; - try writer.writeAll(field.name); - } - } -} - -pub fn isEmpty(features: CPUFeatures) bool { - return @as(u8, @bitCast(features.flags)) == 0; -} - -pub fn hasAnyAVX(features: CPUFeatures) bool { - return features.flags.avx or features.flags.avx2 or features.flags.avx512; -} - -pub fn get() CPUFeatures { - const flags: Flags = @bitCast(bun_cpu_features()); - bun.debugAssert(flags.none == false and flags.padding == 0); // sanity check - - if (bun.Environment.isX64) { - bun.analytics.Features.no_avx += @as(usize, @intFromBool(!flags.avx)); - bun.analytics.Features.no_avx2 += @as(usize, @intFromBool(!flags.avx2)); - } - - return .{ .flags = flags }; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/crash_handler/crash_handler.zig b/src/crash_handler/crash_handler.zig deleted file mode 100644 index f641d38adbb3..000000000000 --- a/src/crash_handler/crash_handler.zig +++ /dev/null @@ -1,2263 +0,0 @@ -//! This file contains Bun's crash handler. In debug builds, we are able to -//! print backtraces that are mapped to source code. In release builds, we do -//! not have debug symbols in the binary. Bun's solution to this is called -//! a "trace string", a url with compressed encoding of the captured -//! backtrace. Version 1 trace strings contain the following information: -//! -//! - What version and commit of Bun captured the backtrace. -//! - The platform the backtrace was captured on. -//! - The list of addresses with ASLR removed, ready to be remapped. -//! - If panicking, the message that was panicked with. -//! -//! These can be demangled using Bun's remapping API, which has cached -//! versions of all debug symbols for all versions of Bun. Hosting this keeps -//! users from having to download symbols, which can be very large. -//! -//! The remapper is open source: https://github.com/oven-sh/bun.report -//! -//! A lot of this handler is based on the Zig Standard Library implementation -//! for std.debug.panicImpl and their code for gathering backtraces. - -/// Set this to false if you want to disable all uses of this panic handler. -/// This is useful for testing as a crash in here will not 'panicked during a panic'. -pub const enable = true; - -/// Overridable with BUN_CRASH_REPORT_URL environment variable. -const default_report_base_url = "https://bun.report"; - -/// Only print the `Bun has crashed` message once. Once this is true, control -/// flow is not returned to the main application. -var has_printed_message = false; - -/// Non-zero whenever the program triggered a panic. -/// The counter is incremented/decremented atomically. -var panicking = std.atomic.Value(u8).init(0); - -// Locked to avoid interleaving panic messages from multiple threads. -// TODO: I don't think it's safe to lock/unlock a mutex inside a signal handler. -var panic_mutex = bun.Mutex{}; - -/// Counts how many times the panic handler is invoked by this thread. -/// This is used to catch and handle panics triggered by the panic handler. -threadlocal var panic_stage: usize = 0; - -threadlocal var inside_native_plugin: ?[*:0]const u8 = null; -threadlocal var unsupported_uv_function: ?[*:0]const u8 = null; - -/// This can be set by various parts of the codebase to indicate a broader -/// action being taken. It is printed when a crash happens, which can help -/// narrow down what the bug is. Example: "Crashed while parsing /path/to/file.js" -/// -/// Some of these are enabled in release builds, which may encourage users to -/// attach the affected files to crash report. Others, which may have low crash -/// rate or only crash due to assertion failures, are debug-only. See `Action`. -pub threadlocal var current_action: ?Action = null; - -var before_crash_handlers: std.ArrayListUnmanaged(struct { *anyopaque, *const OnBeforeCrash }) = .{}; - -var before_crash_handlers_mutex: bun.Mutex = .{}; - -/// Prevents crash reports from being uploaded to any server. Reports will still be printed and -/// abort the process. Overrides BUN_CRASH_REPORT_URL, BUN_ENABLE_CRASH_REPORTING, and all other -/// things that affect crash reporting. See suppressReporting() for intended usage. -var suppress_reporting: bool = false; - -/// This structure and formatter must be kept in sync with `bun.report`'s decoder implementation. -pub const CrashReason = union(enum) { - /// From @panic() - panic: []const u8, - - /// "reached unreachable code" - @"unreachable", - - segmentation_fault: usize, - illegal_instruction: usize, - - /// Posix-only - bus_error: usize, - /// Posix-only - floating_point_error: usize, - /// Windows-only - datatype_misalignment, - /// Windows-only - stack_overflow, - - /// Either `main` returned an error, or somewhere else in the code a trace string is printed. - zig_error: anyerror, - - out_of_memory, - - pub fn format(reason: CrashReason, writer: *std.Io.Writer) !void { - switch (reason) { - .panic => |message| try writer.print("{s}", .{message}), - .@"unreachable" => try writer.writeAll("reached unreachable code"), - .segmentation_fault => |addr| try writer.print("Segmentation fault at address 0x{X}", .{addr}), - .illegal_instruction => |addr| try writer.print("Illegal instruction at address 0x{X}", .{addr}), - .bus_error => |addr| try writer.print("Bus error at address 0x{X}", .{addr}), - .floating_point_error => |addr| try writer.print("Floating point error at address 0x{X}", .{addr}), - .datatype_misalignment => try writer.writeAll("Unaligned memory access"), - .stack_overflow => try writer.writeAll("Stack overflow"), - .zig_error => |err| try writer.print("error.{s}", .{@errorName(err)}), - .out_of_memory => try writer.writeAll("Bun ran out of memory"), - } - } -}; - -pub const Action = union(enum) { - parse: []const u8, - visit: []const u8, - print: []const u8, - - /// bun.bundle_v2.LinkerContext.generateCompileResultForJSChunk - bundle_generate_chunk: if (bun.Environment.show_crash_trace) struct { - context: *const anyopaque, // unfortunate dependency loop workaround - chunk: *const bun.bundle_v2.Chunk, - part_range: *const bun.bundle_v2.PartRange, - - pub fn linkerContext(data: *const @This()) *const bun.bundle_v2.LinkerContext { - return @ptrCast(@alignCast(data.context)); - } - } else void, - - resolver: if (bun.Environment.show_crash_trace) struct { - source_dir: []const u8, - import_path: []const u8, - kind: bun.ImportKind, - } else void, - - dlopen: []const u8, - - pub fn format(act: Action, writer: *std.Io.Writer) !void { - switch (act) { - .parse => |path| try writer.print("parsing {s}", .{path}), - .visit => |path| try writer.print("visiting {s}", .{path}), - .print => |path| try writer.print("printing {s}", .{path}), - .bundle_generate_chunk => |data| if (bun.Environment.show_crash_trace) { - try writer.print( - \\generating bundler chunk - \\ chunk entry point: {?s} - \\ source: {?s} - \\ part range: {d}..{d} - , - .{ - if (data.part_range.source_index.isValid()) data.linkerContext().parse_graph.input_files - .items(.source)[data.chunk.entry_point.source_index] - .path.text else null, - if (data.part_range.source_index.isValid()) data.linkerContext().parse_graph.input_files - .items(.source)[data.part_range.source_index.get()] - .path.text else null, - data.part_range.part_index_begin, - data.part_range.part_index_end, - }, - ); - }, - .resolver => |res| if (bun.Environment.show_crash_trace) { - try writer.print("resolving {s} from {s} ({s})", .{ - res.import_path, - res.source_dir, - res.kind.label(), - }); - }, - .dlopen => |path| try writer.print("loading native module: {s}", .{path}), - } - } -}; - -fn captureLibcBacktrace(begin_addr: usize, stack_trace: *std.builtin.StackTrace) void { - const backtrace = struct { - extern "c" fn backtrace(buffer: [*]*anyopaque, size: c_int) c_int; - }.backtrace; - - const addrs = stack_trace.instruction_addresses; - const count = backtrace(@ptrCast(addrs), @intCast(addrs.len)); - stack_trace.index = @intCast(count); - - // Skip frames until we find begin_addr (or close to it) - // backtrace() captures everything including crash handler frames - const tolerance: usize = 128; - const skip: usize = for (addrs[0..stack_trace.index], 0..) |addr, i| { - // Check if this address is close to begin_addr (within tolerance) - const delta = if (addr >= begin_addr) - addr - begin_addr - else - begin_addr - addr; - if (delta <= tolerance) break i; - // Give up searching after 8 frames - if (i >= 8) break 0; - } else 0; - - // Shift the addresses to skip crash handler frames - // If begin_addr was not found, use the complete backtrace - if (skip > 0) { - std.mem.copyForwards(usize, addrs, addrs[skip..stack_trace.index]); - stack_trace.index -= skip; - } -} - -/// This function is invoked when a crash happens. A crash is classified in `CrashReason`. -pub fn crashHandler( - reason: CrashReason, - // TODO: if both of these are specified, what is supposed to happen? - error_return_trace: ?*std.builtin.StackTrace, - begin_addr: ?usize, -) noreturn { - @branchHint(.cold); - - if (bun.Environment.isDebug) - bun.Output.disableScopedDebugWriter(); - - var trace_str_buf = bun.BoundedArray(u8, 1024){}; - - nosuspend switch (panic_stage) { - 0 => { - bun.maybeHandlePanicDuringProcessReload(); - - panic_stage = 1; - _ = panicking.fetchAdd(1, .seq_cst); - - if (before_crash_handlers_mutex.tryLock()) { - for (before_crash_handlers.items) |item| { - const ptr, const cb = item; - cb(ptr); - } - } - - { - panic_mutex.lock(); - defer panic_mutex.unlock(); - - // Use an raw unbuffered writer to stderr to avoid losing information on - // panic in a panic. There is also a possibility that `Output` related code - // is not configured correctly, so that would also mask the message. - // - // Output.errorWriter() is not used here because it may not be configured - // if the program crashes immediately at startup. - var writer_w = std.fs.File.stderr().writerStreaming(&.{}); - const writer = &writer_w.interface; - - // The format of the panic trace is slightly different in debug - // builds. Mainly, we demangle the backtrace immediately instead - // of using a trace string. - // - // To make the release-mode behavior easier to demo, debug mode - // checks for this CLI flag. - const debug_trace = bun.Environment.show_crash_trace and check_flag: { - for (bun.argv) |arg| { - if (bun.strings.eqlComptime(arg, "--debug-crash-handler-use-trace-string")) { - break :check_flag false; - } - } - // Act like release build when explicitly enabling reporting - if (isReportingEnabled()) break :check_flag false; - - break :check_flag true; - }; - - if (!has_printed_message) { - Output.flush(); - Output.Source.Stdio.restore(); - - writer.writeAll("=" ** 60 ++ "\n") catch std.posix.abort(); - printMetadata(writer) catch std.posix.abort(); - - if (inside_native_plugin) |name| { - const native_plugin_name = name; - const fmt = - \\ - \\Bun has encountered a crash while running the "{s}" native plugin. - \\ - \\This indicates either a bug in the native plugin or in Bun. - \\ - ; - writer.print(Output.prettyFmt(fmt, true), .{native_plugin_name}) catch std.posix.abort(); - } else if (bun.analytics.Features.unsupported_uv_function > 0) { - const name = unsupported_uv_function orelse ""; - const fmt = - \\Bun encountered a crash when running a NAPI module that tried to call - \\the {s} libuv function. - \\ - \\Bun is actively working on supporting all libuv functions for POSIX - \\systems, please see this issue to track our progress: - \\ - \\https://github.com/oven-sh/bun/issues/18546 - \\ - \\ - ; - writer.print(Output.prettyFmt(fmt, true), .{name}) catch std.posix.abort(); - has_printed_message = true; - } - } else { - if (Output.enable_ansi_colors_stderr) { - writer.writeAll(Output.prettyFmt("", true)) catch std.posix.abort(); - } - writer.writeAll("oh no") catch std.posix.abort(); - if (Output.enable_ansi_colors_stderr) { - writer.writeAll(Output.prettyFmt(": multiple threads are crashing\n", true)) catch std.posix.abort(); - } else { - writer.writeAll(Output.prettyFmt(": multiple threads are crashing\n", true)) catch std.posix.abort(); - } - } - - if (reason != .out_of_memory or debug_trace) { - if (Output.enable_ansi_colors_stderr) { - writer.writeAll(Output.prettyFmt("", true)) catch std.posix.abort(); - } - - writer.writeAll("panic") catch std.posix.abort(); - - if (Output.enable_ansi_colors_stderr) { - writer.writeAll(Output.prettyFmt("", true)) catch std.posix.abort(); - } - - if (bun.cli.Cli.is_main_thread) { - writer.writeAll("(main thread)") catch std.posix.abort(); - } else switch (bun.Environment.os) { - .windows => { - var name: std.os.windows.PWSTR = undefined; - const result = bun.windows.GetThreadDescription(bun.windows.GetCurrentThread(), &name); - if (std.os.windows.HRESULT_CODE(result) == .SUCCESS and name[0] != 0) { - writer.print("({f})", .{bun.fmt.utf16(bun.span(name))}) catch std.posix.abort(); - } else { - writer.print("(thread {d})", .{bun.c.GetCurrentThreadId()}) catch std.posix.abort(); - } - }, - .mac, .linux, .freebsd => {}, - .wasm => @compileError("TODO"), - } - - writer.writeAll(": ") catch std.posix.abort(); - if (Output.enable_ansi_colors_stderr) { - writer.writeAll(Output.prettyFmt("", true)) catch std.posix.abort(); - } - writer.print("{f}\n", .{reason}) catch std.posix.abort(); - } - - if (current_action) |action| { - writer.print("Crashed while {f}\n", .{action}) catch std.posix.abort(); - } - - var addr_buf: [20]usize = undefined; - var trace_buf: std.builtin.StackTrace = undefined; - - // If a trace was not provided, compute one now - const trace = blk: { - if (error_return_trace) |ert| { - if (ert.index > 0) break :blk ert; - } - trace_buf = std.builtin.StackTrace{ - .index = 0, - .instruction_addresses = &addr_buf, - }; - const desired_begin_addr = begin_addr orelse @returnAddress(); - std.debug.captureStackTrace(desired_begin_addr, &trace_buf); - - if (comptime bun.Environment.isGlibc) { - var addr_buf_libc: [20]usize = undefined; - var trace_buf_libc: std.builtin.StackTrace = .{ - .index = 0, - .instruction_addresses = &addr_buf_libc, - }; - captureLibcBacktrace(desired_begin_addr, &trace_buf_libc); - // Use stack trace from glibc's backtrace() if it has more frames - if (trace_buf_libc.index > trace_buf.index) { - addr_buf = addr_buf_libc; - trace_buf.index = trace_buf_libc.index; - } - } - break :blk &trace_buf; - }; - - if (debug_trace) { - has_printed_message = true; - - dumpStackTrace(trace.*, .{}); - - trace_str_buf.writer().print("{f}", .{TraceString{ - .trace = trace, - .reason = reason, - .action = .view_trace, - }}) catch std.posix.abort(); - } else { - if (!has_printed_message) { - has_printed_message = true; - writer.writeAll("oh no") catch std.posix.abort(); - if (Output.enable_ansi_colors_stderr) { - writer.writeAll(Output.prettyFmt(": ", true)) catch std.posix.abort(); - } else { - writer.writeAll(Output.prettyFmt(": ", true)) catch std.posix.abort(); - } - if (inside_native_plugin) |name| { - const native_plugin_name = name; - writer.print(Output.prettyFmt( - \\Bun has encountered a crash while running the "{s}" native plugin. - \\ - \\To send a redacted crash report to Bun's team, - \\please file a GitHub issue using the link below: - \\ - \\ - , true), .{native_plugin_name}) catch std.posix.abort(); - } else if (bun.analytics.Features.unsupported_uv_function > 0) { - const name = unsupported_uv_function orelse ""; - const fmt = - \\Bun encountered a crash when running a NAPI module that tried to call - \\the {s} libuv function. - \\ - \\Bun is actively working on supporting all libuv functions for POSIX - \\systems, please see this issue to track our progress: - \\ - \\https://github.com/oven-sh/bun/issues/18546 - \\ - \\ - ; - writer.print(Output.prettyFmt(fmt, true), .{name}) catch std.posix.abort(); - } else if (reason == .out_of_memory) { - writer.writeAll( - \\Bun has run out of memory. - \\ - \\To send a redacted crash report to Bun's team, - \\please file a GitHub issue using the link below: - \\ - \\ - ) catch std.posix.abort(); - } else { - writer.writeAll( - \\Bun has crashed. This indicates a bug in Bun, not your code. - \\ - \\To send a redacted crash report to Bun's team, - \\please file a GitHub issue using the link below: - \\ - \\ - ) catch std.posix.abort(); - } - } - - if (Output.enable_ansi_colors_stderr) { - writer.print(Output.prettyFmt("", true), .{}) catch std.posix.abort(); - } - - writer.writeAll(" ") catch std.posix.abort(); - - trace_str_buf.writer().print("{f}", .{TraceString{ - .trace = trace, - .reason = reason, - .action = .open_issue, - }}) catch std.posix.abort(); - - writer.writeAll(trace_str_buf.slice()) catch std.posix.abort(); - - writer.writeAll("\n") catch std.posix.abort(); - } - - if (Output.enable_ansi_colors_stderr) { - writer.writeAll(Output.prettyFmt("\n", true)) catch std.posix.abort(); - } else { - writer.writeAll("\n") catch std.posix.abort(); - } - } - - // Be aware that this function only lets one thread return from it. - // This is important so that we do not try to run the following reload logic twice. - waitForOtherThreadToFinishPanicking(); - - report(trace_str_buf.slice()); - - // At this point, the crash handler has performed it's job. Reset the segfault handler - // so that a crash will actually crash. We need this because we want the process to - // exit with a signal, and allow tools to be able to gather core dumps. - // - // This is done so late (in comparison to the Zig Standard Library's panic handler) - // because if multiple threads segfault (more often the case on Windows), we don't - // want another thread to interrupt the crashing of the first one. - resetSegfaultHandler(); - - if (bun.auto_reload_on_crash and - // Do not reload if the panic arose FROM the reload function. - !bun.isProcessReloadInProgressOnAnotherThread()) - { - // attempt to prevent a double panic - bun.auto_reload_on_crash = false; - - Output.prettyErrorln("--- Bun is auto-restarting due to crash [time: {d}] ---", .{ - @max(std.time.milliTimestamp(), 0), - }); - Output.flush(); - - comptime bun.assert(void == @TypeOf(bun.reloadProcess(bun.default_allocator, false, true))); - bun.reloadProcess(bun.default_allocator, false, true); - } - }, - inline 1, 2 => |t| { - if (t == 1) { - panic_stage = 2; - - resetSegfaultHandler(); - Output.flush(); - } - panic_stage = 3; - - // A panic happened while trying to print a previous panic message, - // we're still holding the mutex but that's fine as we're going to - // call abort() - var stderr_w = std.fs.File.stderr().writerStreaming(&.{}); - const stderr = &stderr_w.interface; - stderr.print("\npanic: {f}\n", .{reason}) catch std.posix.abort(); - stderr.print("panicked during a panic. Aborting.\n", .{}) catch std.posix.abort(); - }, - 3 => { - // Panicked while printing "Panicked during a panic." - panic_stage = 4; - }, - else => { - // Panicked or otherwise looped into the panic handler while trying to exit. - std.posix.abort(); - }, - }; - - crash(); -} - -/// This is called when `main` returns a Zig error. -/// We don't want to treat it as a crash under certain error codes. -pub fn handleRootError(err: anyerror, error_return_trace: ?*std.builtin.StackTrace) noreturn { - var show_trace = bun.Environment.show_crash_trace; - - switch (err) { - error.OutOfMemory => bun.outOfMemory(), - - error.InvalidArgument, - error.@"Invalid Bunfig", - error.InstallFailed, - => if (!show_trace) Global.exit(1), - - error.SyntaxError => { - Output.err("SyntaxError", "An error occurred while parsing code", .{}); - }, - - error.CurrentWorkingDirectoryUnlinked => { - Output.errGeneric( - "The current working directory was deleted, so that command didn't work. Please cd into a different directory and try again.", - .{}, - ); - }, - - error.SystemFdQuotaExceeded => { - if (comptime bun.Environment.isPosix) { - const limit = if (std.posix.getrlimit(.NOFILE)) |limit| limit.cur else |_| null; - if (comptime bun.Environment.isMac) { - Output.prettyError( - \\error: Your computer ran out of file descriptors (SystemFdQuotaExceeded) - \\ - \\Current limit: {f} - \\ - \\To fix this, try running: - \\ - \\ sudo launchctl limit maxfiles 2147483646 - \\ ulimit -n 2147483646 - \\ - \\That will only work until you reboot. - \\ - , - .{ - bun.fmt.nullableFallback(limit, ""), - }, - ); - } else if (comptime bun.Environment.isFreeBSD) { - Output.prettyError( - \\ - \\error: Your computer ran out of file descriptors (SystemFdQuotaExceeded) - \\ - \\Current limit: {f} - \\ - \\To fix this, try running: - \\ - \\ sudo sysctl kern.maxfiles=2147483646 kern.maxfilesperproc=2147483646 - \\ ulimit -n 2147483646 - \\ - \\To persist across reboots, add to /etc/sysctl.conf and edit /etc/login.conf. - \\ - , - .{ - bun.fmt.nullableFallback(limit, ""), - }, - ); - } else { - Output.prettyError( - \\ - \\error: Your computer ran out of file descriptors (SystemFdQuotaExceeded) - \\ - \\Current limit: {f} - \\ - \\To fix this, try running: - \\ - \\ sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf - \\ sudo sysctl -p - \\ ulimit -n 2147483646 - \\ - , - .{ - bun.fmt.nullableFallback(limit, ""), - }, - ); - - if (bun.env_var.USER.get()) |user| { - if (user.len > 0) { - Output.prettyError( - \\ - \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: - \\ - \\ {s} soft nofile 2147483646 - \\ {s} hard nofile 2147483646 - \\ - , - .{ user, user }, - ); - } - } - } - } else { - Output.prettyError( - \\error: Your computer ran out of file descriptors (SystemFdQuotaExceeded) - , - .{}, - ); - } - }, - - error.ProcessFdQuotaExceeded => { - if (comptime bun.Environment.isPosix) { - const limit = if (std.posix.getrlimit(.NOFILE)) |limit| limit.cur else |_| null; - if (comptime bun.Environment.isMac) { - Output.prettyError( - \\ - \\error: bun ran out of file descriptors (ProcessFdQuotaExceeded) - \\ - \\Current limit: {f} - \\ - \\To fix this, try running: - \\ - \\ ulimit -n 2147483646 - \\ - \\You may also need to run: - \\ - \\ sudo launchctl limit maxfiles 2147483646 - \\ - , - .{ - bun.fmt.nullableFallback(limit, ""), - }, - ); - } else if (comptime bun.Environment.isFreeBSD) { - Output.prettyError( - \\ - \\error: bun ran out of file descriptors (ProcessFdQuotaExceeded) - \\ - \\Current limit: {f} - \\ - \\To fix this, try running: - \\ - \\ ulimit -n 2147483646 - \\ sudo sysctl kern.maxfilesperproc=2147483646 - \\ - , - .{ - bun.fmt.nullableFallback(limit, ""), - }, - ); - } else { - Output.prettyError( - \\ - \\error: bun ran out of file descriptors (ProcessFdQuotaExceeded) - \\ - \\Current limit: {f} - \\ - \\To fix this, try running: - \\ - \\ ulimit -n 2147483646 - \\ - \\That will only work for the current shell. To fix this for the entire system, run: - \\ - \\ sudo echo -e "\nfs.file-max=2147483646\n" >> /etc/sysctl.conf - \\ sudo sysctl -p - \\ - , - .{ - bun.fmt.nullableFallback(limit, ""), - }, - ); - - if (bun.env_var.USER.get()) |user| { - if (user.len > 0) { - Output.prettyError( - \\ - \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: - \\ - \\ {s} soft nofile 2147483646 - \\ {s} hard nofile 2147483646 - \\ - , - .{ user, user }, - ); - } - } - } - } else { - Output.prettyErrorln( - \\error: bun ran out of file descriptors (ProcessFdQuotaExceeded) - , - .{}, - ); - } - }, - - // The usage of `unreachable` in Zig's std.posix may cause the file descriptor problem to show up as other errors - error.NotOpenForReading, error.Unexpected => { - if (comptime bun.Environment.isPosix) { - const limit = std.posix.getrlimit(.NOFILE) catch std.mem.zeroes(std.posix.rlimit); - - if (limit.cur > 0 and limit.cur < (8192 * 2)) { - Output.prettyError( - \\ - \\error: An unknown error occurred, possibly due to low max file descriptors (Unexpected) - \\ - \\Current limit: {d} - \\ - \\To fix this, try running: - \\ - \\ ulimit -n 2147483646 - \\ - , - .{ - limit.cur, - }, - ); - - if (bun.Environment.isLinux) { - if (bun.env_var.USER.get()) |user| { - if (user.len > 0) { - Output.prettyError( - \\ - \\If that still doesn't work, you may need to add these lines to /etc/security/limits.conf: - \\ - \\ {s} soft nofile 2147483646 - \\ {s} hard nofile 2147483646 - \\ - , - .{ - user, - user, - }, - ); - } - } - } else if (bun.Environment.isMac) { - Output.prettyError( - \\ - \\If that still doesn't work, you may need to run: - \\ - \\ sudo launchctl limit maxfiles 2147483646 - \\ - , - .{}, - ); - } - } else { - Output.errGeneric( - "An unknown error occurred ({s})", - .{@errorName(err)}, - ); - show_trace = true; - } - } else { - Output.errGeneric( - \\An unknown error occurred ({s}) - , - .{@errorName(err)}, - ); - show_trace = true; - } - }, - - error.ENOENT, error.FileNotFound => { - Output.err( - "ENOENT", - "Bun could not find a file, and the code that produces this error is missing a better error.", - .{}, - ); - }, - - error.MissingPackageJSON => { - Output.errGeneric( - "Bun could not find a package.json file to install from", - .{}, - ); - Output.note("Run \"bun init\" to initialize a project", .{}); - }, - - else => { - Output.errGeneric( - if (bun.Environment.show_crash_trace) - "'main' returned error.{s}" - else - "An internal error occurred ({s})", - .{@errorName(err)}, - ); - show_trace = true; - }, - } - - if (show_trace) { - verbose_error_trace = show_trace; - handleErrorReturnTraceExtra(err, error_return_trace, true); - } - - Global.exit(1); -} - -pub fn panicImpl(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, begin_addr: ?usize) noreturn { - @branchHint(.cold); - crashHandler( - if (bun.strings.eqlComptime(msg, "reached unreachable code")) - .{ .@"unreachable" = {} } - else - .{ .panic = msg }, - error_return_trace, - begin_addr orelse @returnAddress(), - ); -} - -fn panicBuiltin(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace, begin_addr: ?usize) noreturn { - std.debug.panicImpl(error_return_trace, begin_addr, msg); -} - -pub const panic = if (enable) panicImpl else panicBuiltin; - -pub fn reportBaseUrl() []const u8 { - const static = struct { - var base_url: ?[]const u8 = null; - }; - return static.base_url orelse { - const computed = computed: { - if (bun.env_var.BUN_CRASH_REPORT_URL.get()) |url| { - break :computed bun.strings.withoutTrailingSlash(url); - } - break :computed default_report_base_url; - }; - static.base_url = computed; - return computed; - }; -} - -const arch_display_string = if (bun.Environment.isAarch64) - if (bun.Environment.isMac) "Silicon" else "arm64" -else - "x64"; - -const metadata_version_line = std.fmt.comptimePrint( - "Bun {s}v{s} {s} {s}{s}\n", - .{ - if (bun.Environment.isDebug) "Debug " else if (bun.Environment.is_canary) "Canary " else "", - Global.package_json_version_with_sha, - bun.Environment.os.displayString(), - arch_display_string, - if (bun.Environment.baseline) " (baseline)" else "", - }, -); - -fn handleSegfaultPosix(sig: i32, info: *const std.posix.siginfo_t, _: ?*const anyopaque) callconv(.c) noreturn { - const addr = switch (bun.Environment.os) { - .linux => @intFromPtr(info.fields.sigfault.addr), - .mac, .freebsd => @intFromPtr(info.addr), - .windows, .wasm => @compileError("unreachable"), - }; - - crashHandler( - switch (sig) { - std.posix.SIG.SEGV => .{ .segmentation_fault = addr }, - std.posix.SIG.ILL => .{ .illegal_instruction = addr }, - std.posix.SIG.BUS => .{ .bus_error = addr }, - std.posix.SIG.FPE => .{ .floating_point_error = addr }, - - // we do not register this handler for other signals - else => unreachable, - }, - null, - @returnAddress(), - ); -} - -var did_register_sigaltstack = false; -var sigaltstack: [512 * 1024]u8 = undefined; - -fn updatePosixSegfaultHandler(act: ?*bun.sys.Sigaction) !void { - if (act) |act_| { - if (!did_register_sigaltstack) { - var stack: std.c.stack_t = .{ - .flags = 0, - .size = sigaltstack.len, - .sp = &sigaltstack, - }; - - if (std.c.sigaltstack(&stack, null) == 0) { - act_.flags |= std.posix.SA.ONSTACK; - did_register_sigaltstack = true; - } - } - } - - bun.sys.sigaction(std.posix.SIG.SEGV, act, null); - bun.sys.sigaction(std.posix.SIG.ILL, act, null); - bun.sys.sigaction(std.posix.SIG.BUS, act, null); - bun.sys.sigaction(std.posix.SIG.FPE, act, null); -} - -var windows_segfault_handle: ?windows.HANDLE = null; - -pub fn resetOnPosix() void { - if (bun.Environment.enable_asan) return; - var act = bun.sys.Sigaction{ - .handler = .{ .sigaction = handleSegfaultPosix }, - .mask = bun.sys.sigemptyset(), - .flags = (std.posix.SA.SIGINFO | std.posix.SA.RESTART | std.posix.SA.RESETHAND), - }; - updatePosixSegfaultHandler(&act) catch {}; -} - -pub fn init() void { - if (!enable) return; - switch (bun.Environment.os) { - .windows => { - windows_segfault_handle = windows.kernel32.AddVectoredExceptionHandler(0, handleSegfaultWindows); - }, - .mac, .linux, .freebsd => { - resetOnPosix(); - }, - .wasm => @compileError("TODO"), - } -} - -pub fn resetSegfaultHandler() void { - if (!enable) return; - if (bun.Environment.enable_asan) return; - - if (bun.Environment.os == .windows) { - if (windows_segfault_handle) |handle| { - const rc = windows.kernel32.RemoveVectoredExceptionHandler(handle); - windows_segfault_handle = null; - bun.assert(rc != 0); - } - return; - } - - var act = bun.sys.Sigaction{ - .handler = .{ .handler = std.posix.SIG.DFL }, - .mask = bun.sys.sigemptyset(), - .flags = 0, - }; - // To avoid a double-panic, do nothing if an error happens here. - updatePosixSegfaultHandler(&act) catch {}; -} - -pub fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) callconv(.winapi) c_long { - crashHandler( - switch (info.ExceptionRecord.ExceptionCode) { - windows.EXCEPTION_DATATYPE_MISALIGNMENT => .{ .datatype_misalignment = {} }, - windows.EXCEPTION_ACCESS_VIOLATION => .{ .segmentation_fault = info.ExceptionRecord.ExceptionInformation[1] }, - windows.EXCEPTION_ILLEGAL_INSTRUCTION => .{ .illegal_instruction = info.ContextRecord.getRegs().ip }, - windows.EXCEPTION_STACK_OVERFLOW => .{ .stack_overflow = {} }, - - // exception used for thread naming - // https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2017/debugger/how-to-set-a-thread-name-in-native-code?view=vs-2017#set-a-thread-name-by-throwing-an-exception - // related commit - // https://github.com/go-delve/delve/pull/1384 - bun.windows.MS_VC_EXCEPTION => return bun.windows.EXCEPTION_CONTINUE_EXECUTION, - - else => return windows.EXCEPTION_CONTINUE_SEARCH, - }, - null, - @intFromPtr(info.ExceptionRecord.ExceptionAddress), - ); -} - -extern "c" fn gnu_get_libc_version() ?[*:0]const u8; - -// Only populated after JSC::VM::tryCreate -export var Bun__reported_memory_size: usize = 0; - -pub fn printMetadata(writer: anytype) !void { - if (comptime bun.Environment.isDebug) { - if (Output.isAIAgent()) { - return; - } - } - - if (Output.enable_ansi_colors_stderr) { - try writer.writeAll(Output.prettyFmt("", true)); - } - - var is_ancient_cpu = false; - - try writer.writeAll(metadata_version_line); - { - const platform = bun.analytics.GenerateHeader.GeneratePlatform.forOS(); - const cpu_features = CPUFeatures.get(); - if (bun.Environment.isGlibc) { - const version = gnu_get_libc_version() orelse ""; - const kernel_version = bun.analytics.GenerateHeader.GeneratePlatform.kernelVersion(); - if (platform.os == .wsl) { - try writer.print("WSL Kernel v{d}.{d}.{d} | glibc v{s}\n", .{ kernel_version.major, kernel_version.minor, kernel_version.patch, bun.sliceTo(version, 0) }); - } else { - try writer.print("Linux Kernel v{d}.{d}.{d} | glibc v{s}\n", .{ kernel_version.major, kernel_version.minor, kernel_version.patch, bun.sliceTo(version, 0) }); - } - } else if (bun.Environment.isLinux and bun.Environment.isMusl) { - const kernel_version = bun.analytics.GenerateHeader.GeneratePlatform.kernelVersion(); - try writer.print("Linux Kernel v{d}.{d}.{d} | musl\n", .{ kernel_version.major, kernel_version.minor, kernel_version.patch }); - } else if (bun.Environment.isAndroid) { - const kernel_version = bun.analytics.GenerateHeader.GeneratePlatform.kernelVersion(); - try writer.print("Android Kernel v{d}.{d}.{d} | bionic\n", .{ kernel_version.major, kernel_version.minor, kernel_version.patch }); - } else if (bun.Environment.isFreeBSD) { - try writer.print("FreeBSD Kernel v{s}\n", .{platform.version}); - } else if (bun.Environment.isMac) { - try writer.print("macOS v{s}\n", .{platform.version}); - } else if (bun.Environment.isWindows) { - try writer.print("Windows v{f}\n", .{std.zig.system.windows.detectRuntimeVersion()}); - } - - if (bun.Environment.isX64) { - is_ancient_cpu = !cpu_features.hasAnyAVX(); - } - - if (!cpu_features.isEmpty()) { - try writer.print("CPU: {f}\n", .{cpu_features}); - } - - try writer.print("Args: ", .{}); - var arg_chars_left: usize = if (bun.Environment.isDebug) 4096 else 196; - for (bun.argv, 0..) |arg, i| { - if (i != 0) try writer.writeAll(" "); - try bun.fmt.quotedWriter(writer, arg[0..@min(arg.len, arg_chars_left)]); - arg_chars_left -|= arg.len; - if (arg_chars_left == 0) { - try writer.writeAll("..."); - break; - } - } - } - try writer.print("\n{f}", .{bun.analytics.Features.formatter()}); - - if (bun.use_mimalloc) { - var elapsed_msecs: usize = 0; - var user_msecs: usize = 0; - var system_msecs: usize = 0; - var current_rss: usize = 0; - var peak_rss: usize = 0; - var current_commit: usize = 0; - var peak_commit: usize = 0; - var page_faults: usize = 0; - mimalloc.mi_process_info( - &elapsed_msecs, - &user_msecs, - &system_msecs, - ¤t_rss, - &peak_rss, - ¤t_commit, - &peak_commit, - &page_faults, - ); - try writer.print("Elapsed: {d}ms | User: {d}ms | Sys: {d}ms\n", .{ - elapsed_msecs, - user_msecs, - system_msecs, - }); - - try writer.print("RSS: {B:<3.2} | Peak: {B:<3.2} | Commit: {B:<3.2} | Faults: {d}", .{ - current_rss, - peak_rss, - current_commit, - page_faults, - }); - - if (Bun__reported_memory_size > 0) { - try writer.print(" | Machine: {B:<3.2}", .{Bun__reported_memory_size}); - } - - try writer.writeAll("\n"); - } - - if (Output.enable_ansi_colors_stderr) { - try writer.writeAll(Output.prettyFmt("", true)); - } - try writer.writeAll("\n"); - - if (comptime bun.Environment.isX64) { - if (is_ancient_cpu) { - try writer.writeAll("CPU lacks AVX support. Please consider upgrading to a newer CPU.\n"); - } - } -} - -fn waitForOtherThreadToFinishPanicking() void { - if (panicking.fetchSub(1, .seq_cst) != 1) { - // Another thread is panicking, wait for the last one to finish - // and call abort() - if (builtin.single_threaded) unreachable; - - // Sleep forever without hammering the CPU - var futex = std.atomic.Value(u32).init(0); - while (true) bun.Futex.waitForever(&futex, 0); - comptime unreachable; - } -} - -/// This is to be called by any thread that is attempting to exit the process. -/// If another thread is panicking, this will sleep this thread forever, under -/// the assumption that the crash handler will terminate the program. -/// -/// There have been situations in the past where a bundler thread starts -/// panicking, but the main thread ends up marking a test as passing and then -/// exiting with code zero before the crash handler can finish the crash. -pub fn sleepForeverIfAnotherThreadIsCrashing() void { - if (panicking.load(.acquire) > 0) { - // Sleep forever without hammering the CPU - var futex = std.atomic.Value(u32).init(0); - while (true) bun.Futex.waitForever(&futex, 0); - comptime unreachable; - } -} - -/// Each platform is encoded as a single character. It is placed right after the -/// slash after the version, so someone just reading the trace string can tell -/// what platform it came from. L, M, and W are for Linux, macOS, and Windows, -/// with capital letters indicating aarch64, lowercase indicating x86_64. -/// -/// eg: 'https://bun.report/1.1.3/we04c... -// ^ this tells you it is windows x86_64 -/// -/// Baseline gets a weirder encoding of a mix of b and e. -const Platform = enum(u8) { - linux_x86_64 = 'l', - linux_x86_64_baseline = 'B', - linux_aarch64 = 'L', - - mac_x86_64_baseline = 'b', - mac_x86_64 = 'm', - mac_aarch64 = 'M', - - windows_x86_64 = 'w', - windows_x86_64_baseline = 'e', - windows_aarch64 = 'W', - - freebsd_x86_64 = 'f', - freebsd_x86_64_baseline = 'g', - freebsd_aarch64 = 'F', - - const current = @field(Platform, @tagName(bun.Environment.os) ++ - "_" ++ @tagName(builtin.target.cpu.arch) ++ - (if (bun.Environment.baseline) "_baseline" else "")); -}; - -/// Note to the decoder on how to process this string. This ensures backwards -/// compatibility with older versions of the tracestring. -/// -/// '1' - original. uses 7 char hash with VLQ encoded stack-frames -/// '2' - same as '1' but this build is known to be a canary build -const version_char = if (bun.Environment.is_canary) - "2" -else - "1"; - -const git_sha = if (bun.Environment.git_sha.len > 0) bun.Environment.git_sha[0..7] else "unknown"; - -const StackLine = struct { - address: i32, - // null -> from bun.exe - object: ?[]const u8, - - /// `null` implies the trace is not known. - pub fn fromAddress(addr: usize, name_bytes: []u8) ?StackLine { - return switch (bun.Environment.os) { - .windows => { - const module = bun.windows.getModuleHandleFromAddress(addr) orelse - return null; - - const base_address = @intFromPtr(module); - - var temp: [512]u16 = undefined; - const name = bun.windows.getModuleNameW(module, &temp) orelse - return null; - - const image_path = bun.windows.exePathW(); - - return .{ - // To remap this, `pdb-addr2line --exe bun.pdb 0x123456` - .address = @intCast(addr - base_address), - - .object = if (!std.mem.eql(u16, name, image_path)) name: { - const basename = name[if (std.mem.lastIndexOfAny(u16, name, &[_]u16{ '\\', '/' })) |i| - // skip the last slash - i + 1 - else - 0..]; - break :name bun.strings.convertUTF16toUTF8InBuffer(name_bytes, basename) catch null; - } else null, - }; - }, - .mac => { - // This code is slightly modified from std.debug.DebugInfo.lookupModuleNameDyld - // https://github.com/ziglang/zig/blob/215de3ee67f75e2405c177b262cb5c1cd8c8e343/lib/std/debug.zig#L1783 - const address = if (addr == 0) 0 else addr - 1; - - const image_count = std.c._dyld_image_count(); - - var i: u32 = 0; - while (i < image_count) : (i += 1) { - const header = std.c._dyld_get_image_header(i) orelse continue; - const base_address = @intFromPtr(header); - if (address < base_address) continue; - // This 'slide' is the ASLR offset. Subtract from `address` to get a stable address - const vmaddr_slide = std.c._dyld_get_image_vmaddr_slide(i); - - var it = std.macho.LoadCommandIterator{ - .ncmds = header.ncmds, - .buffer = @alignCast(@as( - [*]u8, - @ptrFromInt(@intFromPtr(header) + @sizeOf(std.macho.mach_header_64)), - )[0..header.sizeofcmds]), - }; - - while (it.next()) |cmd| switch (cmd.cmd()) { - .SEGMENT_64 => { - const segment_cmd = cmd.cast(std.macho.segment_command_64).?; - if (!bun.strings.eqlComptime(segment_cmd.segName(), "__TEXT")) continue; - - const original_address = address - vmaddr_slide; - const seg_start = segment_cmd.vmaddr; - const seg_end = seg_start + segment_cmd.vmsize; - if (original_address >= seg_start and original_address < seg_end) { - // Subtract ASLR value for stable address - const stable_address: usize = @intCast(address - vmaddr_slide); - - if (i == 0) { - const image_relative_address = stable_address - seg_start; - if (image_relative_address > std.math.maxInt(i32)) { - return null; - } - - // To remap this, you have to add the offset (which is going to be 0x100000000), - // and then you can run it through `llvm-symbolizer --obj bun-with-symbols 0x123456` - // The reason we are subtracting this known offset is mostly just so that we can - // fit it within a signed 32-bit integer. The VLQs will be shorter too. - return .{ - .object = null, - .address = @intCast(image_relative_address), - }; - } else { - // these libraries are not interesting, mark as unknown - return null; - } - - return null; - } - }, - else => {}, - }; - } - - return null; - }, - else => { - // This code is slightly modified from std.debug.DebugInfo.lookupModuleDl - // https://github.com/ziglang/zig/blob/215de3ee67f75e2405c177b262cb5c1cd8c8e343/lib/std/debug.zig#L2024 - var ctx: struct { - // Input - address: usize, - i: usize = 0, - // Output - result: ?StackLine = null, - } = .{ .address = addr -| 1 }; - const CtxTy = @TypeOf(ctx); - - std.posix.dl_iterate_phdr(&ctx, error{Found}, struct { - fn callback(info: *std.posix.dl_phdr_info, _: usize, context: *CtxTy) !void { - defer context.i += 1; - - if (context.address < info.addr) return; - const phdrs = info.phdr[0..info.phnum]; - for (phdrs) |*phdr| { - if (phdr.p_type != std.elf.PT_LOAD) continue; - - // Overflowing addition is used to handle the case of VSDOs - // having a p_vaddr = 0xffffffffff700000 - const seg_start = info.addr +% phdr.p_vaddr; - const seg_end = seg_start + phdr.p_memsz; - if (context.address >= seg_start and context.address < seg_end) { - // const name = bun.sliceTo(info.name, 0) orelse ""; - context.result = .{ - .address = @intCast(context.address - info.addr), - .object = null, - }; - return error.Found; - } - } - } - }.callback) catch {}; - - return ctx.result; - }, - }; - } - - pub fn writeEncoded(self: ?StackLine, writer: anytype) !void { - const known = self orelse { - try writer.writeAll("_"); - return; - }; - - if (known.object) |object| { - try VLQ.encode(1).writeTo(writer); - try VLQ.encode(@intCast(object.len)).writeTo(writer); - try writer.writeAll(object); - } - - try VLQ.encode(known.address).writeTo(writer); - } - - pub fn format(line: StackLine, writer: *std.Io.Writer) !void { - try writer.print("0x{x}{s}{s}", .{ - if (bun.Environment.isMac) @as(u64, line.address) + 0x100000000 else line.address, - if (line.object != null) " @ " else "", - line.object orelse "", - }); - } - - pub fn writeDecoded(self: ?StackLine, writer: anytype) !void { - const known = self orelse { - try writer.print("???", .{}); - return; - }; - try known.format("", .{}, writer); - } -}; - -const TraceString = struct { - trace: *const std.builtin.StackTrace, - reason: CrashReason, - action: TraceString.Action, - - const Action = enum { - /// Open a pre-filled GitHub issue with the expanded trace - open_issue, - /// View the trace with nothing else - view_trace, - }; - - pub fn format(self: TraceString, writer: *std.Io.Writer) std.Io.Writer.Error!void { - encodeTraceString(self, writer) catch return; - } -}; - -fn encodeTraceString(opts: TraceString, writer: anytype) !void { - try writer.writeAll(reportBaseUrl()); - try writer.writeAll( - "/" ++ - bun.Environment.version_string ++ - "/" ++ - .{@intFromEnum(Platform.current)}, - ); - try writer.writeByte(if (bun.cli.Cli.cmd) |cmd| cmd.char() else '_'); - - try writer.writeAll(version_char ++ git_sha); - - const packed_features = bun.analytics.packedFeatures(); - try writeU64AsTwoVLQs(writer, @bitCast(packed_features)); - - var name_bytes: [1024]u8 = undefined; - - for (opts.trace.instruction_addresses[0..opts.trace.index]) |addr| { - const line = StackLine.fromAddress(addr, &name_bytes); - try StackLine.writeEncoded(line, writer); - } - - try writer.writeAll(VLQ.zero.slice()); - - // The following switch must be kept in sync with `bun.report`'s decoder implementation. - switch (opts.reason) { - .panic => |message| { - try writer.writeByte('0'); - - var compressed_bytes: [2048]u8 = undefined; - var len: bun.zlib.uLong = compressed_bytes.len; - const ret: bun.zlib.ReturnCode = @enumFromInt(bun.zlib.compress2(&compressed_bytes, &len, message.ptr, @intCast(message.len), 9)); - const compressed = switch (ret) { - .Ok => compressed_bytes[0..@intCast(len)], - // Insufficient memory. - .MemError => return error.OutOfMemory, - // The buffer dest was not large enough to hold the compressed data. - .BufError => return error.NoSpaceLeft, - - // The level was not Z_DEFAULT_LEVEL, or was not between 0 and 9. - // This is technically possible but impossible because we pass 9. - .StreamError => return error.Unexpected, - else => return error.Unexpected, - }; - - var b64_bytes: [2048]u8 = undefined; - if (bun.base64.encodeLen(compressed) > b64_bytes.len) { - return error.NoSpaceLeft; - } - const b64_len = bun.base64.encode(&b64_bytes, compressed); - - try writer.writeAll(std.mem.trimRight(u8, b64_bytes[0..b64_len], "=")); - }, - - .@"unreachable" => try writer.writeByte('1'), - - .segmentation_fault => |addr| { - try writer.writeByte('2'); - try writeU64AsTwoVLQs(writer, addr); - }, - .illegal_instruction => |addr| { - try writer.writeByte('3'); - try writeU64AsTwoVLQs(writer, addr); - }, - .bus_error => |addr| { - try writer.writeByte('4'); - try writeU64AsTwoVLQs(writer, addr); - }, - .floating_point_error => |addr| { - try writer.writeByte('5'); - try writeU64AsTwoVLQs(writer, addr); - }, - - .datatype_misalignment => try writer.writeByte('6'), - .stack_overflow => try writer.writeByte('7'), - - .zig_error => |err| { - try writer.writeByte('8'); - try writer.writeAll(@errorName(err)); - }, - - .out_of_memory => try writer.writeByte('9'), - } - - if (opts.action == .view_trace) { - try writer.writeAll("/view"); - } -} - -pub fn writeU64AsTwoVLQs(writer: anytype, addr: usize) !void { - const first = VLQ.encode(@bitCast(@as(u32, @intCast((addr & 0xFFFFFFFF00000000) >> 32)))); - const second = VLQ.encode(@bitCast(@as(u32, @intCast(addr & 0xFFFFFFFF)))); - try first.writeTo(writer); - try second.writeTo(writer); -} - -fn isReportingEnabled() bool { - if (suppress_reporting) return false; - - // If trying to test the crash handler backend, implicitly enable reporting - if (bun.env_var.BUN_CRASH_REPORT_URL.get()) |value| { - return value.len > 0; - } - - // Environment variable to specifically enable or disable reporting - if (bun.env_var.BUN_ENABLE_CRASH_REPORTING.get()) |enable_crash_reporting| { - return enable_crash_reporting; - } - - // Debug builds shouldn't report to the default url by default - if (bun.Environment.isDebug) - return false; - - if (bun.Environment.enable_asan) - return false; - - // Honor DO_NOT_TRACK - if (!bun.analytics.isEnabled()) - return false; - - if (bun.Environment.is_canary) - return true; - - // Change in v1.1.10: enable crash reporter auto upload on macOS and Windows. - if (bun.Environment.isMac or bun.Environment.isWindows) { - return true; - } - - return false; -} - -/// Bun automatically reports crashes on Windows and macOS -/// -/// These URLs contain no source code or personally-identifiable -/// information (PII). The stackframes point to Bun's open-source native code -/// (not user code), and are safe to share publicly and with the Bun team. -fn report(url: []const u8) void { - if (!isReportingEnabled()) return; - - switch (bun.Environment.os) { - .windows => { - var process: std.os.windows.PROCESS_INFORMATION = undefined; - var startup_info = std.os.windows.STARTUPINFOW{ - .cb = @sizeOf(std.os.windows.STARTUPINFOW), - .lpReserved = null, - .lpDesktop = null, - .lpTitle = null, - .dwX = 0, - .dwY = 0, - .dwXSize = 0, - .dwYSize = 0, - .dwXCountChars = 0, - .dwYCountChars = 0, - .dwFillAttribute = 0, - .dwFlags = 0, - .wShowWindow = 0, - .cbReserved2 = 0, - .lpReserved2 = null, - .hStdInput = null, - .hStdOutput = null, - .hStdError = null, - // .hStdInput = bun.FD.stdin().native(), - // .hStdOutput = bun.FD.stdout().native(), - // .hStdError = bun.FD.stderr().native(), - }; - var cmd_line = bun.BoundedArray(u16, 4096){}; - cmd_line.appendSliceAssumeCapacity(std.unicode.utf8ToUtf16LeStringLiteral("powershell -ExecutionPolicy Bypass -Command \"try{Invoke-RestMethod -Uri '")); - { - const encoded = bun.strings.convertUTF8toUTF16InBuffer(cmd_line.unusedCapacitySlice(), url); - cmd_line.len += @intCast(encoded.len); - } - cmd_line.appendSlice(std.unicode.utf8ToUtf16LeStringLiteral("/ack'|out-null}catch{}\"")) catch return; - cmd_line.append(0) catch return; - const cmd_line_slice = cmd_line.buffer[0 .. cmd_line.len - 1 :0]; - const spawn_result = std.os.windows.kernel32.CreateProcessW( - null, - cmd_line_slice, - null, - null, - 1, // true - .{}, - null, - null, - &startup_info, - &process, - ); - - // we don't care what happens with the process - _ = spawn_result; - }, - .mac, .linux, .freebsd => { - var buf: bun.PathBuffer = undefined; - var buf2: bun.PathBuffer = undefined; - const curl = bun.which( - &buf, - bun.env_var.PATH.get() orelse return, - bun.getcwd(&buf2) catch return, - "curl", - ) orelse return; - var cmd_line = bun.BoundedArray(u8, 4096){}; - cmd_line.appendSlice(url) catch return; - cmd_line.appendSlice("/ack") catch return; - cmd_line.append(0) catch return; - - var argv = [_:null]?[*:0]const u8{ - curl, - "-fsSL", - cmd_line.buffer[0..cmd_line.len :0], - }; - const result = std.c.fork(); - switch (result) { - // success and failure cases: ignore the result - else => return, - // child - 0 => { - inline for (0..2) |i| { - _ = std.c.close(i); - } - _ = std.c.execve(argv[0].?, &argv, std.c.environ); - std.c.exit(0); - }, - } - }, - .wasm => @compileError("Not implemented"), - } -} - -/// Crash. Make sure segfault handlers are off so that this doesnt trigger the crash handler. -/// This causes a segfault on posix systems to try to get a core dump. -fn crash() noreturn { - switch (bun.Environment.os) { - .windows => { - // Node.js exits with code 134 (128 + SIGABRT) instead. We use abort() as it includes a - // breakpoint which makes crashes easier to debug. - std.posix.abort(); - }, - else => { - // Install default handler so that the tkill below will terminate. - const sigact = bun.sys.Sigaction{ .handler = .{ .handler = std.posix.SIG.DFL }, .mask = bun.sys.sigemptyset(), .flags = 0 }; - inline for (.{ - std.posix.SIG.SEGV, - std.posix.SIG.ILL, - std.posix.SIG.BUS, - std.posix.SIG.ABRT, - std.posix.SIG.FPE, - std.posix.SIG.HUP, - std.posix.SIG.TERM, - }) |sig| { - bun.sys.sigaction(sig, &sigact, null); - } - - @trap(); - }, - } -} - -pub var verbose_error_trace = false; - -noinline fn coldHandleErrorReturnTrace(err_int_workaround_for_zig_ccall_bug: std.meta.Int(.unsigned, @bitSizeOf(anyerror)), trace: *std.builtin.StackTrace, comptime is_root: bool) void { - @branchHint(.cold); - const err = @errorFromInt(err_int_workaround_for_zig_ccall_bug); - - // The format of the panic trace is slightly different in debug - // builds Mainly, we demangle the backtrace immediately instead - // of using a trace string. - // - // To make the release-mode behavior easier to demo, debug mode - // checks for this CLI flag. - const is_debug = bun.Environment.isDebug and check_flag: { - for (bun.argv) |arg| { - if (bun.strings.eqlComptime(arg, "--debug-crash-handler-use-trace-string")) { - break :check_flag false; - } - } - break :check_flag true; - }; - - if (is_debug) { - if (is_root) { - if (verbose_error_trace) { - Output.note("Release build will not have this trace by default:", .{}); - } - } else { - Output.note( - "caught error.{s}:", - .{@errorName(err)}, - ); - } - Output.flush(); - dumpStackTrace(trace.*, .{}); - } else { - const ts = TraceString{ - .trace = trace, - .reason = .{ .zig_error = err }, - .action = .view_trace, - }; - if (is_root) { - Output.prettyErrorln( - \\ - \\To send a redacted crash report to Bun's team, - \\please file a GitHub issue using the link below: - \\ - \\ {f} - \\ - , - .{ts}, - ); - } else { - Output.prettyErrorln( - "trace: error.{s}: {f}", - .{ @errorName(err), ts }, - ); - } - } -} - -inline fn handleErrorReturnTraceExtra(err: anyerror, maybe_trace: ?*std.builtin.StackTrace, comptime is_root: bool) void { - if (!builtin.have_error_return_tracing) return; - if (!verbose_error_trace and !is_root) return; - - if (maybe_trace) |trace| { - coldHandleErrorReturnTrace(@intFromError(err), trace, is_root); - } -} - -/// In many places we catch errors, the trace for them is absorbed and only a -/// single line (the error name) is printed. When this is set, we will print -/// trace strings for those errors (or full stacks in debug builds). -/// -/// This can be enabled by passing `--verbose-error-trace` to the CLI. -/// In release builds with error return tracing enabled, this is also exposed. -/// You can test if this feature is available by checking `bun --help` for the flag. -pub inline fn handleErrorReturnTrace(err: anyerror, maybe_trace: ?*std.builtin.StackTrace) void { - handleErrorReturnTraceExtra(err, maybe_trace, false); -} -extern "c" fn WTF__DumpStackTrace(ptr: [*]usize, count: usize) void; - -/// Version of the standard library dumpStackTrace that has some fallbacks for -/// cases where such logic fails to run. -pub fn dumpStackTrace(trace: std.builtin.StackTrace, limits: WriteStackTraceLimits) void { - Output.flush(); - var stderr_w = std.fs.File.stderr().writerStreaming(&.{}); - const stderr = &stderr_w.interface; - if (!bun.Environment.show_crash_trace) { - // debug symbols aren't available, lets print a tracestring - stderr.print("View Debug Trace: {f}\n", .{TraceString{ - .action = .view_trace, - .reason = .{ .zig_error = error.DumpStackTrace }, - .trace = &trace, - }}) catch {}; - return; - } - - switch (bun.Environment.os) { - .windows => attempt_dump: { - // Windows has issues with opening the PDB file sometimes. - const debug_info = debug.getSelfDebugInfo() catch |err| { - stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\nFallback trace:\n", .{@errorName(err)}) catch return; - break :attempt_dump; - }; - writeStackTrace(trace, stderr, debug_info, std.io.tty.detectConfig(std.fs.File.stderr()), limits) catch |err| { - stderr.print("Unable to dump stack trace: {s}\nFallback trace:\n", .{@errorName(err)}) catch return; - break :attempt_dump; - }; - return; - }, - .linux => { - // In non-debug builds, use WTF's stack trace printer and return early - if (!bun.Environment.isDebug) { - WTF__DumpStackTrace(trace.instruction_addresses.ptr, trace.index); - return; - } - // Otherwise fall through to llvm-symbolizer for debug builds - }, - else => { - // Assume debug symbol tooling is reliable. - const debug_info = debug.getSelfDebugInfo() catch |err| { - stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return; - return; - }; - writeStackTrace(trace, stderr, debug_info, std.io.tty.detectConfig(std.fs.File.stderr()), limits) catch |err| { - stderr.print("Unable to dump stack trace: {s}", .{@errorName(err)}) catch return; - return; - }; - return; - }, - } - - const programs: []const [:0]const u8 = switch (bun.Environment.os) { - .windows => &.{"pdb-addr2line"}, - // if `llvm-symbolizer` doesn't work, also try `llvm-symbolizer-21` - else => &.{ "llvm-symbolizer", "llvm-symbolizer-21" }, - }; - for (programs) |program| { - var arena = bun.ArenaAllocator.init(bun.default_allocator); - defer arena.deinit(); - var sfa = std.heap.stackFallback(16384, arena.allocator()); - spawnSymbolizer(program, sfa.get(), &trace) catch |err| switch (err) { - // try next program if this one wasn't found - error.FileNotFound => continue, - else => {}, - }; - return; - } -} - -fn spawnSymbolizer(program: [:0]const u8, alloc: std.mem.Allocator, trace: *const std.builtin.StackTrace) !void { - var argv = std.array_list.Managed([]const u8).init(alloc); - try argv.append(program); - try argv.append("--exe"); - try argv.append( - switch (bun.Environment.os) { - .windows => brk: { - const image_path = try bun.strings.toUTF8Alloc(alloc, bun.windows.exePathW()); - break :brk try std.mem.concat(alloc, u8, &.{ - image_path[0 .. image_path.len - 3], - "pdb", - }); - }, - else => try bun.selfExePath(), - }, - ); - - var name_bytes: [1024]u8 = undefined; - for (trace.instruction_addresses[0..trace.index]) |addr| { - const line = StackLine.fromAddress(addr, &name_bytes) orelse - continue; - try argv.append(try std.fmt.allocPrint(alloc, "0x{X}", .{line.address})); - } - - var child = std.process.Child.init(argv.items, alloc); - child.stdin_behavior = .Inherit; - child.stdout_behavior = .Inherit; - child.stderr_behavior = .Inherit; - - child.expand_arg0 = .expand; - child.progress_node = std.Progress.Node.none; - - var stderr_writer = std.fs.File.stderr().writerStreaming(&.{}); - const stderr = &stderr_writer.interface; - const result = child.spawnAndWait() catch |err| { - stderr.print("Failed to invoke command: {f}\n", .{bun.fmt.fmtSlice(argv.items, " ")}) catch {}; - if (bun.Environment.isWindows) { - stderr.print("(You can compile pdb-addr2line from https://github.com/oven-sh/bun.report, cd pdb-addr2line && cargo build)\n", .{}) catch {}; - } - return err; - }; - - if (result != .Exited or result.Exited != 0) { - stderr.print("Failed to invoke command: {f}\n", .{bun.fmt.fmtSlice(argv.items, " ")}) catch {}; - } -} - -pub fn dumpCurrentStackTrace(first_address: ?usize, limits: WriteStackTraceLimits) void { - var addrs: [32]usize = undefined; - var stack: std.builtin.StackTrace = .{ .index = 0, .instruction_addresses = &addrs }; - std.debug.captureStackTrace(first_address orelse @returnAddress(), &stack); - dumpStackTrace(stack, limits); -} - -/// If POSIX, and the existing soft limit for core dumps (ulimit -Sc) is nonzero, change it to zero. -/// Used in places where we intentionally crash for testing purposes so that we don't clutter CI -/// with core dumps. -pub fn suppressCoreDumpsIfNecessary() void { - if (bun.Environment.isPosix) { - var existing_limit = std.posix.getrlimit(.CORE) catch return; - if (existing_limit.cur > 0 or existing_limit.cur == std.posix.RLIM.INFINITY) { - existing_limit.cur = 0; - std.posix.setrlimit(.CORE, existing_limit) catch {}; - } - } -} - -/// From now on, prevent crashes from being reported to bun.report or the URL overridden in -/// BUN_CRASH_REPORT_URL. Should only be used for tests that are going to intentionally crash, -/// so that they do not fail CI due to having a crash reported. And those cases should guard behind -/// a feature flag and call right before the crash, in order to make sure that crashes other than -/// the expected one are not suppressed. -pub fn suppressReporting() void { - suppressCoreDumpsIfNecessary(); - suppress_reporting = true; -} - -/// A variant of `std.builtin.StackTrace` that stores its data within itself -/// instead of being a pointer. This allows storing captured stack traces -/// for later printing. -pub const StoredTrace = struct { - data: [31]usize, - index: usize, - - pub const empty: StoredTrace = .{ - .data = .{0} ** 31, - .index = 0, - }; - - pub fn trace(stored: *StoredTrace) std.builtin.StackTrace { - return .{ - .index = stored.index, - .instruction_addresses = &stored.data, - }; - } - - pub fn capture(begin: ?usize) StoredTrace { - var stored: StoredTrace = StoredTrace.empty; - var frame = stored.trace(); - std.debug.captureStackTrace(begin orelse @returnAddress(), &frame); - stored.index = frame.index; - for (frame.instruction_addresses[0..frame.index], 0..) |addr, i| { - if (addr == 0) { - stored.index = i; - break; - } - } - return stored; - } - - pub fn from(stack_trace: ?*std.builtin.StackTrace) StoredTrace { - if (stack_trace) |stack| { - var data: [31]usize = undefined; - @memset(&data, 0); - const items = @min(stack.instruction_addresses.len, 31); - @memcpy(data[0..items], stack.instruction_addresses[0..items]); - return .{ - .data = data, - .index = @min(items, stack.index), - }; - } else { - return empty; - } - } -}; - -pub const js_bindings = @import("../runtime/api/crash_handler_jsc.zig").js_bindings; - -const OnBeforeCrash = fn (opaque_ptr: *anyopaque) void; - -/// For large codebases such as bun.bake.DevServer, it may be helpful -/// to dump a large amount of state to a file to aid debugging a crash. -/// -/// Pre-crash handlers are likely, but not guaranteed to call. Errors are ignored. -pub fn appendPreCrashHandler(comptime T: type, ptr: *T, comptime handler: fn (*T) anyerror!void) !void { - const wrap = struct { - fn onCrash(opaque_ptr: *anyopaque) void { - handler(@ptrCast(@alignCast(opaque_ptr))) catch |err| { - bun.handleErrorReturnTrace(err, @errorReturnTrace()); - }; - } - }; - - before_crash_handlers_mutex.lock(); - defer before_crash_handlers_mutex.unlock(); - try before_crash_handlers.append(bun.default_allocator, .{ ptr, wrap.onCrash }); -} - -pub fn removePreCrashHandler(ptr: *anyopaque) void { - before_crash_handlers_mutex.lock(); - defer before_crash_handlers_mutex.unlock(); - const index = for (before_crash_handlers.items, 0..) |item, i| { - if (item.@"0" == ptr) break i; - } else return; - _ = before_crash_handlers.orderedRemove(index); -} - -pub fn isPanicking() bool { - return panicking.load(.monotonic) > 0; -} - -pub const SourceAtAddress = struct { - source_location: ?SourceLocation, - symbol_name: []const u8, - compile_unit_name: []const u8, - fn deinit(self: *@This(), debug_info: *debug.SelfInfo) void { - if (self.source_location) |sl| debug_info.allocator.free(sl.file_name); - } -}; - -pub const WriteStackTraceLimits = struct { - frame_count: usize = std.math.maxInt(usize), - stop_at_jsc_llint: bool = false, - skip_stdlib: bool = false, - skip_file_patterns: []const []const u8 = &.{}, - skip_function_patterns: []const []const u8 = &.{}, -}; - -/// Clone of `debug.writeStackTrace`, but can be configured to stop at either a -/// frame count, or when hitting jsc LLInt Additionally, the printing function -/// does not print the `^`, instead it highlights the word at the column. This -/// Makes each frame take up two lines instead of three. -pub fn writeStackTrace( - stack_trace: std.builtin.StackTrace, - out_stream: anytype, - debug_info: *debug.SelfInfo, - tty_config: std.io.tty.Config, - limits: WriteStackTraceLimits, -) !void { - if (builtin.strip_debug_info) return error.MissingDebugInfo; - var frame_index: usize = 0; - var frames_left: usize = @min(stack_trace.index, stack_trace.instruction_addresses.len); - - while (frames_left != 0) : ({ - frames_left -= 1; - frame_index = (frame_index + 1) % stack_trace.instruction_addresses.len; - }) { - if (frame_index >= limits.frame_count) { - break; - } - const return_address = stack_trace.instruction_addresses[frame_index]; - const source = (try getSourceAtAddress(debug_info, return_address - 1)) orelse { - const module_name = debug_info.getModuleNameForAddress(return_address - 1); - try printLineInfo( - out_stream, - null, - return_address - 1, - "???", - module_name orelse "???", - tty_config, - ); - continue; - }; - - if (limits.skip_stdlib) { - if (source.source_location) |sl| { - if (bun.strings.includes(sl.file_name, "lib/std")) { - continue; - } - } - } - for (limits.skip_file_patterns) |pattern| { - if (source.source_location) |sl| { - if (bun.strings.includes(sl.file_name, pattern)) { - continue; - } - } - } - for (limits.skip_function_patterns) |pattern| { - if (bun.strings.includes(source.symbol_name, pattern)) { - continue; - } - } - if (limits.stop_at_jsc_llint and bun.strings.includes(source.symbol_name, "_llint_")) { - break; - } - - try printLineInfo( - out_stream, - source.source_location, - return_address - 1, - source.symbol_name, - source.compile_unit_name, - tty_config, - ); - } - - if (stack_trace.index > stack_trace.instruction_addresses.len) { - const dropped_frames = stack_trace.index - stack_trace.instruction_addresses.len; - - tty_config.setColor(out_stream, .bold) catch {}; - try out_stream.print("({d} additional stack frames not recorded...)\n", .{dropped_frames}); - tty_config.setColor(out_stream, .reset) catch {}; - } else if (frames_left != 0) { - tty_config.setColor(out_stream, .bold) catch {}; - try out_stream.print("({d} additional stack frames skipped...)\n", .{frames_left}); - tty_config.setColor(out_stream, .reset) catch {}; - } - out_stream.writeAll("\n") catch {}; -} - -/// Clone of `debug.printSourceAtAddress` but it returns the metadata as well. -pub fn getSourceAtAddress(debug_info: *debug.SelfInfo, address: usize) !?SourceAtAddress { - const module = debug_info.getModuleForAddress(address) catch |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => return null, - else => return err, - }; - - const symbol_info = module.getSymbolAtAddress(debug_info.allocator, address) catch |err| switch (err) { - error.MissingDebugInfo, error.InvalidDebugInfo => return null, - else => return err, - }; - - return .{ - .source_location = symbol_info.source_location, - .symbol_name = symbol_info.name, - .compile_unit_name = symbol_info.compile_unit_name, - }; -} - -/// Clone of `debug.printLineInfo` as it is private. -fn printLineInfo( - out_stream: *std.Io.Writer, - source_location: ?SourceLocation, - address: usize, - symbol_name: []const u8, - compile_unit_name: []const u8, - tty_config: std.io.tty.Config, -) !void { - const base_path = bun.Environment.base_path ++ std.fs.path.sep_str; - nosuspend { - if (source_location) |*sl| { - if (bun.strings.startsWith(sl.file_name, base_path)) { - try tty_config.setColor(out_stream, .dim); - try out_stream.print("{s}", .{base_path}); - try tty_config.setColor(out_stream, .reset); - try tty_config.setColor(out_stream, .bold); - try out_stream.print("{s}", .{sl.file_name[base_path.len..]}); - } else { - try tty_config.setColor(out_stream, .bold); - try out_stream.print("{s}", .{sl.file_name}); - } - try out_stream.print(":{d}:{d}", .{ sl.line, sl.column }); - } else { - try tty_config.setColor(out_stream, .bold); - try out_stream.writeAll("???:?:?"); - } - - try tty_config.setColor(out_stream, .reset); - try out_stream.writeAll(": "); - try tty_config.setColor(out_stream, .dim); - try out_stream.print("0x{x} in", .{address}); - try tty_config.setColor(out_stream, .reset); - try tty_config.setColor(out_stream, .yellow); - try out_stream.print(" {s}", .{symbol_name}); - try tty_config.setColor(out_stream, .reset); - try tty_config.setColor(out_stream, .dim); - try out_stream.print(" ({s})", .{compile_unit_name}); - try tty_config.setColor(out_stream, .reset); - try out_stream.writeAll("\n"); - - // Show the matching source code line if possible - if (source_location) |sl| { - if (printLineFromFileAnyOs(out_stream, tty_config, sl)) { - if (sl.column > 0 and tty_config == .no_color) { - // The caret already takes one char - const space_needed = @as(usize, @intCast(sl.column - 1)); - try out_stream.splatByteAll(' ', space_needed); - try out_stream.writeAll("^\n"); - } - } else |err| switch (err) { - error.EndOfFile, error.FileNotFound => {}, - error.BadPathName => {}, - error.AccessDenied => {}, - else => return err, - } - } - } -} - -/// Modified version of `debug.printLineFromFileAnyOs` that uses two passes. -/// - Record the whole slice into a buffer -/// - Locate the column, expand a highlight to one word. -/// - Print the line, with the highlight. -fn printLineFromFileAnyOs(out_stream: anytype, tty_config: std.io.tty.Config, source_location: SourceLocation) !void { - // Need this to always block even in async I/O mode, because this could potentially - // be called from e.g. the event loop code crashing. - var f = try std.fs.cwd().openFile(source_location.file_name, .{}); - defer f.close(); - - var line_buf: [4096]u8 = undefined; - var fbs = std.io.fixedBufferStream(&line_buf); - read_line: { - var buf: [4096]u8 = undefined; - var amt_read = try f.read(buf[0..]); - const line_start = seek: { - var current_line_start: usize = 0; - var next_line: usize = 1; - while (next_line != source_location.line) { - const slice = buf[current_line_start..amt_read]; - if (bun.strings.indexOfChar(slice, '\n')) |pos| { - next_line += 1; - if (pos == slice.len - 1) { - amt_read = try f.read(buf[0..]); - current_line_start = 0; - } else current_line_start += pos + 1; - } else if (amt_read < buf.len) { - return error.EndOfFile; - } else { - amt_read = try f.read(buf[0..]); - current_line_start = 0; - } - } - break :seek current_line_start; - }; - const slice = buf[line_start..amt_read]; - if (bun.strings.indexOfChar(slice, '\n')) |pos| { - const line = slice[0..pos]; - std.mem.replaceScalar(u8, line, '\t', ' '); - fbs.writer().writeAll(line) catch {}; - break :read_line; - } else { // Line is the last inside the buffer, and requires another read to find delimiter. Alternatively the file ends. - std.mem.replaceScalar(u8, slice, '\t', ' '); - fbs.writer().writeAll(slice) catch break :read_line; - while (amt_read == buf.len) { - amt_read = try f.read(buf[0..]); - if (bun.strings.indexOfChar(buf[0..amt_read], '\n')) |pos| { - const line = buf[0..pos]; - std.mem.replaceScalar(u8, line, '\t', ' '); - fbs.writer().writeAll(line) catch break :read_line; - break :read_line; - } else { - const line = buf[0..amt_read]; - std.mem.replaceScalar(u8, line, '\t', ' '); - fbs.writer().writeAll(line) catch break :read_line; - } - } - break :read_line; - } - return; - } - const line_without_newline = std.mem.trimRight(u8, fbs.getWritten(), "\n"); - if (source_location.column > line_without_newline.len) { - try out_stream.writeAll(line_without_newline); - try out_stream.writeByte('\n'); - return; - } - // expand the highlight to one word - var left = source_location.column -| 1; - var right = left + 1; - while (left > 0) switch (line_without_newline[left]) { - else => left -= 1, - 'a'...'z', 'A'...'Z', '0'...'9', '_', ' ', '\t' => break, - }; - while (left > 0) switch (line_without_newline[left]) { - 'a'...'z', 'A'...'Z', '0'...'9', '_' => left -= 1, - else => break, - }; - while (right < line_without_newline.len) switch (line_without_newline[right - 1]) { - 'a'...'z', 'A'...'Z', '0'...'9', '_' => right += 1, - else => break, - }; - const before = line_without_newline[0..left]; - const highlight = line_without_newline[left..right]; - var after_before_comment = line_without_newline[right..]; - var comment: []const u8 = ""; - if (bun.strings.indexOf(after_before_comment, "//")) |pos| { - comment = after_before_comment[pos..]; - after_before_comment = after_before_comment[0..pos]; - } - try tty_config.setColor(out_stream, .red); - try tty_config.setColor(out_stream, .dim); - try out_stream.writeAll(before); - try tty_config.setColor(out_stream, .reset); - try tty_config.setColor(out_stream, .red); - try out_stream.writeAll(highlight); - try tty_config.setColor(out_stream, .dim); - try out_stream.writeAll(after_before_comment); - if (comment.len > 0) { - try tty_config.setColor(out_stream, .reset); - try tty_config.setColor(out_stream, .bright_cyan); - try out_stream.writeAll(comment); - } - try tty_config.setColor(out_stream, .reset); - try out_stream.writeByte('\n'); -} - -export fn CrashHandler__setInsideNativePlugin(name: ?[*:0]const u8) callconv(.c) void { - inside_native_plugin = name; -} - -export fn CrashHandler__unsupportedUVFunction(name: ?[*:0]const u8) callconv(.c) void { - bun.analytics.Features.unsupported_uv_function += 1; - unsupported_uv_function = name; - if (bun.feature_flag.BUN_INTERNAL_SUPPRESS_CRASH_ON_UV_STUB.get()) { - suppressReporting(); - } - std.debug.panic("unsupported uv function: {s}", .{name.?}); -} - -export fn Bun__crashHandler(message_ptr: [*]u8, message_len: usize) noreturn { - crashHandler(.{ .panic = message_ptr[0..message_len] }, null, @returnAddress()); -} - -export fn CrashHandler__setDlOpenAction(action: ?[*:0]const u8) void { - if (action) |str| { - bun.debugAssert(current_action == null); - current_action = .{ .dlopen = bun.sliceTo(str, 0) }; - } else { - bun.debugAssert(current_action != null and current_action.? == .dlopen); - current_action = null; - } -} - -pub fn fixDeadCodeElimination() void { - std.mem.doNotOptimizeAway(&CrashHandler__unsupportedUVFunction); -} -comptime { - _ = &Bun__crashHandler; - if (!bun.Environment.isWindows) { - std.mem.doNotOptimizeAway(&CrashHandler__unsupportedUVFunction); - } -} - -const CPUFeatures = @import("./CPUFeatures.zig"); -const builtin = @import("builtin"); -const std = @import("std"); -const windows = std.os.windows; - -const SourceMap = @import("../sourcemap/sourcemap.zig"); -const VLQ = SourceMap.VLQ; - -const bun = @import("bun"); -const Global = bun.Global; -const Output = bun.Output; -const mimalloc = bun.mimalloc; -const Features = bun.analytics.Features; - -const debug = std.debug; -const SourceLocation = debug.SourceLocation; diff --git a/src/crash_handler/handle_oom.zig b/src/crash_handler/handle_oom.zig deleted file mode 100644 index 62cb8019b437..000000000000 --- a/src/crash_handler/handle_oom.zig +++ /dev/null @@ -1,66 +0,0 @@ -fn isOomOnlyError(comptime ErrorUnionOrSet: type) bool { - @setEvalBranchQuota(10000); - const ErrorSet = switch (@typeInfo(ErrorUnionOrSet)) { - .error_union => |union_info| union_info.error_set, - .error_set => ErrorUnionOrSet, - else => @compileError("argument must be an error union or error set"), - }; - for (@typeInfo(ErrorSet).error_set orelse return false) |err| { - if (!std.mem.eql(u8, err.name, "OutOfMemory")) return false; - } - return true; -} - -/// If `error_union_or_set` is `error.OutOfMemory`, calls `bun.outOfMemory`. Otherwise: -/// -/// * If that was the only possible error, returns the non-error payload for error unions, or -/// `noreturn` for error sets. -/// * If other errors are possible, returns the same error union or set, but without -/// `error.OutOfMemory` in the error set. -/// -/// Prefer this method over `catch bun.outOfMemory()`, since that could mistakenly catch -/// non-OOM-related errors. -/// -/// There are two ways to use this function: -/// -/// ``` -/// // option 1: -/// const thing = bun.handleOom(allocateThing()); -/// // option 2: -/// const thing = allocateThing() catch |err| bun.handleOom(err); -/// ``` -pub fn handleOom(error_union_or_set: anytype) return_type: { - const ArgType = @TypeOf(error_union_or_set); - const arg_info = @typeInfo(ArgType); - break :return_type if (isOomOnlyError(ArgType)) switch (arg_info) { - .error_union => |union_info| union_info.payload, - .error_set => noreturn, - else => unreachable, - } else @TypeOf(blk: { - const err = switch (comptime arg_info) { - .error_union => if (error_union_or_set) |success| break :blk success else |err| err, - .error_set => error_union_or_set, - else => unreachable, - }; - break :blk switch (err) { - error.OutOfMemory => unreachable, - else => |other_error| other_error, - }; - }); -} { - const ArgType = @TypeOf(error_union_or_set); - const err = switch (comptime @typeInfo(ArgType)) { - .error_union => if (error_union_or_set) |success| return success else |err| err, - .error_set => error_union_or_set, - else => unreachable, - }; - return if (comptime isOomOnlyError(ArgType)) - bun.outOfMemory() - else switch (err) { - error.OutOfMemory => bun.outOfMemory(), - else => |other_error| other_error, - }; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/csrf/csrf.zig b/src/csrf/csrf.zig deleted file mode 100644 index 8b5ce43f0c8b..000000000000 --- a/src/csrf/csrf.zig +++ /dev/null @@ -1,220 +0,0 @@ -/// CSRF Token implementation for Bun -/// It provides protection against Cross-Site Request Forgery attacks -/// by generating and validating tokens using HMAC signatures -pub const CSRF = @This(); - -/// Default expiration time for tokens (24 hours) -pub const DEFAULT_EXPIRATION_MS: u64 = 24 * 60 * 60 * 1000; - -/// Default HMAC algorithm used for token signing -pub const DEFAULT_ALGORITHM: jsc.API.Bun.Crypto.EVP.Algorithm = .sha256; - -/// Error types for CSRF operations -pub const Error = error{ - InvalidToken, - ExpiredToken, - TokenCreationFailed, - DecodingFailed, -}; - -/// Options for generating CSRF tokens -pub const GenerateOptions = struct { - /// Secret key to use for signing - secret: []const u8, - /// How long the token should be valid (in milliseconds) - expires_in_ms: u64 = DEFAULT_EXPIRATION_MS, - /// Format to encode the token in - encoding: TokenFormat = .base64url, - /// Algorithm to use for signing - algorithm: jsc.API.Bun.Crypto.EVP.Algorithm = DEFAULT_ALGORITHM, -}; - -/// Options for validating CSRF tokens -pub const VerifyOptions = struct { - /// The token to verify - token: []const u8, - /// Secret key used to sign the token - secret: []const u8, - /// Maximum age of the token in milliseconds - max_age_ms: u64 = DEFAULT_EXPIRATION_MS, - /// Encoding to use for the token - encoding: TokenFormat = .base64url, - /// Algorithm to use for signing - algorithm: jsc.API.Bun.Crypto.EVP.Algorithm = DEFAULT_ALGORITHM, -}; - -/// Token encoding format -pub const TokenFormat = enum { - base64, - base64url, - hex, - - pub fn toNodeEncoding(self: TokenFormat) jsc.Node.Encoding { - return switch (self) { - .base64 => .base64, - .base64url => .base64url, - .hex => .hex, - }; - } -}; - -/// Generate a new CSRF token -/// -/// Parameters: -/// - options: Configuration for token generation -/// - vm: The jsc virtual machine context -/// -/// Returns: A string.Slice containing the encoded token -pub fn generate( - options: GenerateOptions, - out_buffer: *[512]u8, -) ![]u8 { - // Generate nonce from entropy - var nonce: [16]u8 = .{0} ** 16; - bun.csprng(&nonce); - - // Current timestamp in milliseconds - const timestamp = std.time.milliTimestamp(); - const timestamp_u64: u64 = @bitCast(@as(i64, timestamp)); - - // Write timestamp to out_buffer - var timestamp_bytes: [8]u8 = .{0} ** 8; - std.mem.writeInt(u64, ×tamp_bytes, timestamp_u64, .big); - var expires_in_bytes: [8]u8 = .{0} ** 8; - std.mem.writeInt(u64, &expires_in_bytes, options.expires_in_ms, .big); - // Prepare payload for signing: timestamp|nonce - var payload_buf: [32]u8 = .{0} ** 32; // 8 (timestamp) + 16 (nonce) - @memcpy(payload_buf[0..8], ×tamp_bytes); - @memcpy(payload_buf[8..24], &nonce); - @memcpy(payload_buf[24..32], &expires_in_bytes); - - // Sign the payload - var digest_buf: [boring.EVP_MAX_MD_SIZE]u8 = .{0} ** boring.EVP_MAX_MD_SIZE; - const digest = hmac.generate(options.secret, &payload_buf, options.algorithm, &digest_buf) orelse - return Error.TokenCreationFailed; - - // Create the final token: timestamp|nonce|expires_in|signature in out_buffer - @memcpy(out_buffer[0..8], ×tamp_bytes); - @memcpy(out_buffer[8..24], &nonce); - @memcpy(out_buffer[24..32], &expires_in_bytes); - @memcpy(out_buffer[32 .. 32 + digest.len], digest); - - // Return slice of the output buffer with the final token - return out_buffer[0 .. 32 + digest.len]; -} - -/// Validate a CSRF token -/// -/// Parameters: -/// - options: Configuration for token validation -/// -/// Returns: true if valid, false if invalid -pub fn verify(options: VerifyOptions) bool { - // Detect the encoding format - const encoding: TokenFormat = options.encoding; - - // Allocate output buffer for decoded data - var buf: [boring.EVP_MAX_MD_SIZE + 32]u8 = .{0} ** (boring.EVP_MAX_MD_SIZE + 32); - var token = options.token; - // check if ends with \0 - if (token.len > 0 and token[token.len - 1] == 0) { - token = token[0 .. token.len - 1]; - } - - const decoded: []const u8 = brk: switch (encoding) { - // shares same decoder but encoder is different see encoding.zig - .base64url, .base64 => { - // do the same as Buffer.from(token, "base64url" | "base64") - const slice = bun.strings.trim(token, "\r\n\t " ++ [_]u8{std.ascii.control_code.vt}); - if (slice.len == 0) return false; - - const outlen = bun.base64.decodeLen(slice); - if (outlen > buf.len) return false; - const wrote = bun.base64.decode(buf[0..outlen], slice).count; - break :brk buf[0..wrote]; - }, - .hex => { - if (token.len % 2 != 0) return false; - // decoded len - const decoded_len = token.len / 2; - if (decoded_len > buf.len) return false; - const result = bun.strings.decodeHexToBytesTruncate(buf[0..decoded_len], u8, token); - if (result == decoded_len) { - break :brk buf[0..decoded_len]; - } - return false; - }, - }; - - // Minimum token length: 8 (timestamp) + 16 (nonce) + 8 (expires_in) + 32 (minimum HMAC-SHA256 size) - if (decoded.len < 64) { - return false; - } - // We successfully decoded the token but it could be a bad token - // base64 and hex can have ambiguity so we need to check for weird cases and reject them - // it could also be a handcrafted token that is invalid - - // Extract timestamp (first 8 bytes) - const timestamp = std.mem.readInt(u64, decoded[0..8], .big); - - // Check if token has expired - const current_time = @as(u64, @bitCast(std.time.milliTimestamp())); - // Extract expires_in (last 8 bytes) - const expires_in = std.mem.readInt(u64, decoded[24..32], .big); - { - // respect the token's expiration time - if (expires_in > 0) { - // handle overflow for invalid expiry, which means bad token - if (std.math.maxInt(u64) - timestamp < expires_in) { - return false; - } - if (current_time > timestamp + expires_in) { - return false; - } - } - } - { - // repect options.max_age_ms - const expiry = options.max_age_ms; - if (expiry > 0) { - // handle overflow for invalid expiry, which means bad token - if (std.math.maxInt(u64) - timestamp < expiry) { - return false; - } - if (current_time > timestamp + expiry) { - return false; - } - } - } - // Extract the parts - const payload = decoded[0..32]; // timestamp + nonce + expires_in - const received_signature = decoded[32..]; - - // Verify the signature - var expected_signature: [boring.EVP_MAX_MD_SIZE]u8 = .{0} ** boring.EVP_MAX_MD_SIZE; - const signature = hmac.generate(options.secret, payload, options.algorithm, &expected_signature) orelse - return false; - - // Compare signatures in constant time - if (received_signature.len != signature.len) { - return false; - } - - // Use BoringSSL's constant-time comparison to prevent timing attacks - return boring.CRYPTO_memcmp( - received_signature.ptr, - signature.ptr, - signature.len, - ) == 0; -} - -pub const csrf__generate = @import("../runtime/api/csrf_jsc.zig").csrf__generate; -pub const csrf__verify = @import("../runtime/api/csrf_jsc.zig").csrf__verify; - -const hmac = @import("../sha_hmac/hmac.zig"); -const std = @import("std"); -const string = @import("../string/string.zig"); - -const bun = @import("bun"); -const jsc = bun.jsc; -const boring = bun.BoringSSL.c; diff --git a/src/css/build-prefixes.js b/src/css/build-prefixes.js index 91f399e208e1..d8b1017206fa 100644 --- a/src/css/build-prefixes.js +++ b/src/css/build-prefixes.js @@ -451,12 +451,7 @@ addValue( "LangSelectorList", ); -let prefixMapping = { - webkit: "webkit", - moz: "moz", - ms: "ms", - o: "o", -}; +const allBrowsers = ["android", "chrome", "edge", "firefox", "ie", "ios_saf", "opera", "safari", "samsung"]; let flags = [ "nesting", @@ -487,246 +482,223 @@ let flags = [ ], ]; -function snakecase(str) { - let s = ""; - for (let i = 0; i < str.length; i++) { - let c = str[i].charCodeAt(0); - if (c === "-") { - s += "_"; - } else { - if (i > 0 && c >= 65 && c <= 90) { - s += "_"; - } - s += str[i].toLowerCase(); - } - } - return s; +// ────────────────────────────────────────────────────────────────────────── +// Rust emission +// ────────────────────────────────────────────────────────────────────────── + +// snake_case → PascalCase for enum variants. +function pascal(s) { + return s.replace(/(?:^|[-_])([a-z0-9])/gi, (_, c) => c.toUpperCase()); } +// CSS property name → Rust enum variant. let enumify = f => - snakecase( + pascal( f - .replace(/^@([a-z])/, (_, x) => "at_" + x) - .replace(/^::([a-z])/, (_, x) => "pseudo_element_" + x) - .replace(/^:([a-z])/, (_, x) => "pseudo_class_" + x) - // .replace(/(^|-)([a-z])/g, (_, a, x) => (a === "-" ? "_" + x : x)); + .replace(/^@([a-z])/, (_, x) => "At_" + x) + .replace(/^::([a-z])/, (_, x) => "PseudoElement_" + x) + .replace(/^:([a-z])/, (_, x) => "PseudoClass_" + x) .replace(/(^|-)([a-z])/g, (_, a, x) => (a === "-" ? "_" + x : x)), ); -let field_len = 0; -let flagsZig = `pub const Features = packed struct(u32) { - ${flags - .map((flag, i) => { - if (Array.isArray(flag)) { - return `pub const ${flag[0]}: @This() = .{${flag[1].map(f => `.${f} = true,`).join("")}};`; - } else { - field_len++; - return `${flag}: bool = false,`; - } - }) - .concat(`__unused: u${32 - field_len} = 0,`) - .sort((a, b) => { - const a_is_const = a.startsWith("const"); - const b_is_const = b.startsWith("const"); - if (a_is_const && !b_is_const) return 1; - if (!a_is_const && b_is_const) return -1; - return 0; - }) - .join("\n ")} - }`; -let targets = fs - .readFileSync("src/css/targets.zig", "utf8") - .replace(/pub const Features = packed struct\(u32\) \{((?:.|\n)+?)\n\}/, flagsZig); - -console.log("TARGETS", targets); -fs.writeFileSync("src/css/targets.zig", targets); -await Bun.$`zig fmt src/css/targets.zig`; - -let targets_dts = `// This file is autogenerated by build-prefixes.js. DO NOT EDIT! - -export interface Targets { - ${allBrowsers.join("?: number,\n ")}?: number +const prefixConst = { webkit: "WEBKIT", moz: "MOZ", ms: "MS", o: "O" }; + +async function rustfmt(path) { + await Bun.$`rustfmt ${path}`.nothrow(); } -export const Features: { - ${flags - .map((flag, i) => { - if (Array.isArray(flag)) { - return `${flag[0]}: ${flag[1].reduce((p, f) => p | (1 << flags.indexOf(f)), 0)},`; - } else { - return `${flag}: ${1 << i},`; +// ─── targets.rs: rewrite the `bitflags! { ... Features ... }` block ─────── +{ + const scalar = flags.filter(f => !Array.isArray(f)); + const groups = flags.filter(f => Array.isArray(f)); + const pad = Math.max(...scalar.map(f => f.length)); + const lines = [ + `bitflags::bitflags! {`, + ` /// Autogenerated by build-prefixes.js`, + ` /// Features to explicitly enable or disable.`, + ` #[derive(Debug, Clone, Copy, PartialEq, Eq)]`, + ` pub struct Features: u32 {`, + ...scalar.map((f, i) => ` const ${f.toUpperCase().padEnd(pad)} = 1 << ${i};`), + ``, + ...groups.flatMap(([name, members], i) => { + const body = members.map(m => `Self::${m.toUpperCase()}.bits()`).join("\n | "); + const line = ` const ${name.toUpperCase()} = ${body};`; + return i > 0 ? [``, line] : [line]; + }), + ` }`, + `}`, + ].join("\n"); + + let targets = fs.readFileSync("src/css/targets.rs", "utf8"); + const re = /bitflags::bitflags! \{\n \/\/\/ Autogenerated by build-prefixes\.js(?:.|\n)+?\n \}\n\}/; + if (!re.test(targets)) { + throw new Error("build-prefixes.js: could not find the Features bitflags! block in src/css/targets.rs"); + } + targets = targets.replace(re, lines); + fs.writeFileSync("src/css/targets.rs", targets); + await rustfmt("src/css/targets.rs"); + console.log("wrote src/css/targets.rs (Features block)"); +} + +// ─── prefixes.rs ────────────────────────────────────────────────────────── +{ + const variants = [...new Set([...p.keys()].flat().map(enumify))].sort(); + const arms = []; + for (const [features, versions] of p) { + const pats = features.map(enumify).join("\n | "); + const body = []; + for (const [name, pfx] of Object.entries(versions)) { + const inner = []; + for (const [prefix, [min, max]] of Object.entries(pfx)) { + if (!prefixConst[prefix]) throw new Error("Missing prefix " + prefix); + const add = `prefixes |= VendorPrefix::${prefixConst[prefix]};`; + if (min == null && max == null) { + inner.push(` let _ = version;\n ${add}`); + } else { + let cond; + if (min == null) cond = `version <= ${max}`; + else if (max == null) cond = `version >= ${min}`; + else if (min === max) cond = `version == ${min}`; + else cond = `version >= ${min} && version <= ${max}`; + inner.push(` if ${cond} {\n ${add}\n }`); + } } - }) - .join("\n ")} -}; -`; + body.push(` if let Some(version) = browsers.${name} {\n${inner.join("\n")}\n }`); + } + arms.push(` ${pats} => {\n${body.join("\n")}\n }`); + } -// fs.writeFileSync("node/targets.d.ts", targets_dts); + const flex = Object.entries(flexSpec) + .map( + ([name, [min, max]]) => + ` if let Some(version) = browsers.${name} {\n if version >= ${min} && version <= ${max} {\n return true;\n }\n }`, + ) + .join("\n"); + const grad = Object.entries(oldGradient) + .map( + ([name, [min, max]]) => + ` if let Some(version) = browsers.${name} {\n if version >= ${min} && version <= ${max} {\n return true;\n }\n }`, + ) + .join("\n"); -let flagsJs = `// This file is autogenerated by build-prefixes.js. DO NOT EDIT! + const out = `// Autogenerated by build-prefixes.js. DO NOT EDIT! -exports.Features = { - ${flags - .map((flag, i) => { - if (Array.isArray(flag)) { - return `${flag[0]}: ${flag[1].reduce((p, f) => p | (1 << flags.indexOf(f)), 0)},`; - } else { - return `${flag}: ${1 << i},`; - } - }) - .join("\n ")} -}; -`; +#![allow(clippy::manual_range_contains)] + +use crate::VendorPrefix; +use crate::targets::Browsers; + +/// CSS features that may require a vendor prefix on one or more browsers. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum Feature { + ${variants.join(",\n ")}, +} -// fs.writeFileSync("node/flags.js", flagsJs); - -let s = `// This file is autogenerated by build-prefixes.js. DO NOT EDIT! - -const css = @import("./css_parser.zig"); -const VendorPrefix = css.VendorPrefix; -const Browsers = css.targets.Browsers; - -pub const Feature = enum { - ${[...p.keys()].flat().map(enumify).sort().join(",\n ")}, - - pub fn prefixesFor(this: *const Feature, browsers: Browsers) VendorPrefix { - var prefixes = VendorPrefix{ .none = true }; - switch (this) { - ${[...p] - .map(([features, versions]) => { - return `${features.map(name => `.${enumify(name)}`).join(" ,\n ")} => { - ${Object.entries(versions) - .map(([name, prefixes]) => { - let needsVersion = !Object.values(prefixes).every(([min, max]) => min == null && max == null); - return `if ${needsVersion ? `(browsers.${name}) |version|` : `(browsers.${name} != null)`} { - ${Object.entries(prefixes) - .map(([prefix, [min, max]]) => { - if (!prefixMapping[prefix]) { - throw new Error("Missing prefix " + prefix); - } - let addPrefix = `prefixes = prefixes.bitwiseOr(VendorPrefix{.${prefixMapping[prefix]} = true });`; - let condition; - if (min == null && max == null) { - return addPrefix; - } else if (min == null) { - condition = `version <= ${max}`; - } else if (max == null) { - condition = `version >= ${min}`; - } else if (min == max) { - condition = `version == ${min}`; - } else { - condition = `version >= ${min} and version <= ${max}`; - } - - return `if (${condition}) { - ${addPrefix} - }`; - }) - .join("\n ")} - }`; - }) - .join("\n ")} - }`; - }) - .join(",\n ")} +impl Feature { + pub fn prefixes_for(self, browsers: &Browsers) -> VendorPrefix { + use Feature::*; + let mut prefixes = VendorPrefix::NONE; + match self { +${arms.join("\n")} + } + prefixes } - return prefixes; - } -pub fn isFlex2009(browsers: Browsers) bool { - ${Object.entries(flexSpec) - .map(([name, [min, max]]) => { - return `if (browsers.${name}) |version| { - if (version >= ${min} and version <= ${max}) { - return true; + pub fn is_flex_2009(browsers: &Browsers) -> bool { +${flex} + false } - }`; - }) - .join("\n ")} - return false; -} -pub fn isWebkitGradient(browsers: Browsers) bool { - ${Object.entries(oldGradient) - .map(([name, [min, max]]) => { - return `if (browsers.${name}) |version| { - if (version >= ${min} and version <= ${max}) { - return true; + pub fn is_webkit_gradient(browsers: &Browsers) -> bool { +${grad} + false } - }`; - }) - .join("\n ")} - return false; } -}; `; + fs.writeFileSync("src/css/prefixes.rs", out); + await rustfmt("src/css/prefixes.rs"); + console.log("wrote src/css/prefixes.rs"); +} + +// ─── compat.rs ──────────────────────────────────────────────────────────── +{ + const variants = [...new Set([...compat.keys()].flat().map(enumify))].sort(); + const arms = []; + for (const [features, supported] of compat) { + const pats = features.map(n => `Feature::${enumify(n)}`).join("\n | "); + const entries = Object.entries(supported); + let body; + if (entries.length === 0) { + body = ` return false;`; + } else { + const checks = entries + .map( + ([browser, min]) => + ` if let Some(version) = browsers.${browser} {\n if version < ${min} {\n return false;\n }\n }`, + ) + .join("\n"); + const unsupported = allBrowsers.filter(b => supported[b] == null); + const unsupCheck = + unsupported.length === 0 + ? "" + : `\n if ${unsupported + .map(b => `browsers.${b}.is_some()`) + .join(" || ")} {\n return false;\n }`; + body = checks + unsupCheck; + } + arms.push(` ${pats} => {\n${body}\n }`); + } -fs.writeFileSync("src/css/prefixes.zig", s); -await Bun.$`zig fmt src/css/prefixes.zig`; + const probes = allBrowsers.map(b => ` probe!(${b});`).join("\n"); -let c = `// This file is autogenerated by build-prefixes.js. DO NOT EDIT! + const out = `// Autogenerated by build-prefixes.js. DO NOT EDIT! -const Browsers = @import("./targets.zig").Browsers; +use crate::targets::Browsers; -pub const Feature = enum { - ${[...compat.keys()].flat().map(enumify).sort().join(",\n ")}, +/// CSS feature → browser-compatibility lookup (caniuse / MDN tables). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum Feature { + ${variants.join(",\n ")}, +} - pub fn isCompatible(this: Feature, browsers: Browsers) bool { - switch (this.*) { - ${[...compat] - .map( - ([features, supportedBrowsers]) => - `${features.map(name => `.${enumify(name)}`).join(" ,\n ")} => {` + - (Object.entries(supportedBrowsers).length === 0 - ? "\n return false;\n }," - : ` - ${Object.entries(supportedBrowsers) - .map( - ([browser, min]) => - `if (browsers.${browser}) |version| { - if (version < ${min}) { - return false; - } - }`, - ) - .join("\n ")}${ - Object.keys(supportedBrowsers).length === allBrowsers.length - ? "" - : `\n if (${allBrowsers - .filter(b => !supportedBrowsers[b]) - .map(browser => `browsers.${browser} != null`) - .join(" or ")}) { - return false; - }` +impl Feature { + /// Returns whether every browser in \`browsers\` supports this feature + /// natively, without fallback. + #[allow(clippy::match_same_arms)] + pub fn is_compatible(self, browsers: &Browsers) -> bool { + match self { +${arms.join("\n")} } - },`), - ) - .join("\n ")} + true } - return true; - } - -pub fn isPartiallyCompatible(this: *const Feature, targets: Browsers) bool { - var browsers = Browsers{}; - ${allBrowsers - .map( - browser => `if (targets.${browser} != null) { - browsers.${browser} = targets.${browser}; - if (this.isCompatible(browsers)) { - return true; + /// Returns whether *any* of the given browser targets supports this + /// feature natively. + pub fn is_partially_compatible(self, targets: &Browsers) -> bool { + // Generic implementation in terms of \`is_compatible\` — + // probe each browser field one at a time. + macro_rules! probe { + ($field:ident) => { + if targets.$field.is_some() { + let mut browsers = Browsers::default(); + browsers.$field = targets.$field; + if self.is_compatible(&browsers) { + return true; + } + } + }; + } +${probes} + false } - browsers.${browser} = null; - }\n`, - ) - .join(" ")} - return false; } -}; `; - -fs.writeFileSync("src/css/compat.zig", c); -await Bun.$`zig fmt src/css/compat.zig`; + fs.writeFileSync("src/css/compat.rs", out); + await rustfmt("src/css/compat.rs"); + console.log("wrote src/css/compat.rs"); +} function parseVersion(version) { version = version.replace("≤", ""); diff --git a/src/css/compat.rs b/src/css/compat.rs index 2b556c4ddc72..4980c6bd2926 100644 --- a/src/css/compat.rs +++ b/src/css/compat.rs @@ -1,4 +1,4 @@ -// This file is autogenerated by build-prefixes.js. DO NOT EDIT! +// Autogenerated by build-prefixes.js. DO NOT EDIT! use crate::targets::Browsers; diff --git a/src/css/compat.zig b/src/css/compat.zig deleted file mode 100644 index 3e912cb4fff1..000000000000 --- a/src/css/compat.zig +++ /dev/null @@ -1,5397 +0,0 @@ -// This file is autogenerated by build-prefixes.js. DO NOT EDIT! - -pub const Feature = enum { - abs_function, - accent_system_color, - afar_list_style_type, - amharic_abegede_list_style_type, - amharic_list_style_type, - anchor_size_size, - animation_timeline_shorthand, - any_link, - any_pseudo, - arabic_indic_list_style_type, - armenian_list_style_type, - asterisks_list_style_type, - auto_size, - autofill, - bengali_list_style_type, - binary_list_style_type, - border_image_repeat_round, - border_image_repeat_space, - calc_function, - cambodian_list_style_type, - cap_unit, - case_insensitive, - ch_unit, - circle_list_style_type, - cjk_decimal_list_style_type, - cjk_earthly_branch_list_style_type, - cjk_heavenly_stem_list_style_type, - clamp_function, - color_function, - conic_gradient, - container_query_length_units, - cue, - cue_function, - custom_media_queries, - decimal_leading_zero_list_style_type, - decimal_list_style_type, - default_pseudo, - devanagari_list_style_type, - dialog, - dir_selector, - disc_list_style_type, - disclosure_closed_list_style_type, - disclosure_open_list_style_type, - double_position_gradients, - em_unit, - ethiopic_abegede_am_et_list_style_type, - ethiopic_abegede_gez_list_style_type, - ethiopic_abegede_list_style_type, - ethiopic_abegede_ti_er_list_style_type, - ethiopic_abegede_ti_et_list_style_type, - ethiopic_halehame_aa_er_list_style_type, - ethiopic_halehame_aa_et_list_style_type, - ethiopic_halehame_am_et_list_style_type, - ethiopic_halehame_gez_list_style_type, - ethiopic_halehame_om_et_list_style_type, - ethiopic_halehame_sid_et_list_style_type, - ethiopic_halehame_so_et_list_style_type, - ethiopic_halehame_tig_list_style_type, - ethiopic_list_style_type, - ethiopic_numeric_list_style_type, - ex_unit, - extended_system_fonts, - first_letter, - first_line, - fit_content_function_size, - fit_content_size, - focus_visible, - focus_within, - font_family_system_ui, - font_size_rem, - font_size_x_x_x_large, - font_stretch_percentage, - font_style_oblique_angle, - font_weight_number, - footnotes_list_style_type, - form_validation, - fullscreen, - gencontent, - georgian_list_style_type, - gradient_interpolation_hints, - gujarati_list_style_type, - gurmukhi_list_style_type, - has_selector, - hebrew_list_style_type, - hex_alpha_colors, - hiragana_iroha_list_style_type, - hiragana_list_style_type, - hypot_function, - ic_unit, - image_set, - in_out_of_range, - indeterminate_pseudo, - is_animatable_size, - is_selector, - japanese_formal_list_style_type, - japanese_informal_list_style_type, - kannada_list_style_type, - katakana_iroha_list_style_type, - katakana_list_style_type, - khmer_list_style_type, - korean_hangul_formal_list_style_type, - korean_hanja_formal_list_style_type, - korean_hanja_informal_list_style_type, - lab_colors, - lang_selector_list, - lao_list_style_type, - lh_unit, - light_dark, - linear_gradient, - logical_border_radius, - logical_border_shorthand, - logical_borders, - logical_inset, - logical_margin, - logical_margin_shorthand, - logical_padding, - logical_padding_shorthand, - logical_size, - logical_text_align, - lower_alpha_list_style_type, - lower_armenian_list_style_type, - lower_greek_list_style_type, - lower_hexadecimal_list_style_type, - lower_latin_list_style_type, - lower_norwegian_list_style_type, - lower_roman_list_style_type, - malayalam_list_style_type, - marker_pseudo, - max_content_size, - max_function, - media_interval_syntax, - media_range_syntax, - min_content_size, - min_function, - mod_function, - mongolian_list_style_type, - moz_available_size, - myanmar_list_style_type, - namespaces, - nesting, - none_list_style_type, - not_selector_list, - nth_child_of, - octal_list_style_type, - oklab_colors, - optional_pseudo, - oriya_list_style_type, - oromo_list_style_type, - overflow_shorthand, - p3_colors, - part_pseudo, - persian_list_style_type, - place_content, - place_items, - place_self, - placeholder, - placeholder_shown, - q_unit, - radial_gradient, - rcap_unit, - rch_unit, - read_only_write, - rem_function, - rem_unit, - repeating_conic_gradient, - repeating_linear_gradient, - repeating_radial_gradient, - rex_unit, - ric_unit, - rlh_unit, - round_function, - selection, - selectors2, - selectors3, - shadowdomv1, - sidama_list_style_type, - sign_function, - simp_chinese_formal_list_style_type, - simp_chinese_informal_list_style_type, - somali_list_style_type, - space_separated_color_notation, - square_list_style_type, - stretch_size, - string_list_style_type, - symbols_list_style_type, - tamil_list_style_type, - telugu_list_style_type, - text_decoration_thickness_percent, - text_decoration_thickness_shorthand, - thai_list_style_type, - tibetan_list_style_type, - tigre_list_style_type, - tigrinya_er_abegede_list_style_type, - tigrinya_er_list_style_type, - tigrinya_et_abegede_list_style_type, - tigrinya_et_list_style_type, - trad_chinese_formal_list_style_type, - trad_chinese_informal_list_style_type, - upper_alpha_list_style_type, - upper_armenian_list_style_type, - upper_hexadecimal_list_style_type, - upper_latin_list_style_type, - upper_norwegian_list_style_type, - upper_roman_list_style_type, - vb_unit, - vh_unit, - vi_unit, - viewport_percentage_units_dynamic, - viewport_percentage_units_large, - viewport_percentage_units_small, - vmax_unit, - vmin_unit, - vw_unit, - webkit_fill_available_size, - x_resolution_unit, - - pub fn isCompatible(this: Feature, browsers: Browsers) bool { - switch (this) { - .selectors2 => { - if (browsers.ie) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 131072) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 196864) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 197120) { - return false; - } - } - if (browsers.android) |version| { - if (version < 131328) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - }, - .selectors3 => { - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 197888) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 197120) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 591104) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 197120) { - return false; - } - } - if (browsers.android) |version| { - if (version < 131328) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - }, - .gencontent, .first_line => { - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 131072) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 196864) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 197120) { - return false; - } - } - if (browsers.android) |version| { - if (version < 131328) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - }, - .first_letter => { - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 197888) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327936) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 722432) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 196608) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - }, - .in_out_of_range => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3276800) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3473408) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2621440) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .form_validation => { - if (browsers.ie) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263171) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - }, - .any_link => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3276800) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 4259840) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3407872) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 590336) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .default_pseudo => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3342336) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2490368) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .dir_selector => { - if (browsers.edge) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3211264) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 6946816) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .focus_within => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3407872) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3932160) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3080192) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 524800) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .focus_visible => { - if (browsers.edge) |version| { - if (version < 5636096) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5570560) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 5636096) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4718592) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .indeterminate_pseudo => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3342336) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 2555904) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 1703936) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .is_selector => { - if (browsers.edge) |version| { - if (version < 5767168) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5111808) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 5767168) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .optional_pseudo => { - if (browsers.ie) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 131840) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - }, - .placeholder_shown => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3342336) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3080192) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2228224) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .dialog => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 6422528) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 2424832) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 1572864) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .fullscreen => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4194304) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 4653056) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 786688) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.android != null or browsers.ie != null or browsers.ios_saf != null) { - return false; - } - }, - .marker_pseudo => { - if (browsers.edge) |version| { - if (version < 5636096) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4456448) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 5636096) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4718592) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.ie != null or browsers.ios_saf != null or browsers.safari != null) { - return false; - } - }, - .placeholder => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3342336) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3735552) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2883584) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 459264) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .selection => { - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 196864) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 591104) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ios_saf != null) { - return false; - } - }, - .case_insensitive => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3080192) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3211264) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2359296) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .read_only_write => { - if (browsers.edge) |version| { - if (version < 851968) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5111808) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 2359296) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 1507328) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .autofill => { - if (browsers.chrome) |version| { - if (version < 7208960) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7208960) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5636096) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 6291456) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1376256) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .namespaces => { - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 131072) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 262656) { - return false; - } - } - if (browsers.android) |version| { - if (version < 131328) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - }, - .shadowdomv1 => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4128768) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3473408) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2621440) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 393728) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .hex_alpha_colors => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3211264) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3407872) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 524800) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .nesting => { - if (browsers.edge) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7667712) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 6946816) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.ie != null or browsers.samsung != null) { - return false; - } - }, - .not_selector_list => { - if (browsers.edge) |version| { - if (version < 5767168) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5505024) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 5767168) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .has_selector => { - if (browsers.edge) |version| { - if (version < 6881280) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7929856) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 6881280) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1310720) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .font_family_system_ui => { - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 6029312) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 3670016) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2818048) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 393728) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .extended_system_fonts => { - if (browsers.safari) |version| { - if (version < 852224) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 852992) { - return false; - } - } - if (browsers.android != null or browsers.chrome != null or browsers.edge != null or browsers.firefox != null or browsers.ie != null or browsers.opera != null or browsers.samsung != null) { - return false; - } - }, - .calc_function => { - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 1048576) { - return false; - } - } - if (browsers.chrome) |version| { - if (version < 1703936) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 393472) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8585216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .custom_media_queries, .fit_content_function_size, .stretch_size => { - return false; - }, - .double_position_gradients => { - if (browsers.chrome) |version| { - if (version < 4653056) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4194304) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3276800) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 786688) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 786944) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4653056) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .clamp_function => { - if (browsers.chrome) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3735552) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 852224) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 852992) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .place_self, .place_items => { - if (browsers.chrome) |version| { - if (version < 3866624) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2949120) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2818048) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.android) |version| { - if (version < 3866624) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .place_content => { - if (browsers.chrome) |version| { - if (version < 3866624) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2949120) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2818048) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.android) |version| { - if (version < 3866624) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .overflow_shorthand => { - if (browsers.chrome) |version| { - if (version < 4456448) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3997696) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3145728) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 852224) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 852992) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4456448) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .media_range_syntax => { - if (browsers.chrome) |version| { - if (version < 6815744) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 6815744) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4128768) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4653056) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1310720) { - return false; - } - } - if (browsers.android) |version| { - if (version < 6815744) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .media_interval_syntax => { - if (browsers.chrome) |version| { - if (version < 6815744) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 6815744) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 6684672) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4653056) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1310720) { - return false; - } - } - if (browsers.android) |version| { - if (version < 6815744) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .logical_borders => { - if (browsers.chrome) |version| { - if (version < 4521984) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2686976) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3145728) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 786688) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 786944) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4521984) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .logical_border_shorthand, .logical_margin_shorthand, .logical_padding_shorthand => { - if (browsers.chrome) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4325376) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 917760) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 918784) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .logical_border_radius => { - if (browsers.chrome) |version| { - if (version < 5832704) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5832704) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4325376) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4128768) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5832704) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .logical_margin, .logical_padding => { - if (browsers.chrome) |version| { - if (version < 4521984) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2686976) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3145728) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 786688) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 786944) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .logical_inset => { - if (browsers.chrome) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4128768) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 917760) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 918784) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .logical_size => { - if (browsers.chrome) |version| { - if (version < 3735552) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2686976) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2818048) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 786688) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 786944) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 3735552) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .logical_text_align => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 196864) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 131072) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2424832) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .lab_colors => { - if (browsers.chrome) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7405568) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1441792) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .oklab_colors => { - if (browsers.chrome) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7405568) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1441792) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .color_function => { - if (browsers.chrome) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7405568) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1441792) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .space_separated_color_notation => { - if (browsers.chrome) |version| { - if (version < 4259840) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3407872) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3080192) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 786688) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 786944) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4259840) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .text_decoration_thickness_percent => { - if (browsers.chrome) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1115136) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1115136) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .text_decoration_thickness_shorthand => { - if (browsers.chrome) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5701632) { - return false; - } - } - if (browsers.ie != null or browsers.ios_saf != null or browsers.safari != null) { - return false; - } - }, - .cue => { - if (browsers.chrome) |version| { - if (version < 1703936) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3604480) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .cue_function => { - if (browsers.chrome) |version| { - if (version < 1703936) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null) { - return false; - } - }, - .any_pseudo => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2424832) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .part_pseudo => { - if (browsers.chrome) |version| { - if (version < 4784128) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3407872) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 852224) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 852992) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4784128) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .image_set => { - if (browsers.chrome) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5767168) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 393216) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 393216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .x_resolution_unit => { - if (browsers.chrome) |version| { - if (version < 4456448) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3145728) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4456448) { - return false; - } - } - if (browsers.ie != null or browsers.ios_saf != null or browsers.safari != null) { - return false; - } - }, - .nth_child_of => { - if (browsers.chrome) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7405568) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1441792) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .min_function, .max_function => { - if (browsers.chrome) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3735552) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 721152) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 721664) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .round_function, .rem_function, .mod_function => { - if (browsers.chrome) |version| { - if (version < 8192000) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 8192000) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5439488) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8192000) { - return false; - } - } - if (browsers.ie != null or browsers.samsung != null) { - return false; - } - }, - .abs_function, .sign_function => { - if (browsers.firefox) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.android != null or browsers.chrome != null or browsers.edge != null or browsers.ie != null or browsers.opera != null or browsers.samsung != null) { - return false; - } - }, - .hypot_function => { - if (browsers.chrome) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5242880) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .gradient_interpolation_hints => { - if (browsers.chrome) |version| { - if (version < 2621440) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2359296) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 1769472) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2621440) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .border_image_repeat_round => { - if (browsers.chrome) |version| { - if (version < 1966080) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 590080) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 590592) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 131072) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .border_image_repeat_space => { - if (browsers.chrome) |version| { - if (version < 3670016) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3276800) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2818048) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 590080) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 590592) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 393216) { - return false; - } - } - if (browsers.android) |version| { - if (version < 3670016) { - return false; - } - } - }, - .font_size_rem => { - if (browsers.chrome) |version| { - if (version < 2752512) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2031616) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 1835008) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2752512) { - return false; - } - } - }, - .font_size_x_x_x_large => { - if (browsers.chrome) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3735552) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .font_style_oblique_angle => { - if (browsers.chrome) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3997696) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3014656) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 721152) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 721664) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 524288) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .font_weight_number => { - if (browsers.chrome) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 1114112) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3997696) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3014656) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 524288) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .font_stretch_percentage => { - if (browsers.chrome) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3997696) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3014656) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 721152) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 721664) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 524288) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4063232) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .light_dark => { - if (browsers.chrome) |version| { - if (version < 8060928) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 8060928) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5373952) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1115392) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1115392) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8060928) { - return false; - } - } - if (browsers.ie != null or browsers.samsung != null) { - return false; - } - }, - .accent_system_color => { - if (browsers.firefox) |version| { - if (version < 6750208) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049856) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1049856) { - return false; - } - } - if (browsers.android != null or browsers.chrome != null or browsers.edge != null or browsers.ie != null or browsers.opera != null or browsers.samsung != null) { - return false; - } - }, - .animation_timeline_shorthand => { - if (browsers.chrome) |version| { - if (version < 7536640) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7536640) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5046272) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1507328) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7536640) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null or browsers.ios_saf != null or browsers.safari != null) { - return false; - } - }, - .q_unit => { - if (browsers.chrome) |version| { - if (version < 4128768) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 3211264) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3014656) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 852224) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 852992) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 524288) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4128768) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .cap_unit => { - if (browsers.chrome) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 6356992) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .ch_unit => { - if (browsers.chrome) |version| { - if (version < 1769472) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .container_query_length_units => { - if (browsers.chrome) |version| { - if (version < 6881280) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 6881280) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7208960) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4718592) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1048576) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1048576) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1310720) { - return false; - } - } - if (browsers.android) |version| { - if (version < 6881280) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .em_unit => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 196608) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 65536) { - return false; - } - } - }, - .ex_unit, .circle_list_style_type, .decimal_list_style_type, .disc_list_style_type, .square_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .ic_unit => { - if (browsers.chrome) |version| { - if (version < 6946816) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 6946816) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 6356992) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4718592) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1310720) { - return false; - } - } - if (browsers.android) |version| { - if (version < 6946816) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .lh_unit => { - if (browsers.chrome) |version| { - if (version < 7143424) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7143424) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4849664) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1376256) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7143424) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .rcap_unit => { - if (browsers.chrome) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7733248) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null) { - return false; - } - }, - .rch_unit, .rex_unit, .ric_unit => { - if (browsers.chrome) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1114624) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1441792) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null) { - return false; - } - }, - .rem_unit => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 131072) { - return false; - } - } - }, - .rlh_unit => { - if (browsers.chrome) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 7864320) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4915200) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 1049600) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1441792) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7274496) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .vb_unit, .vi_unit, .viewport_percentage_units_dynamic, .viewport_percentage_units_large, .viewport_percentage_units_small => { - if (browsers.chrome) |version| { - if (version < 7077888) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 7077888) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 6619136) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4784128) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 984064) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1376256) { - return false; - } - } - if (browsers.android) |version| { - if (version < 7077888) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .vh_unit, .vw_unit => { - if (browsers.chrome) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 1245184) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 589824) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 393216) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 393216) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .vmax_unit => { - if (browsers.chrome) |version| { - if (version < 1703936) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 1048576) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 1245184) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .vmin_unit => { - if (browsers.chrome) |version| { - if (version < 1703936) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 1245184) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .conic_gradient, .repeating_conic_gradient => { - if (browsers.chrome) |version| { - if (version < 4521984) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5439488) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3145728) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 786688) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 786944) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.android) |version| { - if (version < 4521984) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .linear_gradient, .repeating_linear_gradient => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327936) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2424832) { - return false; - } - } - }, - .radial_gradient => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327936) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2424832) { - return false; - } - } - }, - .repeating_radial_gradient => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 655360) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327936) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .afar_list_style_type, .amharic_list_style_type, .amharic_abegede_list_style_type, .ethiopic_list_style_type, .ethiopic_abegede_list_style_type, .ethiopic_abegede_am_et_list_style_type, .ethiopic_abegede_gez_list_style_type, .ethiopic_abegede_ti_er_list_style_type, .ethiopic_abegede_ti_et_list_style_type, .ethiopic_halehame_aa_er_list_style_type, .ethiopic_halehame_aa_et_list_style_type, .ethiopic_halehame_am_et_list_style_type, .ethiopic_halehame_gez_list_style_type, .ethiopic_halehame_om_et_list_style_type, .ethiopic_halehame_sid_et_list_style_type, .ethiopic_halehame_so_et_list_style_type, .ethiopic_halehame_tig_list_style_type, .lower_hexadecimal_list_style_type, .lower_norwegian_list_style_type, .upper_hexadecimal_list_style_type, .upper_norwegian_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 262656) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 196608) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null) { - return false; - } - }, - .arabic_indic_list_style_type, .bengali_list_style_type, .cjk_earthly_branch_list_style_type, .cjk_heavenly_stem_list_style_type, .devanagari_list_style_type, .gujarati_list_style_type, .gurmukhi_list_style_type, .kannada_list_style_type, .khmer_list_style_type, .lao_list_style_type, .malayalam_list_style_type, .myanmar_list_style_type, .oriya_list_style_type, .persian_list_style_type, .telugu_list_style_type, .thai_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 262656) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .armenian_list_style_type, .decimal_leading_zero_list_style_type, .georgian_list_style_type, .lower_alpha_list_style_type, .lower_greek_list_style_type, .lower_roman_list_style_type, .upper_alpha_list_style_type, .upper_latin_list_style_type, .upper_roman_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 524288) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .asterisks_list_style_type, .footnotes_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327936) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null) { - return false; - } - }, - .binary_list_style_type, .octal_list_style_type, .oromo_list_style_type, .sidama_list_style_type, .somali_list_style_type, .tigre_list_style_type, .tigrinya_er_list_style_type, .tigrinya_er_abegede_list_style_type, .tigrinya_et_list_style_type, .tigrinya_et_abegede_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 262656) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null) { - return false; - } - }, - .cambodian_list_style_type, .mongolian_list_style_type, .tibetan_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2162688) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 262656) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .cjk_decimal_list_style_type => { - if (browsers.chrome) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 1835008) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4194304) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1048576) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .disclosure_closed_list_style_type, .disclosure_open_list_style_type => { - if (browsers.chrome) |version| { - if (version < 5832704) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5832704) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2162688) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4128768) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5832704) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .ethiopic_numeric_list_style_type, .japanese_formal_list_style_type, .japanese_informal_list_style_type, .tamil_list_style_type => { - if (browsers.chrome) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 4194304) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 1048576) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5963776) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .hebrew_list_style_type, .hiragana_list_style_type, .hiragana_iroha_list_style_type, .katakana_list_style_type, .katakana_iroha_list_style_type, .auto_size => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .korean_hangul_formal_list_style_type, .korean_hanja_formal_list_style_type, .korean_hanja_informal_list_style_type => { - if (browsers.chrome) |version| { - if (version < 2949120) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 1835008) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2097152) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2949120) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .lower_armenian_list_style_type, .upper_armenian_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2162688) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 327936) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .lower_latin_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 524288) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .none_list_style_type => { - if (browsers.chrome) |version| { - if (version < 1179648) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 65536) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .simp_chinese_formal_list_style_type, .simp_chinese_informal_list_style_type, .trad_chinese_formal_list_style_type, .trad_chinese_informal_list_style_type => { - if (browsers.chrome) |version| { - if (version < 2949120) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2097152) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 983040) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 2949120) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .string_list_style_type => { - if (browsers.chrome) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 2555904) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 3735552) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 917760) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 918784) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.android) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .symbols_list_style_type => { - if (browsers.firefox) |version| { - if (version < 2293760) { - return false; - } - } - if (browsers.android != null or browsers.chrome != null or browsers.edge != null or browsers.ie != null or browsers.ios_saf != null or browsers.opera != null or browsers.safari != null or browsers.samsung != null) { - return false; - } - }, - .anchor_size_size => { - if (browsers.chrome) |version| { - if (version < 8192000) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 8192000) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 5439488) { - return false; - } - } - if (browsers.android) |version| { - if (version < 8192000) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null or browsers.ios_saf != null or browsers.safari != null or browsers.samsung != null) { - return false; - } - }, - .fit_content_size => { - if (browsers.chrome) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .is_animatable_size => { - if (browsers.chrome) |version| { - if (version < 1703936) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 786432) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 1048576) { - return false; - } - } - if (browsers.ie) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - }, - .max_content_size => { - if (browsers.chrome) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2818048) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 66816) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .min_content_size => { - if (browsers.chrome) |version| { - if (version < 3014656) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 2162688) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 720896) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 3014656) { - return false; - } - } - if (browsers.ie != null) { - return false; - } - }, - .webkit_fill_available_size => { - if (browsers.chrome) |version| { - if (version < 1638400) { - return false; - } - } - if (browsers.edge) |version| { - if (version < 5177344) { - return false; - } - } - if (browsers.opera) |version| { - if (version < 917504) { - return false; - } - } - if (browsers.safari) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 458752) { - return false; - } - } - if (browsers.samsung) |version| { - if (version < 327680) { - return false; - } - } - if (browsers.android) |version| { - if (version < 263168) { - return false; - } - } - if (browsers.firefox != null or browsers.ie != null) { - return false; - } - }, - .moz_available_size => { - if (browsers.firefox) |version| { - if (version < 262144) { - return false; - } - } - if (browsers.android != null or browsers.chrome != null or browsers.edge != null or browsers.ie != null or browsers.ios_saf != null or browsers.opera != null or browsers.safari != null or browsers.samsung != null) { - return false; - } - }, - .p3_colors, .lang_selector_list => { - if (browsers.safari) |version| { - if (version < 655616) { - return false; - } - } - if (browsers.ios_saf) |version| { - if (version < 656128) { - return false; - } - } - if (browsers.android != null or browsers.chrome != null or browsers.edge != null or browsers.firefox != null or browsers.ie != null or browsers.opera != null or browsers.samsung != null) { - return false; - } - }, - } - return true; - } - - pub fn isPartiallyCompatible(this: *const Feature, targets: Browsers) bool { - var browsers = Browsers{}; - if (targets.android != null) { - browsers.android = targets.android; - if (this.isCompatible(browsers)) { - return true; - } - browsers.android = null; - } - if (targets.chrome != null) { - browsers.chrome = targets.chrome; - if (this.isCompatible(browsers)) { - return true; - } - browsers.chrome = null; - } - if (targets.edge != null) { - browsers.edge = targets.edge; - if (this.isCompatible(browsers)) { - return true; - } - browsers.edge = null; - } - if (targets.firefox != null) { - browsers.firefox = targets.firefox; - if (this.isCompatible(browsers)) { - return true; - } - browsers.firefox = null; - } - if (targets.ie != null) { - browsers.ie = targets.ie; - if (this.isCompatible(browsers)) { - return true; - } - browsers.ie = null; - } - if (targets.ios_saf != null) { - browsers.ios_saf = targets.ios_saf; - if (this.isCompatible(browsers)) { - return true; - } - browsers.ios_saf = null; - } - if (targets.opera != null) { - browsers.opera = targets.opera; - if (this.isCompatible(browsers)) { - return true; - } - browsers.opera = null; - } - if (targets.safari != null) { - browsers.safari = targets.safari; - if (this.isCompatible(browsers)) { - return true; - } - browsers.safari = null; - } - if (targets.samsung != null) { - browsers.samsung = targets.samsung; - if (this.isCompatible(browsers)) { - return true; - } - browsers.samsung = null; - } - - return false; - } -}; - -const Browsers = @import("./targets.zig").Browsers; diff --git a/src/css/context.zig b/src/css/context.zig deleted file mode 100644 index 6bdc1bbdd108..000000000000 --- a/src/css/context.zig +++ /dev/null @@ -1,307 +0,0 @@ -pub const css = @import("./css_parser.zig"); - -const MediaRule = css.css_rules.media.MediaRule; -const MediaQuery = css.media_query.MediaQuery; -const MediaCondition = css.media_query.MediaCondition; -const MediaList = css.media_query.MediaList; -const MediaFeature = css.media_query.MediaFeature; -const MediaFeatureId = css.media_query.MediaFeatureId; - -const UnparsedProperty = css.css_properties.custom.UnparsedProperty; - -pub const SupportsEntry = struct { - condition: css.SupportsCondition, - declarations: ArrayList(css.Property), - important_declarations: ArrayList(css.Property), - - pub fn deinit(this: *@This(), allocator: std.mem.Allocator) void { - this.condition.deinit(allocator); - css.deepDeinit(css.Property, allocator, &this.declarations); - css.deepDeinit(css.Property, allocator, &this.important_declarations); - } -}; - -pub const DeclarationContext = enum { - none, - style_rule, - keyframes, - style_attribute, -}; - -pub const PropertyHandlerContext = struct { - allocator: Allocator, - targets: css.targets.Targets, - is_important: bool, - supports: ArrayList(SupportsEntry), - ltr: ArrayList(css.Property), - rtl: ArrayList(css.Property), - dark: ArrayList(css.Property), - context: DeclarationContext, - unused_symbols: *const std.StringArrayHashMapUnmanaged(void), - - pub fn new( - allocator: Allocator, - targets: css.targets.Targets, - unused_symbols: *const std.StringArrayHashMapUnmanaged(void), - ) PropertyHandlerContext { - return PropertyHandlerContext{ - .allocator = allocator, - .targets = targets, - .is_important = false, - .supports = ArrayList(SupportsEntry){}, - .ltr = ArrayList(css.Property){}, - .rtl = ArrayList(css.Property){}, - .dark = ArrayList(css.Property){}, - .context = DeclarationContext.none, - .unused_symbols = unused_symbols, - }; - } - - pub fn child(this: *const PropertyHandlerContext, context: DeclarationContext) PropertyHandlerContext { - return PropertyHandlerContext{ - .allocator = this.allocator, - .targets = this.targets, - .is_important = false, - .supports = .{}, - .ltr = .{}, - .rtl = .{}, - .dark = .{}, - .context = context, - .unused_symbols = this.unused_symbols, - }; - } - - pub fn addDarkRule(this: *@This(), allocator: Allocator, property: css.Property) void { - bun.handleOom(this.dark.append(allocator, property)); - } - - pub fn addLogicalRule(this: *@This(), allocator: Allocator, ltr: css.Property, rtl: css.Property) void { - this.ltr.append(allocator, ltr) catch unreachable; - this.rtl.append(allocator, rtl) catch unreachable; - } - - pub fn shouldCompileLogical(this: *const @This(), feature: css.compat.Feature) bool { - // Don't convert logical properties in style attributes because - // our fallbacks rely on extra rules to define --ltr and --rtl. - if (this.context == DeclarationContext.style_attribute) return false; - - return this.targets.shouldCompileLogical(feature); - } - - pub fn getSupportsRules( - this: *const @This(), - comptime T: type, - style_rule: *const css.StyleRule(T), - ) ArrayList(css.CssRule(T)) { - if (this.supports.items.len == 0) { - return .{}; - } - - var dest = ArrayList(css.CssRule(T)).initCapacity( - this.allocator, - this.supports.items.len, - ) catch |err| bun.handleOom(err); - - for (this.supports.items) |*entry| { - dest.appendAssumeCapacity(css.CssRule(T){ - .supports = css.SupportsRule(T){ - .condition = entry.condition.deepClone(this.allocator), - .rules = css.CssRuleList(T){ - .v = v: { - var v = bun.handleOom(ArrayList(css.CssRule(T)).initCapacity(this.allocator, 1)); - - v.appendAssumeCapacity(.{ .style = css.StyleRule(T){ - .selectors = style_rule.selectors.deepClone(this.allocator), - .vendor_prefix = css.VendorPrefix{ .none = true }, - .declarations = css.DeclarationBlock{ - .declarations = css.deepClone(css.Property, this.allocator, &entry.declarations), - .important_declarations = css.deepClone(css.Property, this.allocator, &entry.important_declarations), - }, - .rules = css.CssRuleList(T){}, - .loc = style_rule.loc, - } }); - - break :v v; - }, - }, - .loc = style_rule.loc, - }, - }); - } - - return dest; - } - - pub fn getAdditionalRules( - this: *const @This(), - comptime T: type, - style_rule: *const css.StyleRule(T), - ) ArrayList(css.CssRule(T)) { - // TODO: :dir/:lang raises the specificity of the selector. Use :where to lower it? - var dest = ArrayList(css.CssRule(T)){}; - - if (this.ltr.items.len > 0) { - getAdditionalRulesHelper(this, T, "ltr", "ltr", style_rule, &dest); - } - - if (this.rtl.items.len > 0) { - getAdditionalRulesHelper(this, T, "rtl", "rtl", style_rule, &dest); - } - - if (this.dark.items.len > 0) { - dest.append(this.allocator, css.CssRule(T){ - .media = MediaRule(T){ - .query = MediaList{ - .media_queries = brk: { - var list = ArrayList(MediaQuery).initCapacity( - this.allocator, - 1, - ) catch |err| bun.handleOom(err); - - list.appendAssumeCapacity(MediaQuery{ - .qualifier = null, - .media_type = .all, - .condition = MediaCondition{ - .feature = MediaFeature{ - .plain = .{ - .name = .{ .standard = MediaFeatureId.@"prefers-color-scheme" }, - .value = .{ .ident = .{ .v = "dark" } }, - }, - }, - }, - }); - - break :brk list; - }, - }, - .rules = brk: { - var list: css.CssRuleList(T) = .{}; - - list.v.append(this.allocator, css.CssRule(T){ - .style = css.StyleRule(T){ - .selectors = style_rule.selectors.deepClone(this.allocator), - .vendor_prefix = css.VendorPrefix{ .none = true }, - .declarations = css.DeclarationBlock{ - .declarations = css.deepClone(css.Property, this.allocator, &this.dark), - .important_declarations = .{}, - }, - .rules = .{}, - .loc = style_rule.loc, - }, - }) catch |err| bun.handleOom(err); - - break :brk list; - }, - .loc = style_rule.loc, - }, - }) catch |err| bun.handleOom(err); - } - - return dest; - } - pub fn getAdditionalRulesHelper( - this: *const @This(), - comptime T: type, - comptime dir: []const u8, - comptime decls: []const u8, - sty: *const css.StyleRule(T), - dest: *ArrayList(css.CssRule(T)), - ) void { - var selectors = sty.selectors.deepClone(this.allocator); - for (selectors.v.slice_mut()) |*selector| { - selector.append(this.allocator, css.Component{ - .non_ts_pseudo_class = css.PseudoClass{ - .dir = .{ .direction = @field(css.selector.parser.Direction, dir) }, - }, - }); - } - - const rule = css.StyleRule(T){ - .selectors = selectors, - .vendor_prefix = css.VendorPrefix{ .none = true }, - .declarations = css.DeclarationBlock{ - .declarations = css.deepClone(css.Property, this.allocator, &@field(this, decls)), - .important_declarations = .{}, - }, - .rules = .{}, - .loc = sty.loc, - }; - - bun.handleOom(dest.append(this.allocator, .{ .style = rule })); - } - - pub fn reset(this: *@This()) void { - for (this.supports.items) |*supp| { - supp.deinit(this.allocator); - } - this.supports.clearRetainingCapacity(); - - for (this.ltr.items) |*ltr| { - ltr.deinit(this.allocator); - } - this.ltr.clearRetainingCapacity(); - - for (this.rtl.items) |*rtl| { - rtl.deinit(this.allocator); - } - this.rtl.clearRetainingCapacity(); - - for (this.dark.items) |*dark| { - dark.deinit(this.allocator); - } - this.dark.clearRetainingCapacity(); - } - - pub fn addConditionalProperty(this: *@This(), condition: css.SupportsCondition, property: css.Property) void { - if (this.context != DeclarationContext.style_rule) return; - - if (brk: { - for (this.supports.items) |*supp| { - if (condition.eql(&supp.condition)) break :brk supp; - } - break :brk null; - }) |entry| { - if (this.is_important) { - bun.handleOom(entry.important_declarations.append(this.allocator, property)); - } else { - bun.handleOom(entry.declarations.append(this.allocator, property)); - } - } else { - var important_declarations = ArrayList(css.Property){}; - var declarations = ArrayList(css.Property){}; - if (this.is_important) { - bun.handleOom(important_declarations.append(this.allocator, property)); - } else { - bun.handleOom(declarations.append(this.allocator, property)); - } - this.supports.append(this.allocator, SupportsEntry{ - .condition = condition, - .declarations = declarations, - .important_declarations = important_declarations, - }) catch |err| bun.handleOom(err); - } - } - - pub fn addUnparsedFallbacks(this: *@This(), unparsed: *UnparsedProperty) void { - if (this.context != DeclarationContext.style_rule and this.context != DeclarationContext.style_attribute) { - return; - } - - const fallbacks = unparsed.value.getFallbacks(this.allocator, this.targets); - - for (fallbacks.slice()) |condition_and_fallback| { - this.addConditionalProperty(condition_and_fallback[0], css.Property{ - .unparsed = UnparsedProperty{ - .property_id = unparsed.property_id.deepClone(this.allocator), - .value = condition_and_fallback[1], - }, - }); - } - } -}; - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/css_modules.zig b/src/css/css_modules.zig deleted file mode 100644 index 9e6ea427d11b..000000000000 --- a/src/css/css_modules.zig +++ /dev/null @@ -1,430 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const css_values = @import("./values/values.zig"); -pub const Error = css.Error; -const PrintErr = css.PrintErr; - -pub const CssModule = struct { - config: *const Config, - sources: *const ArrayList([]const u8), - hashes: ArrayList([]const u8), - exports_by_source_index: ArrayList(CssModuleExports), - references: *CssModuleReferences, - - pub fn new( - allocator: Allocator, - config: *const Config, - sources: *const ArrayList([]const u8), - project_root: ?[]const u8, - references: *CssModuleReferences, - ) CssModule { - // TODO: this is BAAAAAAAAAAD we are going to remove it - const hashes = hashes: { - var hashes = bun.handleOom(ArrayList([]const u8).initCapacity(allocator, sources.items.len)); - for (sources.items) |path| { - var alloced = false; - const source = source: { - // Make paths relative to project root so hashes are stable - if (project_root) |root| { - if (bun.path.Platform.auto.isAbsolute(root)) { - alloced = true; - break :source bun.handleOom(allocator.dupe(u8, bun.path.relative(root, path))); - } - } - break :source path; - }; - defer if (alloced) allocator.free(source); - hashes.appendAssumeCapacity(hash( - allocator, - "{s}", - .{source}, - config.pattern.segments.at(0).* == .hash, - )); - } - break :hashes hashes; - }; - const exports_by_source_index = exports_by_source_index: { - var exports_by_source_index = bun.handleOom(ArrayList(CssModuleExports).initCapacity(allocator, sources.items.len)); - exports_by_source_index.appendNTimesAssumeCapacity(CssModuleExports{}, sources.items.len); - break :exports_by_source_index exports_by_source_index; - }; - return CssModule{ - .config = config, - .sources = sources, - .references = references, - .hashes = hashes, - .exports_by_source_index = exports_by_source_index, - }; - } - - pub fn deinit(this: *CssModule) void { - _ = this; // autofix - // TODO: deinit - } - - pub fn getReference(this: *CssModule, allocator: Allocator, name: []const u8, source_index: u32) void { - const gop = bun.handleOom(this.exports_by_source_index.items[source_index].getOrPut(allocator, name)); - if (gop.found_existing) { - gop.value_ptr.is_referenced = true; - } else { - gop.value_ptr.* = CssModuleExport{ - .name = this.config.pattern.writeToString(allocator, .{}, this.hashes.items[source_index], this.sources.items[source_index], name), - .composes = .{}, - .is_referenced = true, - }; - } - } - - pub fn referenceDashed( - this: *CssModule, - dest: *css.Printer, - name: []const u8, - from: *const ?css.css_properties.css_modules.Specifier, - source_index: u32, - ) PrintErr!?[]const u8 { - const allocator = dest.allocator; - const reference, const key = if (from.*) |specifier| switch (specifier) { - .global => return name[2..], - .import_record_index => |import_record_index| init: { - const import_record = try dest.importRecord(import_record_index); - break :init .{ - CssModuleReference{ - .dependency = .{ - .name = name[2..], - .specifier = import_record.path.text, - }, - }, - import_record.path.text, - }; - }, - } else { - // Local export. Mark as used. - const gop = bun.handleOom(this.exports_by_source_index.items[source_index].getOrPut(allocator, name)); - if (gop.found_existing) { - gop.value_ptr.is_referenced = true; - } else { - var res = ArrayList(u8){}; - bun.handleOom(res.appendSlice(allocator, "--")); - gop.value_ptr.* = CssModuleExport{ - .name = this.config.pattern.writeToString( - allocator, - res, - this.hashes.items[source_index], - this.sources.items[source_index], - name[2..], - ), - .composes = .{}, - .is_referenced = true, - }; - } - return null; - }; - - const the_hash = hash(allocator, "{s}_{s}_{s}", .{ this.hashes.items[source_index], name, key }, false); - - this.references.put( - allocator, - bun.handleOom(std.fmt.allocPrint(allocator, "--{s}", .{the_hash})), - reference, - ) catch |err| bun.handleOom(err); - - return the_hash; - } - - pub fn handleComposes( - _: *CssModule, - _: *css.Printer, - selectors: *const css.selector.parser.SelectorList, - _: *const css.css_properties.css_modules.Composes, - _: u32, - ) css.Maybe(void, css.PrinterErrorKind) { - // const allocator = dest.allocator; - for (selectors.v.slice()) |*sel| { - if (sel.len() == 1 and sel.components.items[0] == .class) { - continue; - } - - // The composes property can only be used within a simple class selector. - return .{ .err = css.PrinterErrorKind.invalid_composes_selector }; - } - - return .success; - } - - pub fn addDashed(this: *CssModule, allocator: Allocator, local: []const u8, source_index: u32) void { - const gop = bun.handleOom(this.exports_by_source_index.items[source_index].getOrPut(allocator, local)); - if (!gop.found_existing) { - gop.value_ptr.* = CssModuleExport{ - // todo_stuff.depth - .name = this.config.pattern.writeToStringWithPrefix( - allocator, - "--", - this.hashes.items[source_index], - this.sources.items[source_index], - local[2..], - ), - .composes = .{}, - .is_referenced = false, - }; - } - } - - pub fn addLocal(this: *CssModule, allocator: Allocator, exported: []const u8, local: []const u8, source_index: u32) void { - const gop = bun.handleOom(this.exports_by_source_index.items[source_index].getOrPut(allocator, exported)); - if (!gop.found_existing) { - gop.value_ptr.* = CssModuleExport{ - // todo_stuff.depth - .name = this.config.pattern.writeToString( - allocator, - .{}, - this.hashes.items[source_index], - this.sources.items[source_index], - local, - ), - .composes = .{}, - .is_referenced = false, - }; - } - } -}; - -/// Configuration for CSS modules. -pub const Config = struct { - /// The name pattern to use when renaming class names and other identifiers. - /// Default is `[hash]_[local]`. - pattern: Pattern = .{}, - - /// Whether to rename dashed identifiers, e.g. custom properties. - dashed_idents: bool = false, - - /// Whether to scope animation names. - /// Default is `true`. - animation: bool = true, - - /// Whether to scope grid names. - /// Default is `true`. - grid: bool = true, - - /// Whether to scope custom identifiers - /// Default is `true`. - custom_idents: bool = true, -}; - -/// A CSS modules class name pattern. -pub const Pattern = struct { - /// The list of segments in the pattern. - segments: css.SmallList(Segment, 3) = css.SmallList(Segment, 3).initInlined(&[_]Segment{ .local, .{ .literal = "_" }, .hash }), - - /// Write the substituted pattern to a destination. - pub fn write( - this: *const Pattern, - hash_: []const u8, - path: []const u8, - local: []const u8, - closure: anytype, - comptime writefn: *const fn (@TypeOf(closure), []const u8, replace_dots: bool) void, - ) void { - for (this.segments.slice()) |*segment| { - switch (segment.*) { - .literal => |s| { - writefn(closure, s, false); - }, - .name => { - const stem = std.fs.path.stem(path); - if (std.mem.indexOf(u8, stem, ".")) |_| { - writefn(closure, stem, true); - } else { - writefn(closure, stem, false); - } - }, - .local => { - writefn(closure, local, false); - }, - .hash => { - writefn(closure, hash_, false); - }, - } - } - } - - pub fn writeToStringWithPrefix( - this: *const Pattern, - allocator: Allocator, - comptime prefix: []const u8, - hash_: []const u8, - path: []const u8, - local: []const u8, - ) []const u8 { - const Closure = struct { res: ArrayList(u8), allocator: Allocator }; - var closure = Closure{ .res = .{}, .allocator = allocator }; - this.write( - hash_, - path, - local, - &closure, - struct { - pub fn writefn(self: *Closure, slice: []const u8, replace_dots: bool) void { - bun.handleOom(self.res.appendSlice(self.allocator, prefix)); - if (replace_dots) { - const start = self.res.items.len; - bun.handleOom(self.res.appendSlice(self.allocator, slice)); - const end = self.res.items.len; - for (self.res.items[start..end]) |*c| { - if (c.* == '.') { - c.* = '-'; - } - } - return; - } - bun.handleOom(self.res.appendSlice(self.allocator, slice)); - } - }.writefn, - ); - return closure.res.items; - } - - pub fn writeToString( - this: *const Pattern, - allocator: Allocator, - res_: ArrayList(u8), - hash_: []const u8, - path: []const u8, - local: []const u8, - ) []const u8 { - var res = res_; - const Closure = struct { res: *ArrayList(u8), allocator: Allocator }; - var closure = Closure{ .res = &res, .allocator = allocator }; - this.write( - hash_, - path, - local, - &closure, - struct { - pub fn writefn(self: *Closure, slice: []const u8, replace_dots: bool) void { - if (replace_dots) { - const start = self.res.items.len; - bun.handleOom(self.res.appendSlice(self.allocator, slice)); - const end = self.res.items.len; - for (self.res.items[start..end]) |*c| { - if (c.* == '.') { - c.* = '-'; - } - } - return; - } - bun.handleOom(self.res.appendSlice(self.allocator, slice)); - return; - } - }.writefn, - ); - - return res.items; - } -}; - -/// A segment in a CSS modules class name pattern. -/// -/// See [Pattern](Pattern). -pub const Segment = union(enum) { - /// A literal string segment. - literal: []const u8, - - /// The base file name. - name, - - /// The original class name. - local, - - /// A hash of the file name. - hash, -}; - -/// A map of exported names to values. -pub const CssModuleExports = std.StringArrayHashMapUnmanaged(CssModuleExport); - -/// A map of placeholders to references. -pub const CssModuleReferences = std.StringArrayHashMapUnmanaged(CssModuleReference); - -/// An exported value from a CSS module. -pub const CssModuleExport = struct { - /// The local (compiled) name for this export. - name: []const u8, - /// Other names that are composed by this export. - composes: ArrayList(CssModuleReference), - /// Whether the export is referenced in this file. - is_referenced: bool, -}; - -/// A referenced name within a CSS module, e.g. via the `composes` property. -/// -/// See [CssModuleExport](CssModuleExport). -pub const CssModuleReference = union(enum) { - /// A local reference. - local: struct { - /// The local (compiled) name for the reference. - name: []const u8, - }, - /// A global reference. - global: struct { - /// The referenced global name. - name: []const u8, - }, - /// A reference to an export in a different file. - dependency: struct { - /// The name to reference within the dependency. - name: []const u8, - /// The dependency specifier for the referenced file. - /// - /// import record idx - specifier: []const u8, - }, - - pub fn eql(this: *const @This(), other: *const @This()) bool { - if (@intFromEnum(this.*) != @intFromEnum(other.*)) return false; - - return switch (this.*) { - .local => |v| bun.strings.eql(v.name, other.local.name), - .global => |v| bun.strings.eql(v.name, other.global.name), - // .dependency => |v| bun.strings.eql(v.name, other.dependency.name) and bun.strings.eql(v.specifier, other.dependency.specifier), - .dependency => |v| bun.strings.eql(v.name, other.dependency.name) and bun.strings.eql(v.specifier, other.dependency.specifier), - }; - } -}; - -// TODO: replace with bun's hash -pub fn hash(allocator: Allocator, comptime fmt: []const u8, args: anytype, at_start: bool) []const u8 { - const count = std.fmt.count(fmt, args); - var stack_fallback = std.heap.stackFallback(128, allocator); - const fmt_alloc = if (count <= 128) stack_fallback.get() else allocator; - var hasher = bun.Wyhash11.init(0); - var fmt_str = bun.handleOom(std.fmt.allocPrint(fmt_alloc, fmt, args)); - hasher.update(fmt_str); - - const h: u32 = @truncate(hasher.final()); - var h_bytes: [4]u8 = undefined; - std.mem.writeInt(u32, &h_bytes, h, .little); - - const encode_len = bun.base64.simdutfEncodeLenUrlSafe(h_bytes[0..].len); - - var slice_to_write = if (encode_len <= 128 - @as(usize, @intFromBool(at_start))) - bun.handleOom(allocator.alloc(u8, encode_len + @as(usize, @intFromBool(at_start)))) - else - fmt_str[0..]; - - const base64_encoded_hash_len = bun.base64.simdutfEncodeUrlSafe(slice_to_write, &h_bytes); - - const base64_encoded_hash = slice_to_write[0..base64_encoded_hash_len]; - - if (at_start and base64_encoded_hash.len > 0 and base64_encoded_hash[0] >= '0' and base64_encoded_hash[0] <= '9') { - std.mem.copyBackwards(u8, slice_to_write[1..][0..base64_encoded_hash_len], base64_encoded_hash); - slice_to_write[0] = '_'; - return slice_to_write[0 .. base64_encoded_hash_len + 1]; - } - - return base64_encoded_hash; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/css_parser.zig b/src/css/css_parser.zig deleted file mode 100644 index fefc5aa4acb2..000000000000 --- a/src/css/css_parser.zig +++ /dev/null @@ -1,7329 +0,0 @@ -pub const SrcIndex = bun.bundle_v2.Index; - -pub const SymbolList = bun.ast.Symbol.List; - -pub const ImportRecord = bun.ImportRecord; -pub const ImportKind = bun.ImportKind; - -pub const prefixes = @import("./prefixes.zig"); - -pub const dependencies = @import("./dependencies.zig"); -pub const Dependency = dependencies.Dependency; - -pub const css_modules = @import("./css_modules.zig"); -pub const CssModuleExports = css_modules.CssModuleExports; -pub const CssModule = css_modules.CssModule; -pub const CssModuleReferences = css_modules.CssModuleReferences; -pub const CssModuleReference = css_modules.CssModuleReference; -pub const CssModuleConfig = css_modules.Config; - -pub const css_rules = @import("./rules/rules.zig"); -pub const CssRule = css_rules.CssRule; -pub const CssRuleList = css_rules.CssRuleList; -pub const LayerName = css_rules.layer.LayerName; -pub const LayerStatementRule = css_rules.layer.LayerStatementRule; -pub const SupportsCondition = css_rules.supports.SupportsCondition; -pub const CustomMedia = css_rules.custom_media.CustomMediaRule; -pub const NamespaceRule = css_rules.namespace.NamespaceRule; -pub const UnknownAtRule = css_rules.unknown.UnknownAtRule; -pub const ImportRule = css_rules.import.ImportRule; -pub const StyleRule = css_rules.style.StyleRule; -pub const StyleContext = css_rules.StyleContext; -pub const SupportsRule = css_rules.supports.SupportsRule; -pub const TailwindAtRule = css_rules.tailwind.TailwindAtRule; - -pub const MinifyContext = css_rules.MinifyContext; - -pub const media_query = @import("./media_query.zig"); -pub const MediaList = media_query.MediaList; -pub const MediaFeatureType = media_query.MediaFeatureType; - -pub const css_values = @import("./values/values.zig"); -pub const DashedIdent = css_values.ident.DashedIdent; -pub const DashedIdentFns = css_values.ident.DashedIdentFns; -pub const CssColor = css_values.color.CssColor; -pub const ColorFallbackKind = css_values.color.ColorFallbackKind; -pub const CSSString = css_values.string.CSSString; -pub const CSSStringFns = css_values.string.CSSStringFns; -pub const CSSInteger = css_values.number.CSSInteger; -pub const CSSIntegerFns = css_values.number.CSSIntegerFns; -pub const CSSNumber = css_values.number.CSSNumber; -pub const CSSNumberFns = css_values.number.CSSNumberFns; -pub const Ident = css_values.ident.Ident; -pub const IdentFns = css_values.ident.IdentFns; -pub const CustomIdent = css_values.ident.CustomIdent; -pub const CustomIdentFns = css_values.ident.CustomIdentFns; -pub const Url = css_values.url.Url; - -pub const declaration = @import("./declaration.zig"); - -pub const css_properties = @import("./properties/properties.zig"); -pub const Property = css_properties.Property; -pub const PropertyId = css_properties.PropertyId; -pub const PropertyIdTag = css_properties.PropertyIdTag; -pub const TokenList = css_properties.custom.TokenList; -pub const TokenListFns = css_properties.custom.TokenListFns; - -pub const DeclarationList = css_decls.DeclarationList; -pub const DeclarationBlock = css_decls.DeclarationBlock; - -pub const selector = @import("./selectors/selector.zig"); -pub const SelectorList = selector.parser.SelectorList; -pub const Selector = selector.parser.Selector; -pub const Component = selector.parser.Component; -pub const PseudoClass = selector.parser.PseudoClass; -pub const PseudoElement = selector.parser.PseudoElement; - -pub const logical = @import("./logical.zig"); -pub const PropertyCategory = logical.PropertyCategory; -pub const LogicalGroup = logical.LogicalGroup; - -pub const css_printer = @import("./printer.zig"); -pub const Printer = css_printer.Printer; -pub const PrinterOptions = css_printer.PrinterOptions; -pub const targets = @import("./targets.zig"); -pub const Targets = css_printer.Targets; -pub const ImportInfo = css_printer.ImportInfo; -// pub const Features = css_printer.Features; - -pub const PropertyHandlerContext = context.PropertyHandlerContext; -pub const DeclarationHandler = declaration.DeclarationHandler; - -pub const Maybe = bun.jsc.Node.Maybe; -// TODO: Remove existing Error defined here and replace it with these -pub const Err = errors_.Err; -pub const PrinterErrorKind = errors_.PrinterErrorKind; -pub const PrinterError = errors_.PrinterError; -pub const ErrorLocation = errors_.ErrorLocation; -pub const ParseError = errors_.ParseError; -pub const ParserError = errors_.ParserError; -pub const BasicParseError = errors_.BasicParseError; -pub const BasicParseErrorKind = errors_.BasicParseErrorKind; -pub const SelectorError = errors_.SelectorError; -pub const MinifyErrorKind = errors_.MinifyErrorKind; -pub const MinifyError = errors_.MinifyError; -pub const MinifyErr = errors_.MinifyErr; - -pub const generic = @import("./generics.zig"); -pub const HASH_SEED = generic.HASH_SEED; - -pub const ImportConditions = css_rules.import.ImportConditions; - -pub const compat = @import("./compat.zig"); - -pub const Features = targets.Features; -pub const Feature = compat.Feature; - -pub const fmtPrinterError = errors_.fmtPrinterError; - -pub const PrintErr = error{ - CSSPrintError, -}; - -pub fn OOM(e: anyerror) noreturn { - if (comptime bun.Environment.isDebug) { - std.debug.assert(e == std.mem.Allocator.Error.OutOfMemory); - } - bun.outOfMemory(); -} - -pub const SmallList = @import("./small_list.zig").SmallList; - -pub const todo_stuff = struct { - pub const think_mem_mgmt = "TODO: think about memory management"; - - pub const depth = "TODO: we need to go deeper"; - - pub const match_ignore_ascii_case = "TODO: implement match_ignore_ascii_case"; - - pub const enum_property = "TODO: implement enum_property!"; - - pub const match_byte = "TODO: implement match_byte!"; - - pub const warn = "TODO: implement warning"; -}; - -pub const VendorPrefix = packed struct(u8) { - /// No vendor prefixes. - /// 0b00000001 - none: bool = false, - /// The `-webkit` vendor prefix. - /// 0b00000010 - webkit: bool = false, - /// The `-moz` vendor prefix. - /// 0b00000100 - moz: bool = false, - /// The `-ms` vendor prefix. - /// 0b00001000 - ms: bool = false, - /// The `-o` vendor prefix. - /// 0b00010000 - o: bool = false, - __unused: u3 = 0, - - pub const empty = VendorPrefix{}; - pub const all = VendorPrefix{ - .none = true, - .moz = true, - .ms = true, - .o = true, - .webkit = true, - }; - - pub const NONE = VendorPrefix{ .none = true }; - pub const WEBKIT = VendorPrefix{ .webkit = true }; - pub const MOZ = VendorPrefix{ .moz = true }; - pub const MS = VendorPrefix{ .ms = true }; - pub const O = VendorPrefix{ .o = true }; - - /// Fields listed here so we can iterate them in the order we want - pub const FIELDS: []const []const u8 = &.{ "webkit", "moz", "ms", "o", "none" }; - - pub fn toCss(this: *const VendorPrefix, dest: *Printer) PrintErr!void { - return switch (this.asBits()) { - VendorPrefix.asBits(.{ .webkit = true }) => dest.writeStr("-webkit-"), - VendorPrefix.asBits(.{ .moz = true }) => dest.writeStr("-moz-"), - VendorPrefix.asBits(.{ .ms = true }) => dest.writeStr("-ms-"), - VendorPrefix.asBits(.{ .o = true }) => dest.writeStr("-o-"), - else => {}, - }; - } - - pub inline fn fromName(comptime name: []const u8) VendorPrefix { - comptime { - var vp: VendorPrefix = .{}; - @field(vp, name) = true; - return vp; - } - } - - /// Returns VendorPrefix::None if empty. - pub inline fn orNone(this: VendorPrefix) VendorPrefix { - return this._or(VendorPrefix{ .none = true }); - } - - /// **WARNING**: NOT THE SAME as .bitwiseOr!! - pub inline fn _or(this: VendorPrefix, other: VendorPrefix) VendorPrefix { - if (this.isEmpty()) return other; - return this; - } - - pub fn difference(left: @This(), right: @This()) @This() { - return @bitCast(@as(u8, @bitCast(left)) - @as(u8, @bitCast(right))); - } - - pub fn isEmpty(this: VendorPrefix) bool { - return this == VendorPrefix{}; - } - - pub fn bitwiseAnd(a: @This(), b: @This()) @This() { - return bun.bits.@"and"(@This(), a, b); - } - - pub fn asBits(vp: @This()) u8 { - return @bitCast(vp); - } -}; - -pub const SourceLocation = struct { - line: u32, - column: u32, - - pub fn toLoggerLocation(this: SourceLocation, file: []const u8) bun.logger.Location { - return bun.logger.Location{ - .file = file, - .line = @intCast(this.line), - .column = @intCast(this.column), - }; - } - - /// Create a new BasicParseError at this location for an unexpected token - pub fn newBasicUnexpectedTokenError(this: SourceLocation, token: Token) ParseError(ParserError) { - return BasicParseError.intoDefaultParseError(.{ - .kind = .{ .unexpected_token = token }, - .location = this, - }); - } - - /// Create a new ParseError at this location for an unexpected token - pub fn newUnexpectedTokenError(this: SourceLocation, token: Token) ParseError(ParserError) { - return ParseError(ParserError){ - .kind = .{ .basic = .{ .unexpected_token = token } }, - .location = this, - }; - } - - pub fn newCustomError(this: SourceLocation, err: anytype) ParseError(ParserError) { - return switch (@TypeOf(err)) { - ParserError => .{ - .kind = .{ .custom = err }, - .location = this, - }, - BasicParseError => .{ - .kind = .{ .custom = BasicParseError.intoDefaultParseError(err) }, - .location = this, - }, - selector.parser.SelectorParseErrorKind => .{ - .kind = .{ .custom = selector.parser.SelectorParseErrorKind.intoDefaultParserError(err) }, - .location = this, - }, - else => @compileError("TODO implement this for: " ++ @typeName(@TypeOf(err))), - }; - } -}; -pub const Location = css_rules.Location; - -pub const Error = Err(ParserError); - -pub fn Result(comptime T: type) type { - @setEvalBranchQuota(1_000_000); - return Maybe(T, ParseError(ParserError)); -} - -pub fn PrintResult(comptime T: type) type { - return Maybe(T, PrinterError); -} - -pub fn todo(comptime fmt: []const u8, args: anytype) noreturn { - bun.analytics.Features.todo_panic = 1; - std.debug.panic("TODO: " ++ fmt, args); -} - -pub fn voidWrap(comptime T: type, comptime parsefn: *const fn (*Parser) Result(T)) *const fn (void, *Parser) Result(T) { - const Wrapper = struct { - fn wrapped(_: void, p: *Parser) Result(T) { - return parsefn(p); - } - }; - return Wrapper.wrapped; -} - -pub fn DefineListShorthand(comptime T: type) type { - _ = T; // autofix - // TODO: implement this when we implement visit? - // does nothing now - return struct {}; -} - -pub fn DefineShorthand(comptime T: type, comptime property_name: PropertyIdTag, comptime PropertyFieldMap: anytype) type { - _ = property_name; // autofix - // TODO: validate map, make sure each field is set - // make sure each field is same index as in T - _ = PropertyFieldMap; - - return struct { - /// Returns a shorthand from the longhand properties defined in the given declaration block. - pub fn fromLonghands(allocator: Allocator, decls: *const DeclarationBlock, vendor_prefix: VendorPrefix) ?struct { T, bool } { - _ = allocator; // autofix - _ = decls; // autofix - _ = vendor_prefix; // autofix - // var count: usize = 0; - // var important_count: usize = 0; - // var this: T = undefined; - // var set_fields = std.StaticBitSet(std.meta.fields(T).len).initEmpty(); - // const all_fields_set = std.StaticBitSet(std.meta.fields(T).len).initFull(); - - // // Loop through each property in `decls.declarations` and then `decls.important_declarations` - // // The inline for loop is so we can share the code for both - // const DECL_FIELDS = &.{ "declarations", "important_declarations" }; - // inline for (DECL_FIELDS) |decl_field_name| { - // const decl_list: *const ArrayList(css_properties.Property) = &@field(decls, decl_field_name); - // const important = comptime std.mem.eql(u8, decl_field_name, "important_declarations"); - - // // Now loop through each property in the list - // main_loop: for (decl_list.items) |*property| { - // // The property field map maps each field in `T` to a tag of `Property` - // // Here we do `inline for` to basically switch on the tag of `property` to see - // // if it matches a field in `T` which maps to the same tag - // // - // // Basically, check that `@as(PropertyIdTag, property.*)` equals `T.PropertyFieldMap[field.name]` - // inline for (std.meta.fields(@TypeOf(T.PropertyFieldMap))) |field| { - // const tag: PropertyIdTag = @as(?*const PropertyIdTag, field.default_value).?.*; - - // if (@intFromEnum(@as(PropertyIdTag, property.*)) == tag) { - // if (@hasField(T.VendorPrefixMap, field.name)) { - // if (@hasField(T.VendorPrefixMap, field.name) and - // !VendorPrefix.eq(@field(property, field.name)[1], vendor_prefix)) - // { - // return null; - // } - - // @field(this, field.name) = if (@hasDecl(@TypeOf(@field(property, field.name)[0]), "clone")) - // @field(property, field.name)[0].deepClone(allocator) - // else - // @field(property, field.name)[0]; - // } else { - // @field(this, field.name) = if (@hasDecl(@TypeOf(@field(property, field.name)), "clone")) - // @field(property, field.name).deepClone(allocator) - // else - // @field(property, field.name); - // } - - // set_fields.set(std.meta.fieldIndex(T, field.name)); - // count += 1; - // if (important) { - // important_count += 1; - // } - - // continue :main_loop; - // } - // } - - // // If `property` matches none of the tags in `T.PropertyFieldMap` then let's try - // // if it matches the tag specified by `property_name` - // if (@as(PropertyIdTag, property.*) == property_name) { - // inline for (std.meta.fields(@TypeOf(T.PropertyFieldMap))) |field| { - // if (@hasField(T.VendorPrefixMap, field.name)) { - // @field(this, field.name) = if (@hasDecl(@TypeOf(@field(property, field.name)[0]), "clone")) - // @field(property, field.name)[0].deepClone(allocator) - // else - // @field(property, field.name)[0]; - // } else { - // @field(this, field.name) = if (@hasDecl(@TypeOf(@field(property, field.name)), "clone")) - // @field(property, field.name).deepClone(allocator) - // else - // @field(property, field.name); - // } - - // set_fields.set(std.meta.fieldIndex(T, field.name)); - // count += 1; - // if (important) { - // important_count += 1; - // } - // } - // continue :main_loop; - // } - - // // Otherwise, try to convert to te fields using `.longhand()` - // inline for (std.meta.fields(@TypeOf(T.PropertyFieldMap))) |field| { - // const property_id = @unionInit( - // PropertyId, - // field.name, - // if (@hasDecl(T.VendorPrefixMap, field.name)) vendor_prefix, - // ); - // const value = property.longhand(&property_id); - // if (@as(PropertyIdTag, value) == @as(PropertyIdTag, property_id)) { - // @field(this, field.name) = if (@hasDecl(T.VendorPrefixMap, field.name)) - // @field(value, field.name)[0] - // else - // @field(value, field.name); - // set_fields.set(std.meta.fieldIndex(T, field.name)); - // count += 1; - // if (important) { - // important_count += 1; - // } - // } - // } - // } - // } - - // if (important_count > 0 and important_count != count) { - // return null; - // } - - // // All properties in the group must have a matching value to produce a shorthand. - // if (set_fields.eql(all_fields_set)) { - // return .{ this, important_count > 0 }; - // } - - // return null; - @compileError(todo_stuff.depth); - } - - /// Returns a shorthand from the longhand properties defined in the given declaration block. - pub fn longhands(vendor_prefix: VendorPrefix) []const PropertyId { - _ = vendor_prefix; // autofix - // const out: []const PropertyId = comptime out: { - // var out: [std.meta.fields(@TypeOf(T.PropertyFieldMap)).len]PropertyId = undefined; - - // for (std.meta.fields(@TypeOf(T.PropertyFieldMap)), 0..) |field, i| { - // out[i] = @unionInit( - // PropertyId, - // field.name, - // if (@hasField(T.VendorPrefixMap, field.name)) vendor_prefix, - // ); - // } - - // break :out out; - // }; - // return out; - - @compileError(todo_stuff.depth); - } - - /// Returns a longhand property for this shorthand. - pub fn longhand(this: *const T, allocator: Allocator, property_id: *const PropertyId) ?Property { - _ = this; // autofix - _ = allocator; // autofix - _ = property_id; // autofix - // inline for (std.meta.fields(@TypeOf(T.PropertyFieldMap))) |field| { - // if (@as(PropertyIdTag, property_id.*) == @field(T.PropertyFieldMap, field.name)) { - // const val = if (@hasDecl(@TypeOf(@field(T, field.namee)), "clone")) - // @field(this, field.name).deepClone(allocator) - // else - // @field(this, field.name); - // return @unionInit( - // Property, - // field.name, - // if (@field(T.VendorPrefixMap, field.name)) - // .{ val, @field(property_id, field.name)[1] } - // else - // val, - // ); - // } - // } - // return null; - @compileError(todo_stuff.depth); - } - - /// Updates this shorthand from a longhand property. - pub fn setLonghand(this: *T, allocator: Allocator, property: *const Property) bool { - _ = this; // autofix - _ = allocator; // autofix - _ = property; // autofix - // inline for (std.meta.fields(T.PropertyFieldMap)) |field| { - // if (@as(PropertyIdTag, property.*) == @field(T.PropertyFieldMap, field.name)) { - // const val = if (@hasDecl(@TypeOf(@field(T, field.name)), "clone")) - // @field(this, field.name).deepClone(allocator) - // else - // @field(this, field.name); - - // @field(this, field.name) = val; - - // return true; - // } - // } - // return false; - @compileError(todo_stuff.depth); - } - }; -} - -pub fn DefineRectShorthand(comptime T: type, comptime V: type) type { - return struct { - pub fn parse(input: *Parser) Result(T) { - const rect = switch (css_values.rect.Rect(V).parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - return .{ - .result = .{ - .top = rect.top, - .right = rect.right, - .bottom = rect.bottom, - .left = rect.left, - }, - }; - } - - pub fn toCss(this: *const T, dest: *Printer) PrintErr!void { - const rect = css_values.rect.Rect(V){ - .top = this.top, - .right = this.right, - .bottom = this.bottom, - .left = this.left, - }; - return rect.toCss(dest); - } - }; -} - -pub fn DefineSizeShorthand(comptime T: type, comptime V: type) type { - if (std.meta.fields(T).len != 2) @compileError("DefineSizeShorthand must be used on a struct with 2 fields"); - return struct { - pub fn toCss(this: *const T, dest: *Printer) PrintErr!void { - const size: css_values.size.Size2D(V) = .{ - .a = @field(this, std.meta.fields(T)[0].name), - .b = @field(this, std.meta.fields(T)[1].name), - }; - return size.toCss(dest); - // TODO: unfuck this - // @panic(todo_stuff.depth); - } - - pub fn parse(input: *Parser) Result(T) { - const size = switch (css_values.size.Size2D(V).parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - var this: T = undefined; - @field(this, std.meta.fields(T)[0].name) = size.a; - @field(this, std.meta.fields(T)[1].name) = size.b; - - return .{ .result = this }; - // TODO: unfuck this - // @panic(todo_stuff.depth); - } - }; -} - -pub fn DeriveParse(comptime T: type) type { - const tyinfo = @typeInfo(T); - const is_union_enum = tyinfo == .@"union"; - const enum_type = if (comptime is_union_enum) @typeInfo(tyinfo.@"union".tag_type.?) else tyinfo; - const enum_actual_type = if (comptime is_union_enum) tyinfo.@"union".tag_type.? else T; - - const Map = bun.ComptimeEnumMap(enum_actual_type); - - return struct { - pub fn parse(input: *Parser) Result(T) { - if (comptime is_union_enum) { - const payload_count, const first_payload_index, const void_count, const first_void_index = comptime counts: { - var first_void_index: ?usize = null; - var first_payload_index: ?usize = null; - var payload_count: usize = 0; - var void_count: usize = 0; - for (tyinfo.@"union".fields, 0..) |field, i| { - if (field.type == void) { - void_count += 1; - if (first_void_index == null) first_void_index = i; - } else { - payload_count += 1; - if (first_payload_index == null) first_payload_index = i; - } - } - if (first_payload_index == null) { - @compileError("Type defined as `union(enum)` but no variant carries a payload. Make it an `enum` instead."); - } - if (first_void_index) |void_index| { - // Check if they overlap - if (first_payload_index.? < void_index and void_index < first_payload_index.? + payload_count) @compileError("Please put all the fields with data together and all the fields with no data together."); - if (first_payload_index.? > void_index and first_payload_index.? < void_index + void_count) @compileError("Please put all the fields with data together and all the fields with no data together."); - } - break :counts .{ payload_count, first_payload_index.?, void_count, first_void_index }; - }; - - return generateCode(input, first_payload_index, first_void_index, void_count, payload_count); - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (Map.getCaseInsensitiveWithEql(ident, bun.strings.eqlComptimeIgnoreLen)) |matched| { - inline for (bun.meta.EnumFields(enum_actual_type)) |field| { - if (field.value == @intFromEnum(matched)) { - if (comptime is_union_enum) return .{ .result = @unionInit(T, field.name, void) }; - return .{ .result = @enumFromInt(field.value) }; - } - } - unreachable; - } - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - /// Comptime code which constructs the parsing code for a union(enum) which could contain - /// void fields (fields with no associated data) and payload fields (fields which carry data), - /// for example: - /// - /// ```zig - /// /// A value for the [border-width](https://www.w3.org/TR/css-backgrounds-3/#border-width) property. - /// pub const BorderSideWidth = union(enum) { - /// /// A UA defined `thin` value. - /// thin, - /// /// A UA defined `medium` value. - /// medium, - /// /// A UA defined `thick` value. - /// thick, - /// /// An explicit width. - /// length: Length, - /// } - /// ``` - /// - /// During parsing, we can check if it is one of the void fields (in this case `thin`, `medium`, or `thick`) by reading a single - /// identifier from the Parser, and checking if it matches any of the void field names. We already constructed a ComptimeEnumMap (see above) - /// to make this super cheap. - /// - /// If we don't get an identifier that matches any of the void fields, we can then try to parse the payload fields. - /// - /// This function is made more complicated by the fact that it tries to parse in order of the fields that were declared in the union(enum). - /// If, for example, all the void fields were declared after the `length: Length` field, this function will try to parse the `length` field first, - /// and then try to parse the void fields. - /// - /// This parsing order is a detail copied from LightningCSS. I'm not sure if it is necessary. But it could be. - inline fn generateCode( - input: *Parser, - comptime first_payload_index: usize, - comptime maybe_first_void_index: ?usize, - comptime void_count: usize, - comptime payload_count: usize, - ) Result(T) { - const last_payload_index = first_payload_index + payload_count - 1; - if (comptime maybe_first_void_index == null) { - inline for (tyinfo.@"union".fields[first_payload_index .. first_payload_index + payload_count], first_payload_index..) |field, i| { - if (comptime (i == last_payload_index)) { - return .{ .result = switch (generic.parseFor(field.type)(input)) { - .result => |v| @unionInit(T, field.name, v), - .err => |e| return .{ .err = e }, - } }; - } - if (input.tryParse(generic.parseFor(field.type), .{}).asValue()) |v| { - return .{ .result = @unionInit(T, field.name, v) }; - } - } - } - - const first_void_index = maybe_first_void_index.?; - - const void_fields = bun.meta.EnumFields(T)[first_void_index .. first_void_index + void_count]; - - if (comptime void_count == 1) { - const void_field = enum_type.@"enum".fields[first_void_index]; - // The field is declared before the payload fields. - // So try to parse an ident matching the name of the field, then fallthrough - // to parsing the payload fields. - if (comptime first_void_index < first_payload_index) { - if (input.tryParse(Parser.expectIdentMatching, .{void_field.name}).isOk()) { - if (comptime is_union_enum) return .{ .result = @unionInit(T, void_field.name, {}) }; - return .{ .result = @enumFromInt(void_field.value) }; - } - - inline for (tyinfo.@"union".fields[first_payload_index .. first_payload_index + payload_count], first_payload_index..) |field, i| { - if (comptime (i == last_payload_index and last_payload_index > first_void_index)) { - return .{ .result = switch (generic.parseFor(field.type)(input)) { - .result => |v| @unionInit(T, field.name, v), - .err => |e| return .{ .err = e }, - } }; - } - if (input.tryParse(generic.parseFor(field.type), .{}).asValue()) |v| { - return .{ .result = @unionInit(T, field.name, v) }; - } - } - } else { - inline for (tyinfo.@"union".fields[first_payload_index .. first_payload_index + payload_count], first_payload_index..) |field, i| { - if (comptime (i == last_payload_index and last_payload_index > first_void_index)) { - return .{ .result = switch (generic.parseFor(field.type)(input)) { - .result => |v| @unionInit(T, field.name, v), - .err => |e| return .{ .err = e }, - } }; - } - if (input.tryParse(generic.parseFor(field.type), .{}).asValue()) |v| { - return .{ .result = @unionInit(T, field.name, v) }; - } - } - - // We can generate this as the last statements of the function, avoiding the `input.tryParse` routine above - if (input.expectIdentMatching(void_field.name).asErr()) |e| return .{ .err = e }; - if (comptime is_union_enum) return .{ .result = @unionInit(T, void_field.name, {}) }; - return .{ .result = @enumFromInt(void_field.value) }; - } - } else if (comptime first_void_index < first_payload_index) { - // Multiple fields declared before the payload fields, use tryParse - const state = input.state(); - if (input.tryParse(Parser.expectIdent, .{}).asValue()) |ident| { - if (Map.getCaseInsensitiveWithEql(ident, bun.strings.eqlComptimeIgnoreLen)) |matched| { - inline for (void_fields) |field| { - if (field.value == @intFromEnum(matched)) { - if (comptime is_union_enum) return .{ .result = @unionInit(T, field.name, {}) }; - return .{ .result = @enumFromInt(field.value) }; - } - } - unreachable; - } - input.reset(&state); - } - - inline for (tyinfo.@"union".fields[first_payload_index .. first_payload_index + payload_count], first_payload_index..) |field, i| { - if (comptime (i == last_payload_index and last_payload_index > first_void_index)) { - return .{ .result = switch (generic.parseFor(field.type)(input)) { - .result => |v| @unionInit(T, field.name, v), - .err => |e| return .{ .err = e }, - } }; - } - if (input.tryParse(generic.parseFor(field.type), .{}).asValue()) |v| { - return .{ .result = @unionInit(T, field.name, v) }; - } - } - } else if (comptime first_void_index > first_payload_index) { - inline for (tyinfo.@"union".fields[first_payload_index .. first_payload_index + payload_count], first_payload_index..) |field, i| { - if (comptime (i == last_payload_index and last_payload_index > first_void_index)) { - return .{ .result = switch (generic.parseFor(field.type)(input)) { - .result => |v| @unionInit(T, field.name, v), - .err => |e| return .{ .err = e }, - } }; - } - if (input.tryParse(generic.parseFor(field.type), .{}).asValue()) |v| { - return .{ .result = @unionInit(T, field.name, v) }; - } - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (Map.getCaseInsensitiveWithEql(ident, bun.strings.eqlComptimeIgnoreLen)) |matched| { - inline for (void_fields) |field| { - if (field.value == @intFromEnum(matched)) { - if (comptime is_union_enum) return .{ .result = @unionInit(T, field.name, {}) }; - return .{ .result = @enumFromInt(field.value) }; - } - } - unreachable; - } - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - @compileError("SHOULD BE UNREACHABLE!"); - } - - // inline fn generatePayloadBranches( - // input: *Parser, - // comptime first_payload_index: usize, - // comptime first_void_index: usize, - // comptime payload_count: usize, - // ) Result(T) { - // const last_payload_index = first_payload_index + payload_count - 1; - // inline for (tyinfo.@"union".fields[first_payload_index..], first_payload_index..) |field, i| { - // if (comptime (i == last_payload_index and last_payload_index > first_void_index)) { - // return generic.parseFor(field.type)(input); - // } - // if (input.tryParse(generic.parseFor(field.type), .{}).asValue()) |v| { - // return .{ .result = @unionInit(T, field.name, v) }; - // } - // } - // // The last field will return so this is never reachable - // unreachable; - // } - - // pub fn parse(this: *const T, dest: *Printer) PrintErr!void { - // // to implement this, we need to cargo expand the derive macro - // _ = this; // autofix - // _ = dest; // autofix - // @compileError(todo_stuff.depth); - // } - }; -} - -/// This uses comptime reflection to generate a `toCss` function enums and union(enum)s. -/// -/// Supported payload types for union(enum)s are: -/// - any type that has a `toCss` function -/// - void types (stringifies the identifier) -/// - optional types (unwraps the optional) -/// - anonymous structs, will automatically serialize it if it has a `__generateToCss` function -pub fn DeriveToCss(comptime T: type) type { - const tyinfo = @typeInfo(T); - const enum_fields = bun.meta.EnumFields(T); - const is_enum_or_union_enum = tyinfo == .@"union" or tyinfo == .@"enum"; - - return struct { - pub fn toCss(this: *const T, dest: *Printer) PrintErr!void { - if (comptime is_enum_or_union_enum) { - inline for (std.meta.fields(T), 0..) |field, i| { - if (@intFromEnum(this.*) == enum_fields[i].value) { - if (comptime tyinfo == .@"enum" or field.type == void) { - return dest.writeStr(enum_fields[i].name); - } else if (comptime generic.hasToCss(field.type)) { - return generic.toCss(field.type, &@field(this, field.name), dest); - } else if (@hasDecl(field.type, "__generateToCss") and @typeInfo(field.type) == .@"struct") { - const variant_fields = std.meta.fields(field.type); - if (variant_fields.len > 1) { - const last = variant_fields.len - 1; - inline for (variant_fields, 0..) |variant_field, j| { - // Unwrap it from the optional - if (@typeInfo(variant_field.type) == .optional) { - if (@field(@field(this, field.name), variant_field.name)) |*value| { - try value.toCss(dest); - } - } else { - try @field(@field(this, field.name), variant_field.name).toCss(dest); - } - - // Emit a space if there are more fields after - if (comptime j != last) { - try dest.writeChar(' '); - } - } - } else { - const variant_field = variant_fields[0]; - try @field(variant_field.type, "toCss")(@field(@field(this, field.name), variant_field.name), dest); - } - } else { - @compileError("Don't know how to serialize this variant: " ++ @typeName(field.type) ++ ", on " ++ @typeName(T) ++ ".\n\nYou probably want to implement a `toCss` function for this type, or add a dummy `fn __generateToCss() void {}` to the type signal that it is okay for it to be auto-generated by this function.."); - } - } - } - } else { - @compileError("Unsupported type: " ++ @typeName(T)); - } - return; - } - }; -} - -pub const enum_property_util = struct { - pub fn asStr(comptime T: type, this: *const T) []const u8 { - const tag = @intFromEnum(this.*); - inline for (bun.meta.EnumFields(T)) |field| { - if (tag == field.value) return field.name; - } - unreachable; - } - - pub inline fn parse(comptime T: type, input: *Parser) Result(T) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const Map = comptime bun.ComptimeEnumMap(T); - if (Map.getASCIIICaseInsensitive(ident)) |x| return .{ .result = x }; - // inline for (std.meta.fields(T)) |field| { - // if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, field.name)) return .{ .result = @enumFromInt(field.value) }; - // } - - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(comptime T: type, this: *const T, dest: *Printer) PrintErr!void { - return dest.writeStr(asStr(T, this)); - } -}; - -pub fn DefineEnumProperty(comptime T: type) type { - const fields: []const std.builtin.Type.EnumField = std.meta.fields(T); - - return struct { - pub fn eql(lhs: *const T, rhs: *const T) bool { - return @intFromEnum(lhs.*) == @intFromEnum(rhs.*); - } - - pub fn parse(input: *Parser) Result(T) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - // todo_stuff.match_ignore_ascii_case - inline for (fields) |field| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, field.name)) return .{ .result = @enumFromInt(field.value) }; - } - - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const T, dest: *Printer) PrintErr!void { - return dest.writeStr(@tagName(this.*)); - } - - pub inline fn deepClone(this: *const T, _: std.mem.Allocator) T { - return this.*; - } - - pub fn hash(this: *const T, hasher: *std.hash.Wyhash) void { - const tag = @intFromEnum(this.*); - hasher.update(std.mem.asBytes(&tag)); - } - }; -} - -pub fn DeriveValueType(comptime T: type, comptime ValueTypeMap: anytype) type { - const field_values: []const MediaFeatureType = field_values: { - const fields = std.meta.fields(T); - var mapping: [fields.len]MediaFeatureType = undefined; - for (fields, 0..) |field, i| { - // Check that it exists in the type map - mapping[i] = @field(ValueTypeMap, field.name); - } - const mapping_final = mapping; - break :field_values mapping_final[0..]; - }; - - return struct { - pub fn valueType(this: *const T) MediaFeatureType { - inline for (std.meta.fields(T), 0..) |field, i| { - if (field.value == @intFromEnum(this.*)) { - return field_values[i]; - } - } - unreachable; - } - }; -} - -fn consume_until_end_of_block(block_type: BlockType, tokenizer: *Tokenizer) void { - @branchHint(.cold); - var stack = SmallList(BlockType, 16){}; - stack.appendAssumeCapacity(block_type); - - while (switch (tokenizer.next()) { - .result => |v| v, - .err => null, - }) |tok| { - if (BlockType.closing(&tok)) |b| { - if (stack.getLastUnchecked() == b) { - _ = stack.pop(); - if (stack.len() == 0) return; - } - } - - if (BlockType.opening(&tok)) |bt| stack.append(tokenizer.allocator, bt); - } -} - -fn parse_at_rule( - allocator: Allocator, - start: *const ParserState, - name: []const u8, - input: *Parser, - comptime P: type, - parser: *P, -) Result(P.AtRuleParser.AtRule) { - _ = allocator; // autofix - ValidAtRuleParser(P); - const delimiters = Delimiters{ .semicolon = true, .curly_bracket = true }; - const Closure = struct { - name: []const u8, - parser: *P, - - pub fn parsefn(this: *@This(), input2: *Parser) Result(P.AtRuleParser.Prelude) { - return P.AtRuleParser.parsePrelude(this.parser, this.name, input2); - } - }; - var closure = Closure{ .name = name, .parser = parser }; - const prelude: P.AtRuleParser.Prelude = switch (input.parseUntilBefore(delimiters, P.AtRuleParser.Prelude, &closure, Closure.parsefn)) { - .result => |vvv| vvv, - .err => |e| { - // const end_position = input.position(); - // _ = end_position; k - out: { - const tok = switch (input.next()) { - .result => |v| v, - .err => break :out, - }; - if (tok.* != .open_curly and tok.* != .semicolon) bun.unreachablePanic("Should have consumed these delimiters", .{}); - break :out; - } - return .{ .err = e }; - }, - }; - const next = switch (input.next()) { - .result => |v| v.*, - .err => { - return switch (P.AtRuleParser.ruleWithoutBlock(parser, prelude, start)) { - .result => |v| { - return .{ .result = v }; - }, - .err => { - return .{ .err = input.newUnexpectedTokenError(.semicolon) }; - }, - }; - }, - }; - switch (next) { - .semicolon => { - switch (P.AtRuleParser.ruleWithoutBlock(parser, prelude, start)) { - .result => |v| { - return .{ .result = v }; - }, - .err => { - return .{ .err = input.newUnexpectedTokenError(.semicolon) }; - }, - } - }, - .open_curly => { - const AnotherClosure = struct { - prelude: P.AtRuleParser.Prelude, - start: *const ParserState, - parser: *P, - pub fn parsefn(this: *@This(), input2: *Parser) Result(P.AtRuleParser.AtRule) { - return P.AtRuleParser.parseBlock(this.parser, this.prelude, this.start, input2); - } - }; - var another_closure = AnotherClosure{ - .prelude = prelude, - .start = start, - .parser = parser, - }; - return parse_nested_block(input, P.AtRuleParser.AtRule, &another_closure, AnotherClosure.parsefn); - }, - else => { - bun.unreachablePanic("", .{}); - }, - } -} - -fn parse_custom_at_rule_prelude(name: []const u8, input: *Parser, options: *const ParserOptions, comptime T: type, at_rule_parser: *T) Result(AtRulePrelude(T.CustomAtRuleParser.Prelude)) { - ValidCustomAtRuleParser(T); - switch (T.CustomAtRuleParser.parsePrelude(at_rule_parser, name, input, options)) { - .result => |prelude| { - return .{ .result = .{ .custom = prelude } }; - }, - .err => |e| { - if (e.kind == .basic and e.kind.basic == .at_rule_invalid) { - // do nothing - } else return .{ - .err = input.newCustomError( - ParserError{ .at_rule_prelude_invalid = {} }, - ), - }; - }, - } - - options.warn(input.newError(.{ .at_rule_invalid = name })); - input.skipWhitespace(); - const tokens = switch (TokenListFns.parse(input, options, 0)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = .{ .unknown = .{ - .name = name, - .tokens = tokens, - } } }; -} - -fn parse_custom_at_rule_without_block( - comptime T: type, - prelude: T.CustomAtRuleParser.Prelude, - start: *const ParserState, - options: *const ParserOptions, - at_rule_parser: *T, - is_nested: bool, -) Maybe(CssRule(T.CustomAtRuleParser.AtRule), void) { - return switch (T.CustomAtRuleParser.ruleWithoutBlock(at_rule_parser, prelude, start, options, is_nested)) { - .result => |v| .{ .result = CssRule(T.CustomAtRuleParser.AtRule){ .custom = v } }, - .err => |e| .{ .err = e }, - }; -} - -fn parse_custom_at_rule_body( - comptime T: type, - prelude: T.CustomAtRuleParser.Prelude, - input: *Parser, - start: *const ParserState, - options: *const ParserOptions, - at_rule_parser: *T, - is_nested: bool, -) Result(T.CustomAtRuleParser.AtRule) { - const result = switch (T.CustomAtRuleParser.parseBlock(at_rule_parser, prelude, start, input, options, is_nested)) { - .result => |vv| vv, - .err => |e| { - _ = e; // autofix - // match &err.kind { - // ParseErrorKind::Basic(kind) => ParseError { - // kind: ParseErrorKind::Basic(kind.clone()), - // location: err.location, - // }, - // _ => input.new_error(BasicParseErrorKind::AtRuleBodyInvalid), - // } - todo("This part here", .{}); - }, - }; - return .{ .result = result }; -} - -fn parse_qualified_rule( - start: *const ParserState, - input: *Parser, - comptime P: type, - parser: *P, - delimiters: Delimiters, -) Result(P.QualifiedRuleParser.QualifiedRule) { - ValidQualifiedRuleParser(P); - const prelude_result = brk: { - const prelude = input.parseUntilBefore(delimiters, P.QualifiedRuleParser.Prelude, parser, P.QualifiedRuleParser.parsePrelude); - break :brk prelude; - }; - if (input.expectCurlyBracketBlock().asErr()) |e| return .{ .err = e }; - const prelude = switch (prelude_result) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const Closure = struct { - start: *const ParserState, - prelude: P.QualifiedRuleParser.Prelude, - parser: *P, - - pub fn parsefn(this: *@This(), input2: *Parser) Result(P.QualifiedRuleParser.QualifiedRule) { - return P.QualifiedRuleParser.parseBlock(this.parser, this.prelude, this.start, input2); - } - }; - var closure = Closure{ - .start = start, - .prelude = prelude, - .parser = parser, - }; - return parse_nested_block(input, P.QualifiedRuleParser.QualifiedRule, &closure, Closure.parsefn); -} - -fn parse_until_before( - parser: *Parser, - delimiters_: Delimiters, - error_behavior: ParseUntilErrorBehavior, - comptime T: type, - closure: anytype, - comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T), -) Result(T) { - const delimiters = bun.bits.@"or"(Delimiters, parser.stop_before, delimiters_); - const result = result: { - var delimited_parser = Parser{ - .input = parser.input, - .at_start_of = if (parser.at_start_of) |block_type| brk: { - parser.at_start_of = null; - break :brk block_type; - } else null, - .stop_before = delimiters, - .import_records = parser.import_records, - .flags = parser.flags, - .extra = parser.extra, - }; - const result = delimited_parser.parseEntirely(T, closure, parse_fn); - if (error_behavior == .stop and result.isErr()) { - return result; - } - if (delimited_parser.at_start_of) |block_type| { - consume_until_end_of_block(block_type, &delimited_parser.input.tokenizer); - } - break :result result; - }; - - // FIXME: have a special-purpose tokenizer method for this that does less work. - while (true) { - if (bun.bits.contains(Delimiters, delimiters, Delimiters.fromByte(parser.input.tokenizer.nextByte()))) break; - - switch (parser.input.tokenizer.next()) { - .result => |token| { - if (BlockType.opening(&token)) |block_type| { - consume_until_end_of_block(block_type, &parser.input.tokenizer); - } - }, - else => break, - } - } - - return result; -} - -// fn parse_until_before_impl(parser: *Parser, delimiters: Delimiters, error_behavior: Parse - -pub fn parse_until_after( - parser: *Parser, - delimiters: Delimiters, - error_behavior: ParseUntilErrorBehavior, - comptime T: type, - closure: anytype, - comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T), -) Result(T) { - const result = parse_until_before(parser, delimiters, error_behavior, T, closure, parsefn); - const is_err = result.isErr(); - if (error_behavior == .stop and is_err) { - return result; - } - const next_byte = parser.input.tokenizer.nextByte(); - if (next_byte != null and !bun.bits.contains(Delimiters, parser.stop_before, .fromByte(next_byte))) { - if (bun.Environment.isDebug) bun.debugAssert(bun.bits.contains(Delimiters, delimiters, Delimiters.fromByte(next_byte))); - - // We know this byte is ASCII. - parser.input.tokenizer.advance(1); - if (next_byte == '{') { - consume_until_end_of_block(BlockType.curly_bracket, &parser.input.tokenizer); - } - } - return result; -} - -fn parse_nested_block(parser: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) { - const block_type: BlockType = if (parser.at_start_of) |block_type| brk: { - parser.at_start_of = null; - break :brk block_type; - } else @panic( - \\ - \\A nested parser can only be created when a Function, - \\ParenthisisBlock, SquareBracketBlock, or CurlyBracketBlock - \\token was just consumed. - ); - - const closing_delimiter = switch (block_type) { - .curly_bracket => Delimiters{ .close_curly_bracket = true }, - .square_bracket => Delimiters{ .close_square_bracket = true }, - .parenthesis => Delimiters{ .close_parenthesis = true }, - }; - var nested_parser = Parser{ - .input = parser.input, - .stop_before = closing_delimiter, - .import_records = parser.import_records, - .flags = parser.flags, - .extra = parser.extra, - }; - const result = nested_parser.parseEntirely(T, closure, parsefn); - if (nested_parser.at_start_of) |block_type2| { - consume_until_end_of_block(block_type2, &nested_parser.input.tokenizer); - } - consume_until_end_of_block(block_type, &parser.input.tokenizer); - return result; -} - -/// Qualified rules are rules that apply styles to elements in a -/// document. -pub fn ValidQualifiedRuleParser(comptime T: type) void { - // The intermediate representation of a qualified rule prelude. - _ = T.QualifiedRuleParser.Prelude; - - // The finished representation of a qualified rule. - _ = T.QualifiedRuleParser.QualifiedRule; - - // Parse the prelude of a qualified rule. For style rules, this is as Selector list. - // - // Return the representation of the prelude, - // or `Err(())` to ignore the entire at-rule as invalid. - // - // The prelude is the part before the `{ /* ... */ }` block. - // - // The given `input` is a "delimited" parser - // that ends where the prelude should end (before the next `{`). - // - // fn parsePrelude(this: *T, input: *Parser) Error!T.QualifiedRuleParser.Prelude; - _ = T.QualifiedRuleParser.parsePrelude; - - // Parse the content of a `{ /* ... */ }` block for the body of the qualified rule. - // - // The location passed in is source location of the start of the prelude. - // - // Return the finished representation of the qualified rule - // as returned by `RuleListParser::next`, - // or `Err(())` to ignore the entire at-rule as invalid. - // - // fn parseBlock(this: *T, prelude: P.QualifiedRuleParser.Prelude, start: *const ParserState, input: *Parser) Error!P.QualifiedRuleParser.QualifiedRule; - _ = T.QualifiedRuleParser.parseBlock; -} - -pub const DefaultAtRule = struct { - pub fn toCss(_: *const @This(), dest: *Printer) PrintErr!void { - return dest.newError(.fmt_error, null); - } - - pub fn deepClone(_: *const @This(), _: std.mem.Allocator) @This() { - return .{}; - } -}; - -pub const DefaultAtRuleParser = struct { - const This = @This(); - - pub const CustomAtRuleParser = struct { - pub const Prelude = void; - pub const AtRule = DefaultAtRule; - - pub fn parsePrelude(_: *This, name: []const u8, input: *Parser, _: *const ParserOptions) Result(Prelude) { - return .{ .err = input.newError(BasicParseErrorKind{ .at_rule_invalid = name }) }; - } - - pub fn parseBlock(_: *This, _: CustomAtRuleParser.Prelude, _: *const ParserState, input: *Parser, _: *const ParserOptions, _: bool) Result(CustomAtRuleParser.AtRule) { - return .{ .err = input.newError(BasicParseErrorKind.at_rule_body_invalid) }; - } - - pub fn ruleWithoutBlock(_: *This, _: CustomAtRuleParser.Prelude, _: *const ParserState, _: *const ParserOptions, _: bool) Maybe(CustomAtRuleParser.AtRule, void) { - return .{ .err = {} }; - } - - pub fn onImportRule(_: *This, _: *ImportRule, _: u32, _: u32) void {} - - pub fn onLayerRule(_: *This, _: *const bun.css.SmallList(LayerName, 1)) void {} - - pub fn enclosingLayerLength(_: *This) u32 { - return 0; - } - - pub fn setEnclosingLayer(_: *This, _: LayerName) void {} - - pub fn pushToEnclosingLayer(_: *This, _: LayerName) void {} - - pub fn resetEnclosingLayer(_: *This, _: u32) void {} - - pub fn bumpAnonLayerCount(_: *This, _: i32) void {} - }; -}; - -/// We may want to enable this later -pub const ENABLE_TAILWIND_PARSING = false; - -pub const BundlerAtRule = if (ENABLE_TAILWIND_PARSING) TailwindAtRule else DefaultAtRule; -pub const BundlerAtRuleParser = struct { - const This = @This(); - allocator: Allocator, - import_records: *bun.BabyList(ImportRecord), - layer_names: bun.BabyList(LayerName) = .{}, - options: *const ParserOptions, - - /// Having _named_ layers nested inside of an _anonymous_ layer - /// has no effect: - /// - /// ```css - /// @layer { - /// @layer foo { /* layer 1 */ } - /// @layer foo { /* also layer 1 */ } - /// } - /// ``` - /// - /// See: https://drafts.csswg.org/css-cascade-5/#example-787042b6 - anon_layer_count: u32 = 0, - enclosing_layer: LayerName = .{}, - - pub const CustomAtRuleParser = struct { - pub const Prelude = if (ENABLE_TAILWIND_PARSING) union(enum) { - tailwind: TailwindAtRule, - } else void; - pub const AtRule = if (ENABLE_TAILWIND_PARSING) TailwindAtRule else DefaultAtRule; - - pub fn parsePrelude(this: *This, name: []const u8, input: *Parser, _: *const ParserOptions) Result(Prelude) { - if (comptime ENABLE_TAILWIND_PARSING) { - const PreludeNames = enum { - tailwind, - }; - const Map = comptime bun.ComptimeEnumMap(PreludeNames); - if (Map.getASCIIICaseInsensitive(name)) |prelude| return switch (prelude) { - .tailwind => { - const loc_ = input.currentSourceLocation(); - const loc = css_rules.Location{ - .source_index = this.options.source_index, - .line = loc_.line, - .column = loc_.column, - }; - const style_name = switch (css_rules.tailwind.TailwindStyleName.parse(input)) { - .result => |v| v, - .err => return .{ .err = input.newError(BasicParseErrorKind{ .at_rule_invalid = name }) }, - }; - return .{ .result = .{ - .tailwind = .{ - .style_name = style_name, - .loc = loc, - }, - } }; - }, - }; - } - return .{ .err = input.newError(BasicParseErrorKind{ .at_rule_invalid = name }) }; - } - - pub fn parseBlock(_: *This, _: CustomAtRuleParser.Prelude, _: *const ParserState, input: *Parser, _: *const ParserOptions, _: bool) Result(CustomAtRuleParser.AtRule) { - return .{ .err = input.newError(BasicParseErrorKind.at_rule_body_invalid) }; - } - - pub fn ruleWithoutBlock(_: *This, prelude: CustomAtRuleParser.Prelude, _: *const ParserState, _: *const ParserOptions, _: bool) Maybe(CustomAtRuleParser.AtRule, void) { - if (comptime ENABLE_TAILWIND_PARSING) { - return switch (prelude) { - .tailwind => |v| return .{ .result = v }, - }; - } - return .{ .err = {} }; - } - - pub fn onImportRule(this: *This, import_rule: *ImportRule, start_position: u32, end_position: u32) void { - const import_record_index = this.import_records.len; - import_rule.import_record_idx = import_record_index; - this.import_records.append(this.allocator, ImportRecord{ - .path = bun.fs.Path.init(import_rule.url), - .kind = if (import_rule.supports != null) .at_conditional else .at, - .range = bun.logger.Range{ - .loc = bun.logger.Loc{ .start = @intCast(start_position) }, - .len = @intCast(end_position - start_position), - }, - }) catch |err| bun.handleOom(err); - } - - pub fn onLayerRule(this: *This, layers: *const bun.css.SmallList(LayerName, 1)) void { - if (this.anon_layer_count > 0) return; - - bun.handleOom(this.layer_names.ensureUnusedCapacity(this.allocator, layers.len())); - - for (layers.slice()) |*layer| { - if (this.enclosing_layer.v.len() > 0) { - var cloned = LayerName{ - .v = SmallList([]const u8, 1){}, - }; - cloned.v.ensureTotalCapacity(this.allocator, this.enclosing_layer.v.len() + layer.v.len()); - cloned.v.appendSliceAssumeCapacity(this.enclosing_layer.v.slice()); - cloned.v.appendSliceAssumeCapacity(layer.v.slice()); - bun.handleOom(this.layer_names.append(this.allocator, cloned)); - } else { - bun.handleOom(this.layer_names.append(this.allocator, layer.deepClone(this.allocator))); - } - } - } - - pub fn enclosingLayerLength(this: *This) u32 { - return this.enclosing_layer.v.len(); - } - - pub fn setEnclosingLayer(this: *This, layer: LayerName) void { - this.enclosing_layer = layer; - } - - pub fn pushToEnclosingLayer(this: *This, name: LayerName) void { - this.enclosing_layer.v.appendSlice(this.allocator, name.v.slice()); - } - - pub fn resetEnclosingLayer(this: *This, len: u32) void { - this.enclosing_layer.v.setLen(len); - } - - pub fn bumpAnonLayerCount(this: *This, amount: i32) void { - if (amount > 0) { - this.anon_layer_count += @intCast(amount); - } else { - this.anon_layer_count -= @intCast(@abs(amount)); - } - } - }; -}; - -/// Same as `ValidAtRuleParser` but modified to provide parser options -/// -/// Also added: -/// - onImportRule to handle @import rules -pub fn ValidCustomAtRuleParser(comptime T: type) void { - // The intermediate representation of prelude of an at-rule. - _ = T.CustomAtRuleParser.Prelude; - - // The finished representation of an at-rule. - _ = T.CustomAtRuleParser.AtRule; - - // Parse the prelude of an at-rule with the given `name`. - // - // Return the representation of the prelude and the type of at-rule, - // or `Err(())` to ignore the entire at-rule as invalid. - // - // The prelude is the part after the at-keyword - // and before the `;` semicolon or `{ /* ... */ }` block. - // - // At-rule name matching should be case-insensitive in the ASCII range. - // This can be done with `std::ascii::Ascii::eq_ignore_ascii_case`, - // or with the `match_ignore_ascii_case!` macro. - // - // The given `input` is a "delimited" parser - // that ends wherever the prelude should end. - // (Before the next semicolon, the next `{`, or the end of the current block.) - // - // pub fn parsePrelude(this: *T, allocator: Allocator, name: []const u8, *Parser, options: *ParserOptions) Result(T.CustomAtRuleParser.Prelude) {} - _ = T.CustomAtRuleParser.parsePrelude; - - // End an at-rule which doesn't have block. Return the finished - // representation of the at-rule. - // - // The location passed in is source location of the start of the prelude. - // `is_nested` indicates whether the rule is nested inside a style rule. - // - // This is only called when either the `;` semicolon indeed follows the prelude, - // or parser is at the end of the input. - _ = T.CustomAtRuleParser.ruleWithoutBlock; - - // Parse the content of a `{ /* ... */ }` block for the body of the at-rule. - // - // The location passed in is source location of the start of the prelude. - // `is_nested` indicates whether the rule is nested inside a style rule. - // - // Return the finished representation of the at-rule - // as returned by `RuleListParser::next` or `DeclarationListParser::next`, - // or `Err(())` to ignore the entire at-rule as invalid. - // - // This is only called when a block was found following the prelude. - _ = T.CustomAtRuleParser.parseBlock; - - _ = T.CustomAtRuleParser.onImportRule; - - _ = T.CustomAtRuleParser.onLayerRule; - - _ = T.CustomAtRuleParser.enclosingLayerLength; - _ = T.CustomAtRuleParser.setEnclosingLayer; - _ = T.CustomAtRuleParser.pushToEnclosingLayer; - _ = T.CustomAtRuleParser.resetEnclosingLayer; - _ = T.CustomAtRuleParser.bumpAnonLayerCount; -} - -/// At rules are rules that basically have the `@` symbol: -/// -/// ```css -/// @import "foo.css"; -/// @media (min-width: 100px) { -/// foo { -/// } -/// } -/// ``` -pub fn ValidAtRuleParser(comptime T: type) void { - _ = T.AtRuleParser.AtRule; - _ = T.AtRuleParser.Prelude; - - // Parse the prelude of an at-rule with the given `name`. - // - // Return the representation of the prelude and the type of at-rule, - // or `Err(())` to ignore the entire at-rule as invalid. - // - // The prelude is the part after the at-keyword - // and before the `;` semicolon or `{ /* ... */ }` block. - // - // At-rule name matching should be case-insensitive in the ASCII range. - // This can be done with `std::ascii::Ascii::eq_ignore_ascii_case`, - // or with the `match_ignore_ascii_case!` macro. - // - // The given `input` is a "delimited" parser - // that ends wherever the prelude should end. - // (Before the next semicolon, the next `{`, or the end of the current block.) - // - // pub fn parsePrelude(this: *T, allocator: Allocator, name: []const u8, *Parser) Result(T.AtRuleParser.Prelude) {} - _ = T.AtRuleParser.parsePrelude; - - // End an at-rule which doesn't have block. Return the finished - // representation of the at-rule. - // - // The location passed in is source location of the start of the prelude. - // - // This is only called when `parse_prelude` returned `WithoutBlock`, and - // either the `;` semicolon indeed follows the prelude, or parser is at - // the end of the input. - // fn ruleWithoutBlock(this: *T, allocator: Allocator, prelude: T.AtRuleParser.Prelude, state: *const ParserState) Maybe(T.AtRuleParser.AtRule, void) - _ = T.AtRuleParser.ruleWithoutBlock; - - // Parse the content of a `{ /* ... */ }` block for the body of the at-rule. - // - // The location passed in is source location of the start of the prelude. - // - // Return the finished representation of the at-rule - // as returned by `RuleListParser::next` or `DeclarationListParser::next`, - // or `Err(())` to ignore the entire at-rule as invalid. - // - // This is only called when `parse_prelude` returned `WithBlock`, and a block - // was indeed found following the prelude. - // - // fn parseBlock(this: *T, prelude: T.AtRuleParser.Prelude, start: *const ParserState, input: *Parser) Error!T.AtRuleParser.AtRule - _ = T.AtRuleParser.parseBlock; -} - -pub fn AtRulePrelude(comptime T: type) type { - return union(enum) { - font_face, - font_feature_values, - font_palette_values: DashedIdent, - counter_style: CustomIdent, - import: struct { - []const u8, - MediaList, - ?SupportsCondition, - ?struct { value: ?LayerName }, - }, - namespace: struct { - ?[]const u8, - []const u8, - }, - charset, - custom_media: struct { - DashedIdent, - MediaList, - }, - property: struct { - DashedIdent, - }, - media: MediaList, - supports: SupportsCondition, - viewport: VendorPrefix, - keyframes: struct { - name: css_rules.keyframes.KeyframesName, - prefix: VendorPrefix, - }, - page: ArrayList(css_rules.page.PageSelector), - moz_document, - layer: bun.css.SmallList(LayerName, 1), - container: struct { - name: ?css_rules.container.ContainerName, - condition: css_rules.container.ContainerCondition, - }, - starting_style, - nest: selector.parser.SelectorList, - scope: struct { - scope_start: ?selector.parser.SelectorList, - scope_end: ?selector.parser.SelectorList, - }, - unknown: struct { - name: []const u8, - /// The tokens of the prelude - tokens: TokenList, - }, - custom: T, - - pub fn allowedInStyleRule(this: *const @This()) bool { - return switch (this.*) { - .media, .supports, .container, .moz_document, .layer, .starting_style, .scope, .nest, .unknown, .custom => true, - .namespace, .font_face, .font_feature_values, .font_palette_values, .counter_style, .keyframes, .page, .property, .import, .custom_media, .viewport, .charset => false, - }; - } - }; -} - -pub fn TopLevelRuleParser(comptime AtRuleParserT: type) type { - ValidCustomAtRuleParser(AtRuleParserT); - const AtRuleT = AtRuleParserT.CustomAtRuleParser.AtRule; - const AtRulePreludeT = AtRulePrelude(AtRuleParserT.CustomAtRuleParser.Prelude); - - return struct { - allocator: Allocator, - options: *const ParserOptions, - state: State, - at_rule_parser: *AtRuleParserT, - // TODO: think about memory management - rules: *CssRuleList(AtRuleT), - composes: *ComposesMap, - composes_refs: SmallList(bun.bundle_v2.Ref, 2) = .{}, - local_properties: *LocalPropertyUsage, - - const State = enum(u8) { - start = 1, - layers = 2, - imports = 3, - namespaces = 4, - body = 5, - }; - - const This = @This(); - - pub const AtRuleParser = struct { - pub const Prelude = AtRulePreludeT; - pub const AtRule = void; - - pub fn parsePrelude(this: *This, name: []const u8, input: *Parser) Result(Prelude) { - const PreludeEnum = enum { - import, - charset, - namespace, - @"custom-media", - property, - }; - const Map = comptime bun.ComptimeEnumMap(PreludeEnum); - - if (Map.getASCIIICaseInsensitive(name)) |prelude| { - switch (prelude) { - .import => { - if (@intFromEnum(this.state) > @intFromEnum(State.imports)) { - return .{ .err = input.newCustomError(@as(ParserError, ParserError.unexpected_import_rule)) }; - } - const url_str = switch (input.expectUrlOrString()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const layer: ?struct { value: ?LayerName } = - if (input.tryParse(Parser.expectIdentMatching, .{"layer"}) == .result) - .{ .value = null } - else if (input.tryParse(Parser.expectFunctionMatching, .{"layer"}) == .result) brk: { - break :brk .{ - .value = switch (input.parseNestedBlock(LayerName, {}, voidWrap(LayerName, LayerName.parse))) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, - }; - } else null; - - const supports = if (input.tryParse(Parser.expectFunctionMatching, .{"supports"}) == .result) brk: { - const Func = struct { - pub fn do(_: void, p: *Parser) Result(SupportsCondition) { - const result = p.tryParse(SupportsCondition.parse, .{}); - if (result == .err) return SupportsCondition.parseDeclaration(p); - return result; - } - }; - break :brk switch (input.parseNestedBlock(SupportsCondition, {}, Func.do)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - } else null; - - const media = switch (MediaList.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - return .{ - .result = .{ - .import = .{ - url_str, - media, - supports, - if (layer) |l| .{ .value = if (l.value) |ll| ll else null } else null, - }, - }, - }; - }, - .namespace => { - if (@intFromEnum(this.state) > @intFromEnum(State.namespaces)) { - return .{ .err = input.newCustomError(ParserError{ .unexpected_namespace_rule = {} }) }; - } - - const prefix = switch (input.tryParse(Parser.expectIdent, .{})) { - .result => |v| v, - .err => null, - }; - const namespace = switch (input.expectUrlOrString()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = .{ .namespace = .{ prefix, namespace } } }; - }, - .charset => { - // @charset is removed by rust-cssparser if it's the first rule in the stylesheet. - // Anything left is technically invalid, however, users often concatenate CSS files - // together, so we are more lenient and simply ignore @charset rules in the middle of a file. - if (input.expectString().asErr()) |e| return .{ .err = e }; - return .{ .result = .charset }; - }, - .@"custom-media" => { - const custom_media_name = switch (DashedIdentFns.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const media = switch (MediaList.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ - .result = .{ - .custom_media = .{ - custom_media_name, - media, - }, - }, - }; - }, - .property => { - const property_name = switch (DashedIdentFns.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = .{ .property = .{property_name} } }; - }, - } - } - - const Nested = NestedRuleParser(AtRuleParserT); - var nested_rule_parser: Nested = this.nested(); - return Nested.AtRuleParser.parsePrelude(&nested_rule_parser, name, input); - } - - pub fn parseBlock(this: *This, prelude: AtRuleParser.Prelude, start: *const ParserState, input: *Parser) Result(AtRuleParser.AtRule) { - this.state = .body; - var nested_parser = this.nested(); - return NestedRuleParser(AtRuleParserT).AtRuleParser.parseBlock(&nested_parser, prelude, start, input); - } - - pub fn ruleWithoutBlock(this: *This, prelude: AtRuleParser.Prelude, start: *const ParserState) Maybe(AtRuleParser.AtRule, void) { - const loc_ = start.sourceLocation(); - const loc = css_rules.Location{ - .source_index = this.options.source_index, - .line = loc_.line, - .column = loc_.column, - }; - - switch (prelude) { - .import => { - this.state = State.imports; - var import_rule = ImportRule{ - .url = prelude.import[0], - .media = prelude.import[1], - .supports = prelude.import[2], - .layer = if (prelude.import[3]) |v| .{ .v = v.value } else null, - .loc = loc, - }; - AtRuleParserT.CustomAtRuleParser.onImportRule(this.at_rule_parser, &import_rule, @intCast(start.position), @intCast(start.position + 1)); - this.rules.v.append(this.allocator, .{ - .import = import_rule, - }) catch |err| bun.handleOom(err); - return .success; - }, - .namespace => { - this.state = State.namespaces; - - const prefix = prelude.namespace[0]; - const url = prelude.namespace[1]; - - this.rules.v.append(this.allocator, .{ - .namespace = NamespaceRule{ - .prefix = if (prefix) |p| .{ .v = p } else null, - .url = url, - .loc = loc, - }, - }) catch |err| bun.handleOom(err); - - return .success; - }, - .custom_media => { - const name = prelude.custom_media[0]; - const query = prelude.custom_media[1]; - this.state = State.body; - this.rules.v.append( - this.allocator, - .{ - .custom_media = css_rules.custom_media.CustomMediaRule{ - .name = name, - .query = query, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .layer => { - if (@intFromEnum(this.state) <= @intFromEnum(State.layers)) { - this.state = .layers; - } else { - this.state = .body; - } - var nested_parser = this.nested(); - const result = NestedRuleParser(AtRuleParserT).AtRuleParser.ruleWithoutBlock(&nested_parser, prelude, start); - return result; - }, - .charset => return .success, - .unknown => { - const name = prelude.unknown.name; - const prelude2 = prelude.unknown.tokens; - this.rules.v.append(this.allocator, .{ .unknown = UnknownAtRule{ - .name = name, - .prelude = prelude2, - .block = null, - .loc = loc, - } }) catch |err| bun.handleOom(err); - return .success; - }, - .custom => { - this.state = .body; - var nested_parser = this.nested(); - return NestedRuleParser(AtRuleParserT).AtRuleParser.ruleWithoutBlock(&nested_parser, prelude, start); - }, - else => return .{ .err = {} }, - } - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = selector.parser.SelectorList; - pub const QualifiedRule = void; - - pub fn parsePrelude(this: *This, input: *Parser) Result(Prelude) { - this.state = .body; - var nested_parser = this.nested(); - const N = @TypeOf(nested_parser); - return N.QualifiedRuleParser.parsePrelude(&nested_parser, input); - } - - pub fn parseBlock(this: *This, prelude: Prelude, start: *const ParserState, input: *Parser) Result(QualifiedRule) { - var nested_parser = this.nested(); - const N = @TypeOf(nested_parser); - return N.QualifiedRuleParser.parseBlock(&nested_parser, prelude, start, input); - } - }; - - pub fn new(allocator: Allocator, options: *const ParserOptions, at_rule_parser: *AtRuleParserT, rules: *CssRuleList(AtRuleT), composes: *ComposesMap, local_properties: *LocalPropertyUsage) @This() { - return .{ - .options = options, - .state = .start, - .at_rule_parser = at_rule_parser, - .rules = rules, - .allocator = allocator, - .composes = composes, - .local_properties = local_properties, - }; - } - - pub fn nested(this: *This) NestedRuleParser(AtRuleParserT) { - return NestedRuleParser(AtRuleParserT){ - .options = this.options, - .at_rule_parser = this.at_rule_parser, - .declarations = DeclarationList{}, - .important_declarations = DeclarationList{}, - .rules = this.rules, - .is_in_style_rule = false, - .allow_declarations = false, - .allocator = this.allocator, - .composes = this.composes, - .composes_refs = &this.composes_refs, - .local_properties = this.local_properties, - }; - } - }; -} - -pub fn NestedRuleParser(comptime T: type) type { - ValidCustomAtRuleParser(T); - - const AtRuleT = T.CustomAtRuleParser.AtRule; - - return struct { - options: *const ParserOptions, - at_rule_parser: *T, - // todo_stuff.think_mem_mgmt - declarations: DeclarationList, - // todo_stuff.think_mem_mgmt - important_declarations: DeclarationList, - // todo_stuff.think_mem_mgmt - rules: *CssRuleList(T.CustomAtRuleParser.AtRule), - is_in_style_rule: bool, - allow_declarations: bool, - - composes_state: ComposesState = .disallow_entirely, - composes_refs: *SmallList(bun.bundle_v2.Ref, 2), - composes: *ComposesMap, - local_properties: *LocalPropertyUsage, - - allocator: Allocator, - - const ComposesState = union(enum) { - allow: SourceLocation, - disallow_nested: SourceLocation, - disallow_not_single_class: SourceLocation, - disallow_entirely, - }; - - const This = @This(); - - pub fn getLoc(this: *This, start: *const ParserState) Location { - const loc = start.sourceLocation(); - return Location{ - .source_index = this.options.source_index, - .line = loc.line, - .column = loc.column, - }; - } - - pub const AtRuleParser = struct { - pub const Prelude = AtRulePrelude(T.CustomAtRuleParser.Prelude); - pub const AtRule = void; - - pub fn parsePrelude(this: *This, name: []const u8, input: *Parser) Result(Prelude) { - const result: Prelude = brk: { - const PreludeEnum = enum { - media, - supports, - @"font-face", - @"font-palette-values", - @"counter-style", - viewport, - @"-ms-viewport", - keyframes, - @"-webkit-keyframes", - @"-moz-keyframes", - @"-o-keyframes", - @"-ms-keyframes", - page, - @"-moz-document", - layer, - container, - @"starting-style", - scope, - nest, - }; - const Map = comptime bun.ComptimeEnumMap(PreludeEnum); - if (Map.getASCIIICaseInsensitive(name)) |kind| switch (kind) { - .media => { - const media = switch (MediaList.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :brk .{ .media = media }; - }, - .supports => { - const cond = switch (SupportsCondition.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :brk .{ .supports = cond }; - }, - .@"font-face" => break :brk .font_face, - .@"font-palette-values" => { - const dashed_ident_name = switch (DashedIdentFns.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :brk .{ .font_palette_values = dashed_ident_name }; - }, - .@"counter-style" => { - const custom_name = switch (CustomIdentFns.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :brk .{ .counter_style = custom_name }; - }, - .viewport, .@"-ms-viewport" => { - const prefix: VendorPrefix = if (bun.strings.startsWithCaseInsensitiveAscii(name, "-ms")) VendorPrefix{ .ms = true } else VendorPrefix{ .none = true }; - break :brk .{ .viewport = prefix }; - }, - inline .keyframes, .@"-webkit-keyframes", .@"-moz-keyframes", .@"-o-keyframes", .@"-ms-keyframes" => |n| { - const prefix: VendorPrefix = switch (n) { - .@"-webkit-keyframes" => VendorPrefix{ .webkit = true }, - .@"-moz-keyframes" => VendorPrefix{ .moz = true }, - .@"-o-keyframes" => VendorPrefix{ .o = true }, - .@"-ms-keyframes" => VendorPrefix{ .ms = true }, - else => VendorPrefix{ .none = true }, - }; - - const keyframes_name = switch (input.tryParse(css_rules.keyframes.KeyframesName.parse, .{})) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :brk .{ .keyframes = .{ .name = keyframes_name, .prefix = prefix } }; - }, - .page => { - const Fn = struct { - pub fn parsefn(input2: *Parser) Result(ArrayList(css_rules.page.PageSelector)) { - return input2.parseCommaSeparated(css_rules.page.PageSelector, css_rules.page.PageSelector.parse); - } - }; - const selectors = switch (input.tryParse(Fn.parsefn, .{})) { - .result => |v| v, - .err => ArrayList(css_rules.page.PageSelector){}, - }; - break :brk .{ .page = selectors }; - }, - .@"-moz-document" => { - // Firefox only supports the url-prefix() function with no arguments as a legacy CSS hack. - // See https://css-tricks.com/snippets/css/css-hacks-targeting-firefox/ - if (input.expectFunctionMatching("url-prefix").asErr()) |e| return .{ .err = e }; - const Fn = struct { - pub fn parsefn(_: void, input2: *Parser) Result(void) { - // Firefox also allows an empty string as an argument... - // https://github.com/mozilla/gecko-dev/blob/0077f2248712a1b45bf02f0f866449f663538164/servo/components/style/stylesheets/document_rule.rs#L303 - _ = input2.tryParse(parseInner, .{}); - if (input2.expectExhausted().asErr()) |e| return .{ .err = e }; - return .success; - } - fn parseInner(input2: *Parser) Result(void) { - const s = switch (input2.expectString()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (s.len > 0) { - return .{ .err = input2.newCustomError(ParserError.invalid_value) }; - } - return .success; - } - }; - if (input.parseNestedBlock(void, {}, Fn.parsefn).asErr()) |e| return .{ .err = e }; - break :brk .moz_document; - }, - .layer => { - const names = switch (bun.css.SmallList(LayerName, 1).parse(input)) { - .result => |vv| vv, - .err => |e| names: { - if (e.kind == .basic and e.kind.basic == .end_of_input) { - break :names bun.css.SmallList(LayerName, 1){}; - } - return .{ .err = e }; - }, - }; - - break :brk .{ .layer = names }; - }, - .container => { - const container_name = switch (input.tryParse(css_rules.container.ContainerName.parse, .{})) { - .result => |vv| vv, - .err => null, - }; - const condition = switch (css_rules.container.ContainerCondition.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :brk .{ .container = .{ .name = container_name, .condition = condition } }; - }, - .@"starting-style" => break :brk .starting_style, - .scope => { - var selector_parser = selector.parser.SelectorParser{ - .is_nesting_allowed = true, - .options = this.options, - .allocator = input.allocator(), - }; - const Closure = struct { - selector_parser: *selector.parser.SelectorParser, - pub fn parsefn(self: *@This(), input2: *Parser) Result(selector.parser.SelectorList) { - return selector.parser.SelectorList.parseRelative(self.selector_parser, input2, .ignore_invalid_selector, .none); - } - }; - var closure = Closure{ - .selector_parser = &selector_parser, - }; - - const scope_start = if (input.tryParse(Parser.expectParenthesisBlock, .{}).isOk()) scope_start: { - break :scope_start switch (input.parseNestedBlock(selector.parser.SelectorList, &closure, Closure.parsefn)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - } else null; - - const scope_end = if (input.tryParse(Parser.expectIdentMatching, .{"to"}).isOk()) scope_end: { - if (input.expectParenthesisBlock().asErr()) |e| return .{ .err = e }; - break :scope_end switch (input.parseNestedBlock(selector.parser.SelectorList, &closure, Closure.parsefn)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - } else null; - - break :brk .{ - .scope = .{ - .scope_start = scope_start, - .scope_end = scope_end, - }, - }; - }, - .nest => { - if (this.is_in_style_rule) { - this.options.warn(input.newCustomError(ParserError{ .deprecated_nest_rule = {} })); - var selector_parser = selector.parser.SelectorParser{ - .is_nesting_allowed = true, - .options = this.options, - .allocator = input.allocator(), - }; - const selectors = switch (selector.parser.SelectorList.parse(&selector_parser, input, .discard_list, .contained)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :brk .{ .nest = selectors }; - } - }, - }; - - switch (parse_custom_at_rule_prelude( - name, - input, - this.options, - T, - this.at_rule_parser, - )) { - .result => |v| break :brk v, - .err => |e| return .{ .err = e }, - } - }; - - if (this.is_in_style_rule and !result.allowedInStyleRule()) { - return .{ .err = input.newError(BasicParseErrorKind{ .at_rule_invalid = name }) }; - } - - return .{ .result = result }; - } - - pub fn parseBlock(this: *This, prelude: AtRuleParser.Prelude, start: *const ParserState, input: *Parser) Result(AtRuleParser.AtRule) { - const loc = this.getLoc(start); - switch (prelude) { - .font_face => { - var decl_parser = css_rules.font_face.FontFaceDeclarationParser{}; - var parser = RuleBodyParser(css_rules.font_face.FontFaceDeclarationParser).new(input, &decl_parser); - // todo_stuff.think_mem_mgmt - var properties: ArrayList(css_rules.font_face.FontFaceProperty) = .{}; - - while (parser.next()) |result| { - if (result.asValue()) |decl| { - properties.append( - input.allocator(), - decl, - ) catch |err| bun.handleOom(err); - } - } - - this.rules.v.append( - input.allocator(), - .{ - .font_face = css_rules.font_face.FontFaceRule{ - .properties = properties, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .font_palette_values => { - const name = prelude.font_palette_values; - const rule = switch (css_rules.font_palette_values.FontPaletteValuesRule.parse(name, input, loc)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append( - input.allocator(), - .{ .font_palette_values = rule }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .counter_style => { - const name = prelude.counter_style; - this.rules.v.append( - input.allocator(), - .{ - .counter_style = css_rules.counter_style.CounterStyleRule{ - .name = name, - .declarations = switch (DeclarationBlock.parse(input, this.options)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .media => { - const query = prelude.media; - const rules = switch (this.parseStyleBlock(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append( - input.allocator(), - .{ - .media = css_rules.media.MediaRule(T.CustomAtRuleParser.AtRule){ - .query = query, - .rules = rules, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .supports => { - const condition = prelude.supports; - const rules = switch (this.parseStyleBlock(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append(input.allocator(), .{ - .supports = css_rules.supports.SupportsRule(T.CustomAtRuleParser.AtRule){ - .condition = condition, - .rules = rules, - .loc = loc, - }, - }) catch |err| bun.handleOom(err); - return .success; - }, - .container => { - const rules = switch (this.parseStyleBlock(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append( - input.allocator(), - .{ - .container = css_rules.container.ContainerRule(T.CustomAtRuleParser.AtRule){ - .name = prelude.container.name, - .condition = prelude.container.condition, - .rules = rules, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .scope => { - const rules = switch (this.parseStyleBlock(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append( - input.allocator(), - .{ - .scope = css_rules.scope.ScopeRule(T.CustomAtRuleParser.AtRule){ - .scope_start = prelude.scope.scope_start, - .scope_end = prelude.scope.scope_end, - .rules = rules, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .viewport => { - this.rules.v.append(input.allocator(), .{ - .viewport = css_rules.viewport.ViewportRule{ - .vendor_prefix = prelude.viewport, - .declarations = switch (DeclarationBlock.parse(input, this.options)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - .loc = loc, - }, - }) catch |err| bun.handleOom(err); - return .success; - }, - .keyframes => { - var parser = css_rules.keyframes.KeyframesListParser{}; - var iter = RuleBodyParser(css_rules.keyframes.KeyframesListParser).new(input, &parser); - // todo_stuff.think_mem_mgmt - var keyframes = ArrayList(css_rules.keyframes.Keyframe){}; - - while (iter.next()) |result| { - if (result.asValue()) |keyframe| { - keyframes.append( - input.allocator(), - keyframe, - ) catch |err| bun.handleOom(err); - } - } - - this.rules.v.append(input.allocator(), .{ - .keyframes = css_rules.keyframes.KeyframesRule{ - .name = prelude.keyframes.name, - .keyframes = keyframes, - .vendor_prefix = prelude.keyframes.prefix, - .loc = loc, - }, - }) catch |err| bun.handleOom(err); - return .success; - }, - .page => { - const selectors = prelude.page; - const rule = switch (css_rules.page.PageRule.parse(selectors, input, loc, this.options)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append( - input.allocator(), - .{ .page = rule }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .moz_document => { - const rules = switch (this.parseStyleBlock(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append(input.allocator(), .{ - .moz_document = css_rules.document.MozDocumentRule(T.CustomAtRuleParser.AtRule){ - .rules = rules, - .loc = loc, - }, - }) catch |err| bun.handleOom(err); - return .success; - }, - .layer => { - const name = if (prelude.layer.len() == 0) null else if (prelude.layer.len() == 1) names: { - break :names prelude.layer.at(0).*; - } else return .{ .err = input.newError(.at_rule_body_invalid) }; - - T.CustomAtRuleParser.onLayerRule(this.at_rule_parser, &prelude.layer); - const old_len = T.CustomAtRuleParser.enclosingLayerLength(this.at_rule_parser); - if (name != null) { - T.CustomAtRuleParser.pushToEnclosingLayer(this.at_rule_parser, name.?); - } else { - T.CustomAtRuleParser.bumpAnonLayerCount(this.at_rule_parser, 1); - } - - const rules = switch (this.parseStyleBlock(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - if (name == null) { - T.CustomAtRuleParser.bumpAnonLayerCount(this.at_rule_parser, -1); - } - T.CustomAtRuleParser.resetEnclosingLayer(this.at_rule_parser, old_len); - - this.rules.v.append(input.allocator(), .{ - .layer_block = css_rules.layer.LayerBlockRule(T.CustomAtRuleParser.AtRule){ .name = name, .rules = rules, .loc = loc }, - }) catch |err| bun.handleOom(err); - return .success; - }, - .property => { - const name = prelude.property[0]; - this.rules.v.append(input.allocator(), .{ - .property = switch (css_rules.property.PropertyRule.parse(name, input, loc)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - }) catch |err| bun.handleOom(err); - return .success; - }, - .import, .namespace, .custom_media, .charset => { - // These rules don't have blocks - return .{ .err = input.newUnexpectedTokenError(.open_curly) }; - }, - .starting_style => { - const rules = switch (this.parseStyleBlock(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - this.rules.v.append( - input.allocator(), - .{ - .starting_style = css_rules.starting_style.StartingStyleRule(T.CustomAtRuleParser.AtRule){ - .rules = rules, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .nest => { - const selectors = prelude.nest; - const result = switch (this.parseNested(input, true)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const declarations = result[0]; - const rules = result[1]; - this.rules.v.append( - input.allocator(), - .{ - .nesting = css_rules.nesting.NestingRule(T.CustomAtRuleParser.AtRule){ - .style = css_rules.style.StyleRule(T.CustomAtRuleParser.AtRule){ - .selectors = selectors, - .declarations = declarations, - .vendor_prefix = .{}, - .rules = rules, - .loc = loc, - }, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .font_feature_values => bun.unreachablePanic("", .{}), - .unknown => { - this.rules.v.append( - input.allocator(), - .{ - .unknown = css_rules.unknown.UnknownAtRule{ - .name = prelude.unknown.name, - .prelude = prelude.unknown.tokens, - .block = switch (TokenListFns.parse(input, this.options, 0)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .custom => { - this.rules.v.append( - input.allocator(), - .{ - .custom = switch (parse_custom_at_rule_body(T, prelude.custom, input, start, this.options, this.at_rule_parser, this.is_in_style_rule)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - } - } - - pub fn ruleWithoutBlock(this: *This, prelude: AtRuleParser.Prelude, start: *const ParserState) Maybe(AtRuleParser.AtRule, void) { - const loc = this.getLoc(start); - switch (prelude) { - .layer => { - if (this.is_in_style_rule or prelude.layer.len() == 0) { - return .{ .err = {} }; - } - - T.CustomAtRuleParser.onLayerRule(this.at_rule_parser, &prelude.layer); - - this.rules.v.append( - this.allocator, - .{ - .layer_statement = css_rules.layer.LayerStatementRule{ - .names = prelude.layer, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .unknown => { - this.rules.v.append( - this.allocator, - .{ - .unknown = css_rules.unknown.UnknownAtRule{ - .name = prelude.unknown.name, - .prelude = prelude.unknown.tokens, - .block = null, - .loc = loc, - }, - }, - ) catch |err| bun.handleOom(err); - return .success; - }, - .custom => { - this.rules.v.append(this.allocator, switch (parse_custom_at_rule_without_block( - T, - prelude.custom, - start, - this.options, - this.at_rule_parser, - this.is_in_style_rule, - )) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }) catch |err| bun.handleOom(err); - return .success; - }, - else => return .{ .err = {} }, - } - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = selector.parser.SelectorList; - pub const QualifiedRule = void; - - pub fn parsePrelude(this: *This, input: *Parser) Result(Prelude) { - var selector_parser = selector.parser.SelectorParser{ - .is_nesting_allowed = true, - .options = this.options, - .allocator = input.allocator(), - }; - - if (this.is_in_style_rule) { - return selector.parser.SelectorList.parseRelative(&selector_parser, input, .discard_list, .implicit); - } else { - return selector.parser.SelectorList.parse(&selector_parser, input, .discard_list, .none); - } - } - - pub fn parseBlock(this: *This, selectors: Prelude, start: *const ParserState, input: *Parser) Result(QualifiedRule) { - const loc = this.getLoc(start); - defer this.composes_refs.clearRetainingCapacity(); - // allow composes if: - // - NOT in nested style rules - // - AND there is only one class selector - if (input.flags.css_modules) out: { - if (this.is_in_style_rule) { - this.composes_state = .{ .disallow_nested = .{ .line = loc.line, .column = loc.column } }; - break :out; - } - if (selectors.v.len() != 1) { - this.composes_state = .{ .disallow_not_single_class = .{ .line = loc.line, .column = loc.column } }; - break :out; - } - - const sel = selectors.v.slice()[0]; - if (sel.components.items.len != 1) { - this.composes_state = .{ .disallow_not_single_class = .{ .line = loc.line, .column = loc.column } }; - break :out; - } - - const comp = &sel.components.items[0]; - if (comp.asClass()) |r| { - const ref = r.asRef().?; - this.composes_refs.append(input.allocator(), ref); - this.composes_state = .{ .allow = .{ .line = loc.line, .column = loc.column } }; - break :out; - } - - this.composes_state = .{ .disallow_not_single_class = .{ .line = loc.line, .column = loc.column } }; - } - const location = input.position(); - const result = switch (this.parseNested(input, true)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const declarations: DeclarationBlock = result[0]; - const rules = result[1]; - - // We parsed a style rule with the `composes` property - // - // Track which properties it used so we can validate it later (it is undefined - // behavior when composing and properties conflict so we will warn the user - // about that). - if (this.composes_state == .allow) { - const len = input.position() - location; - var usage = PropertyBitset.initEmpty(); - var custom_properties = bun.BabyList([]const u8){}; - fillPropertyBitSet(this.allocator, &usage, &declarations, &custom_properties); - - const custom_properties_slice = custom_properties.slice(); - - for (this.composes_refs.slice()) |ref| { - const entry = bun.handleOom(this.local_properties.getOrPut(this.allocator, ref)); - const property_usage: *PropertyUsage = if (!entry.found_existing) brk: { - entry.value_ptr.* = PropertyUsage{ .range = bun.logger.Range{ .loc = bun.logger.Loc{ .start = @intCast(location) }, .len = @intCast(len) } }; - break :brk entry.value_ptr; - } else entry.value_ptr; - property_usage.fill(&usage, custom_properties_slice); - } - } - - this.rules.v.append(this.allocator, .{ - .style = StyleRule(AtRuleT){ - .selectors = selectors, - .vendor_prefix = VendorPrefix{}, - .declarations = declarations, - .rules = rules, - .loc = loc, - }, - }) catch |err| bun.handleOom(err); - - return .success; - } - }; - - pub const RuleBodyItemParser = struct { - pub fn parseQualified(this: *This) bool { - _ = this; // autofix - return true; - } - - pub fn parseDeclarations(this: *This) bool { - return this.allow_declarations; - } - }; - - pub const DeclarationParser = struct { - pub const Declaration = void; - - pub fn parseValue(this: *This, name: []const u8, input: *Parser) Result(Declaration) { - return css_decls.parse_declaration_impl( - name, - input, - &this.declarations, - &this.important_declarations, - this.options, - this, - ); - } - }; - - /// If css modules is enabled, we want to record each occurrence of the `composes` property - /// for the bundler so we can generate the lazy JS import object later. - pub fn recordComposes(this: *This, allocator: Allocator, composes: *Composes) void { - for (this.composes_refs.slice()) |ref| { - const entry = bun.handleOom(this.composes.getOrPut(allocator, ref)); - if (!entry.found_existing) { - entry.value_ptr.* = ComposesEntry{}; - } - bun.handleOom(entry.value_ptr.*.composes.append(allocator, composes.deepClone(allocator))); - } - } - - pub fn parseNested(this: *This, input: *Parser, is_style_rule: bool) Result(struct { DeclarationBlock, CssRuleList(T.CustomAtRuleParser.AtRule) }) { - // TODO: think about memory management in error cases - var rules = CssRuleList(T.CustomAtRuleParser.AtRule){}; - var nested_parser = This{ - .allocator = input.allocator(), - .options = this.options, - .at_rule_parser = this.at_rule_parser, - .declarations = DeclarationList{}, - .important_declarations = DeclarationList{}, - .rules = &rules, - .is_in_style_rule = this.is_in_style_rule or is_style_rule, - .allow_declarations = this.allow_declarations or this.is_in_style_rule or is_style_rule, - // .composes_state = this.allow_composes and !this.is_in_style_rule, - .composes_state = if (this.is_in_style_rule and this.composes_state == .allow) - .{ .disallow_nested = .{ .line = this.composes_state.allow.line, .column = this.composes_state.allow.column } } - else - this.composes_state, - .composes = this.composes, - .composes_refs = this.composes_refs, - .local_properties = this.local_properties, - }; - - const parse_declarations = This.RuleBodyItemParser.parseDeclarations(&nested_parser); - // TODO: think about memory management - var errors = ArrayList(ParseError(ParserError)){}; - var iter = RuleBodyParser(This).new(input, &nested_parser); - - while (iter.next()) |result| { - if (result.asErr()) |e| { - if (parse_declarations) { - iter.parser.declarations.clearRetainingCapacity(); - iter.parser.important_declarations.clearRetainingCapacity(); - errors.append( - this.allocator, - e, - ) catch |err| bun.handleOom(err); - } else { - if (iter.parser.options.error_recovery) { - iter.parser.options.warn(e); - continue; - } - return .{ .err = e }; - } - } - } - - if (parse_declarations) { - if (errors.items.len > 0) { - if (this.options.error_recovery) { - for (errors.items) |e| { - this.options.warn(e); - } - } else { - return .{ .err = errors.orderedRemove(0) }; - } - } - } - - return .{ - .result = .{ - DeclarationBlock{ - .declarations = nested_parser.declarations, - .important_declarations = nested_parser.important_declarations, - }, - rules, - }, - }; - } - - pub fn parseStyleBlock(this: *This, input: *Parser) Result(CssRuleList(T.CustomAtRuleParser.AtRule)) { - const srcloc = input.currentSourceLocation(); - const loc = Location{ - .source_index = this.options.source_index, - .line = srcloc.line, - .column = srcloc.column, - }; - - // Declarations can be immediately within @media and @supports blocks that are nested within a parent style rule. - // These act the same way as if they were nested within a `& { ... }` block. - const declarations, var rules = switch (this.parseNested(input, false)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - if (declarations.len() > 0) { - rules.v.insert( - input.allocator(), - 0, - .{ - .style = StyleRule(T.CustomAtRuleParser.AtRule){ - .selectors = selector.parser.SelectorList.fromSelector( - input.allocator(), - selector.parser.Selector.fromComponent(input.allocator(), .nesting), - ), - .declarations = declarations, - .vendor_prefix = .{}, - .rules = .{}, - .loc = loc, - }, - }, - ) catch unreachable; - } - - return .{ .result = rules }; - } - }; -} - -pub fn StyleSheetParser(comptime P: type) type { - ValidAtRuleParser(P); - ValidQualifiedRuleParser(P); - - if (P.QualifiedRuleParser.QualifiedRule != P.AtRuleParser.AtRule) { - @compileError("StyleSheetParser: P.QualifiedRuleParser.QualifiedRule != P.AtRuleParser.AtRule"); - } - - const Item = P.AtRuleParser.AtRule; - - return struct { - input: *Parser, - parser: *P, - any_rule_so_far: bool = false, - - pub fn new(input: *Parser, parser: *P) @This() { - return .{ - .input = input, - .parser = parser, - }; - } - - pub fn next(this: *@This(), allocator: Allocator) ?(Result(Item)) { - while (true) { - this.input.@"skip cdc and cdo"(); - - const start = this.input.state(); - const at_keyword: ?[]const u8 = switch (this.input.nextByte() orelse return null) { - '@' => brk: { - const at_keyword: *Token = switch (this.input.nextIncludingWhitespaceAndComments()) { - .result => |vv| vv, - .err => { - this.input.reset(&start); - break :brk null; - }, - }; - - if (at_keyword.* == .at_keyword) break :brk at_keyword.at_keyword; - this.input.reset(&start); - break :brk null; - }, - else => null, - }; - - if (at_keyword) |name| { - const first_stylesheet_rule = !this.any_rule_so_far; - this.any_rule_so_far = true; - - if (first_stylesheet_rule and bun.strings.eqlCaseInsensitiveASCII(name, "charset", true)) { - const delimiters = Delimiters{ - .semicolon = true, - .close_curly_bracket = true, - }; - _ = this.input.parseUntilAfter(delimiters, void, {}, voidWrap(void, Parser.parseEmpty)); - } else { - return parse_at_rule(allocator, &start, name, this.input, P, this.parser); - } - } else { - this.any_rule_so_far = true; - const result = parse_qualified_rule(&start, this.input, P, this.parser, Delimiters{ .curly_bracket = true }); - return result; - } - } - } - }; -} - -/// A result returned from `to_css`, including the serialized CSS -/// and other metadata depending on the input options. -pub const ToCssResult = struct { - /// Serialized CSS code. - code: []const u8, - /// A map of CSS module exports, if the `css_modules` option was - /// enabled during parsing. - exports: ?CssModuleExports, - /// A map of CSS module references, if the `css_modules` config - /// had `dashed_idents` enabled. - references: ?CssModuleReferences, - /// A list of dependencies (e.g. `@import` or `url()`) found in - /// the style sheet, if the `analyze_dependencies` option is enabled. - dependencies: ?ArrayList(Dependency), -}; - -pub const ToCssResultInternal = struct { - /// A map of CSS module exports, if the `css_modules` option was - /// enabled during parsing. - exports: ?CssModuleExports, - /// A map of CSS module references, if the `css_modules` config - /// had `dashed_idents` enabled. - references: ?CssModuleReferences, - /// A list of dependencies (e.g. `@import` or `url()`) found in - /// the style sheet, if the `analyze_dependencies` option is enabled. - dependencies: ?ArrayList(Dependency), -}; - -pub const MinifyOptions = struct { - /// Targets to compile the CSS for. - targets: targets.Targets, - /// A list of known unused symbols, including CSS class names, - /// ids, and `@keyframe` names. The declarations of these will be removed. - unused_symbols: std.StringArrayHashMapUnmanaged(void), - - pub fn default() MinifyOptions { - return MinifyOptions{ - .targets = .{}, - .unused_symbols = .{}, - }; - } -}; - -pub const BundlerStyleSheet = StyleSheet(BundlerAtRule); -pub const BundlerCssRuleList = CssRuleList(BundlerAtRule); -pub const BundlerCssRule = CssRule(BundlerAtRule); -pub const BundlerLayerBlockRule = css_rules.layer.LayerBlockRule(BundlerAtRule); -pub const BundlerSupportsRule = css_rules.supports.SupportsRule(BundlerAtRule); -pub const BundlerMediaRule = css_rules.media.MediaRule(BundlerAtRule); -pub const BundlerPrintResult = bun.css.PrintResult(BundlerAtRule); -pub const BundlerTailwindState = struct { - source: []const u8, - index: bun.bundle_v2.Index, - output_from_tailwind: ?[]const u8 = null, -}; - -/// Additional data we don't want store -/// on the stylesheet -pub const StylesheetExtra = struct { - /// Uses when css modules is enabled - symbols: SymbolList = .{}, -}; - -pub const ParserExtra = struct { - symbols: SymbolList = .{}, - local_scope: LocalScope = .{}, - source_index: SrcIndex, -}; - -pub const CustomIdentList = css_values.ident.CustomIdentList; -pub const Specifier = css_properties.css_modules.Specifier; - -/// Reference to a symbol in a stylesheet. -pub const CssRef = packed struct(u32) { - inner_index: u26 = 0, - - tag: Tag, - - pub const Tag = packed struct(u6) { - class: bool = false, - id: bool = false, - animation: bool = false, - keyframes: bool = false, - container: bool = false, - counter_style: bool = false, - - pub const ID = Tag{ .id = true }; - pub const CLASS = Tag{ .class = true }; - - pub fn canBeComposed(this: @This()) bool { - return this.class; - } - }; - - pub fn canBeComposed(this: @This()) bool { - return this.tag.canBeComposed(); - } - - pub fn sourceIndex(_: @This(), source_index: u32) u32 { - return source_index; - } - - pub fn innerIndex(this: @This()) u32 { - return this.inner_index; - } - - pub fn toRealRef(this: @This(), source_index: u32) bun.bundle_v2.Ref { - return bun.bundle_v2.Ref{ - .inner_index = this.inner_index, - .source_index = @intCast(source_index), - .tag = .symbol, - }; - } -}; -const LocalEntry = struct { - ref: CssRef, - loc: bun.logger.Loc, -}; -/// If css modules is enabled, this maps locally scoped class names to their ref. -/// -/// We use this ref as a layer of indirection during the bundling stage because we don't -/// know the final generated class names for local scope until print time. -pub const LocalScope = bun.StringArrayHashMapUnmanaged(LocalEntry); -/// Local symbol renaming results go here -pub const LocalsResultsMap = bun.bundle_v2.MangledProps; -/// Using `compose` and having conflicting properties is undefined behavior according -/// to the css modules spec. We should warn the user about this. -pub const LocalPropertyUsage = std.AutoArrayHashMapUnmanaged(bun.bundle_v2.Ref, PropertyUsage); -pub const Composes = css_properties.css_modules.Composes; -pub const ComposesMap = std.AutoArrayHashMapUnmanaged(bun.bundle_v2.Ref, ComposesEntry); - -pub const ComposesEntry = struct { - composes: bun.BabyList(Composes) = .{}, -}; -pub const PropertyUsage = struct { - bitset: PropertyBitset = PropertyBitset.initEmpty(), - custom_properties: []const []const u8 = &.{}, - range: bun.logger.Range, - - pub inline fn fill(this: *PropertyUsage, used: *const PropertyBitset, custom_properties: []const []const u8) void { - this.bitset.setUnion(used.*); - this.custom_properties = custom_properties; - } -}; - -pub const PropertyBitset = std.bit_set.ArrayBitSet(usize, std.math.ceilPowerOfTwo(u16, bun.meta.EnumFields(PropertyIdTag).len) catch unreachable); -pub fn fillPropertyBitSet(allocator: Allocator, bitset: *PropertyBitset, block: *const DeclarationBlock, custom_properties: *bun.BabyList([]const u8)) void { - for (block.declarations.items) |*prop| { - const tag = switch (prop.*) { - .custom => { - bun.handleOom(custom_properties.append(allocator, prop.custom.name.asStr())); - continue; - }, - .unparsed => |u| @as(PropertyIdTag, u.property_id), - .composes => continue, - else => @as(PropertyIdTag, prop.*), - }; - const int: u16 = @intFromEnum(tag); - bitset.set(int); - } - for (block.important_declarations.items) |*prop| { - const tag = switch (prop.*) { - .custom => { - bun.handleOom(custom_properties.append(allocator, prop.custom.name.asStr())); - continue; - }, - .unparsed => |u| @as(PropertyIdTag, u.property_id), - .composes => continue, - else => @as(PropertyIdTag, prop.*), - }; - const int: u16 = @intFromEnum(tag); - bitset.set(int); - } -} - -pub fn StyleSheet(comptime AtRule: type) type { - return struct { - /// A list of top-level rules within the style sheet. - rules: CssRuleList(AtRule), - sources: ArrayList([]const u8), - source_map_urls: ArrayList(?[]const u8), - license_comments: ArrayList([]const u8), - options: ParserOptions, - tailwind: if (AtRule == BundlerAtRule) ?*BundlerTailwindState else u0 = if (AtRule == BundlerAtRule) null else 0, - layer_names: bun.BabyList(LayerName) = .{}, - - /// Used when css modules is enabled. - /// - /// Maps `local name string` -> `Ref` - /// - /// Invariants: - /// 1. `local_scope.values()[i].source_index == ` - /// 2. `local_scope.values()[i].tag == .symbol` - /// 3. `local_scopes.values().last().inner_index == symbols.count() - 1` - local_scope: LocalScope = .{}, - /// Used when css modules is enabled. - /// - /// Track which properties are used in local scope. - /// - /// Used later to warn when using `composes` property on - /// two style rules which have conflicting properties. - local_properties: LocalPropertyUsage = .{}, - /// Used whenn css modules is enabled. - /// - /// `bun.bundle_v2.Ref` => `bun.BabyList(ComposesExtended)` - composes: ComposesMap, - - const This = @This(); - - pub fn empty(allocator: Allocator) This { - return This{ - .rules = .{}, - .sources = .{}, - .source_map_urls = .{}, - .license_comments = .{}, - .options = ParserOptions.default(allocator, null), - .composes = .{}, - }; - } - - /// Minify and transform the style sheet for the provided browser targets. - pub fn minify(this: *@This(), allocator: Allocator, options: MinifyOptions, extra: *const StylesheetExtra) Maybe(void, Err(MinifyErrorKind)) { - const ctx = PropertyHandlerContext.new(allocator, options.targets, &options.unused_symbols); - var handler = declaration.DeclarationHandler.default(); - var important_handler = declaration.DeclarationHandler.default(); - - // @custom-media rules may be defined after they are referenced, but may only be defined at the top level - // of a stylesheet. Do a pre-scan here and create a lookup table by name. - var custom_media: ?std.StringArrayHashMapUnmanaged(css_rules.custom_media.CustomMediaRule) = if (this.options.flags.custom_media and options.targets.shouldCompileSame(.custom_media_queries)) brk: { - var custom_media = std.StringArrayHashMapUnmanaged(css_rules.custom_media.CustomMediaRule){}; - - for (this.rules.v.items) |*rule| { - if (rule.* == .custom_media) { - bun.handleOom(custom_media.put(allocator, rule.custom_media.name.v, rule.custom_media.deepClone(allocator))); - } - } - - break :brk custom_media; - } else null; - defer if (custom_media) |*media| media.deinit(allocator); - - var minify_ctx = MinifyContext{ - .allocator = allocator, - .targets = &options.targets, - .handler = &handler, - .important_handler = &important_handler, - .handler_context = ctx, - .unused_symbols = &options.unused_symbols, - .custom_media = custom_media, - .css_modules = this.options.css_modules != null, - .extra = extra, - }; - - this.rules.minify(&minify_ctx, false) catch { - @panic("TODO: Handle"); - }; - - return .success; - } - - pub fn toCssWithWriter( - this: *const @This(), - allocator: Allocator, - writer: *std.Io.Writer, - options: css_printer.PrinterOptions, - import_info: ?bun.css.ImportInfo, - local_names: ?*const LocalsResultsMap, - symbols: *const bun.ast.Symbol.Map, - ) PrintResult(ToCssResultInternal) { - var printer = Printer.new(allocator, std.array_list.Managed(u8).init(allocator), writer, options, import_info, local_names, symbols); - const result = this.toCssWithWriterImpl(allocator, &printer, options) catch { - bun.assert(printer.error_kind != null); - return .{ - .err = printer.error_kind.?, - }; - }; - - return .{ .result = result }; - } - - pub fn toCssWithWriterImpl(this: *const @This(), allocator: Allocator, printer: *Printer, options: css_printer.PrinterOptions) PrintErr!ToCssResultInternal { - const project_root = options.project_root; - - // #[cfg(feature = "sourcemap")] - // { - // printer.sources = Some(&self.sources); - // } - - // #[cfg(feature = "sourcemap")] - // if printer.source_map.is_some() { - // printer.source_maps = self.sources.iter().enumerate().map(|(i, _)| self.source_map(i)).collect(); - // } - - for (this.license_comments.items) |comment| { - try printer.writeStr("/*"); - try printer.writeComment(comment); - try printer.writeStr("*/"); - try printer.newline(); - } - - if (this.options.css_modules) |*config| { - var references = CssModuleReferences{}; - printer.css_module = CssModule.new(allocator, config, &this.sources, project_root, &references); - - try this.rules.toCss(printer); - try printer.newline(); - - return ToCssResultInternal{ - .dependencies = printer.dependencies, - .exports = exports: { - const val = printer.css_module.?.exports_by_source_index.items[0]; - printer.css_module.?.exports_by_source_index.items[0] = .{}; - break :exports val; - }, - // .code = dest.items, - .references = references, - }; - } else { - try this.rules.toCss(printer); - try printer.newline(); - return ToCssResultInternal{ - .dependencies = printer.dependencies, - // .code = dest.items, - .exports = null, - .references = null, - }; - } - } - - pub fn toCss( - this: *const @This(), - allocator: Allocator, - options: css_printer.PrinterOptions, - import_info: ?bun.css.ImportInfo, - local_names: ?*const LocalsResultsMap, - symbols: *const bun.ast.Symbol.Map, - ) PrintResult(ToCssResult) { - // TODO: this is not necessary - // Make sure we always have capacity > 0: https://github.com/napi-rs/napi-rs/issues/1124. - var dest = std.Io.Writer.Allocating.initCapacity(allocator, 1) catch unreachable; - const writer = &dest.writer; - const result = switch (toCssWithWriter( - this, - allocator, - writer, - options, - import_info, - local_names, - symbols, - )) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = ToCssResult{ - .code = dest.written(), - .dependencies = result.dependencies, - .exports = result.exports, - .references = result.references, - }, - }; - } - - pub fn parse(allocator: Allocator, code: []const u8, options: ParserOptions, import_records: ?*bun.BabyList(ImportRecord), source_index: SrcIndex) Maybe(struct { This, StylesheetExtra }, Err(ParserError)) { - var default_at_rule_parser = DefaultAtRuleParser{}; - return parseWith(allocator, code, options, DefaultAtRuleParser, &default_at_rule_parser, import_records, source_index); - } - - pub fn parseBundler(allocator: Allocator, code: []const u8, options: ParserOptions, import_records: *bun.BabyList(ImportRecord), source_index: SrcIndex) Maybe(struct { This, StylesheetExtra }, Err(ParserError)) { - var at_rule_parser = BundlerAtRuleParser{ - .import_records = import_records, - .allocator = allocator, - .options = &options, - .layer_names = .{}, - }; - return parseWith(allocator, code, options, BundlerAtRuleParser, &at_rule_parser, import_records, source_index); - } - - /// Parse a style sheet from a string. - pub fn parseWith( - allocator: Allocator, - code: []const u8, - options: ParserOptions, - comptime P: type, - at_rule_parser: *P, - import_records: ?*bun.BabyList(ImportRecord), - source_index: SrcIndex, - ) Maybe(struct { This, StylesheetExtra }, Err(ParserError)) { - var composes = ComposesMap{}; - var parser_extra = ParserExtra{ - .local_scope = .{}, - .symbols = .{}, - .source_index = source_index, - }; - var local_properties = LocalPropertyUsage{}; - - var input = ParserInput.new(allocator, code); - var parser = Parser.new( - &input, - import_records, - .{ - .css_modules = options.css_modules != null, - }, - &parser_extra, - ); - - var license_comments = ArrayList([]const u8){}; - var state = parser.state(); - while (switch (parser.nextIncludingWhitespaceAndComments()) { - .result => |v| v, - .err => null, - }) |token| { - switch (token.*) { - .whitespace => {}, - .comment => |comment| { - if (bun.strings.startsWithChar(comment, '!')) { - bun.handleOom(license_comments.append(allocator, comment)); - } - }, - else => break, - } - state = parser.state(); - } - parser.reset(&state); - - var rules = CssRuleList(AtRule){}; - var rule_parser = TopLevelRuleParser(P).new(allocator, &options, at_rule_parser, &rules, &composes, &local_properties); - var rule_list_parser = StyleSheetParser(TopLevelRuleParser(P)).new(&parser, &rule_parser); - - while (rule_list_parser.next(allocator)) |result| { - if (result.asErr()) |e| { - const result_options = rule_list_parser.parser.options; - if (result_options.error_recovery) { - // todo_stuff.warn - continue; - } - - return .{ .err = Err(ParserError).fromParseError(e, options.filename) }; - } - } - - var sources = ArrayList([]const u8){}; - bun.handleOom(sources.append(allocator, options.filename)); - var source_map_urls = ArrayList(?[]const u8){}; - bun.handleOom(source_map_urls.append(allocator, parser.currentSourceMapUrl())); - - return .{ - .result = .{ - This{ - .rules = rules, - .sources = sources, - .source_map_urls = source_map_urls, - .license_comments = license_comments, - .options = options, - .layer_names = if (comptime P == BundlerAtRuleParser) at_rule_parser.layer_names else .{}, - .local_scope = parser_extra.local_scope, - .local_properties = local_properties, - .composes = composes, - }, - StylesheetExtra{ - .symbols = parser_extra.symbols, - }, - }, - }; - } - - pub fn debugLayerRuleSanityCheck(this: *const @This()) void { - if (comptime !bun.Environment.isDebug) return; - - const layer_names_field_len = this.layer_names.len; - _ = layer_names_field_len; // autofix - var actual_layer_rules_len: usize = 0; - - for (this.rules.v.items) |*rule| { - switch (rule.*) { - .layer_block => { - actual_layer_rules_len += 1; - }, - } - } - - // bun.debugAssert() - } - - pub fn containsTailwindDirectives(this: *const @This()) bool { - if (comptime AtRule != BundlerAtRule) @compileError("Expected BundlerAtRule for this function."); - var found_import: bool = false; - for (this.rules.v.items) |*rule| { - switch (rule.*) { - .custom => { - return true; - }, - // .charset => {}, - // TODO: layer - .layer_block => {}, - .import => { - found_import = true; - }, - else => { - return false; - }, - } - } - return false; - } - - pub fn newFromTailwindImports( - allocator: Allocator, - options: ParserOptions, - imports_from_tailwind: CssRuleList(AtRule), - ) @This() { - _ = allocator; // autofix - if (comptime AtRule != BundlerAtRule) @compileError("Expected BundlerAtRule for this function."); - - const stylesheet = This{ - .rules = imports_from_tailwind, - .sources = .{}, - .source_map_urls = .{}, - .license_comments = .{}, - .options = options, - }; - - return stylesheet; - } - - /// *NOTE*: Used for Tailwind stylesheets only - /// - /// This plucks out the import rules from the Tailwind stylesheet into a separate rule list, - /// replacing them with `.ignored` rules. - /// - /// We do this because Tailwind's compiler pipeline does not bundle imports, so we handle that - /// ourselves in the bundler. - pub fn pluckImports(this: *const @This(), allocator: Allocator, out: *CssRuleList(AtRule), new_import_records: *bun.BabyList(ImportRecord)) void { - if (comptime AtRule != BundlerAtRule) @compileError("Expected BundlerAtRule for this function."); - const State = enum { count, exec }; - - const STATES = comptime [_]State{ .count, .exec }; - - var count: u32 = 0; - inline for (STATES[0..]) |state| { - if (comptime state == .exec) { - bun.handleOom(out.v.ensureUnusedCapacity(allocator, count)); - } - var saw_imports = false; - for (this.rules.v.items) |*rule| { - switch (rule.*) { - // TODO: layer, might have imports - .layer_block => {}, - .import => { - if (!saw_imports) saw_imports = true; - switch (state) { - .count => count += 1, - .exec => { - const import_rule = &rule.import; - out.v.appendAssumeCapacity(rule.*); - const import_record_idx = new_import_records.len; - import_rule.import_record_idx = import_record_idx; - new_import_records.append(allocator, ImportRecord{ - .path = bun.fs.Path.init(import_rule.url), - .kind = if (import_rule.supports != null) .at_conditional else .at, - .range = bun.logger.Range.None, - }) catch |err| bun.handleOom(err); - rule.* = .ignored; - }, - } - }, - .unknown => { - if (bun.strings.eqlComptime(rule.unknown.name, "tailwind")) { - continue; - } - }, - else => {}, - } - if (saw_imports) break; - } - } - } - }; -} - -pub const StyleAttribute = struct { - declarations: DeclarationBlock, - sources: ArrayList([]const u8), - - pub fn parse(allocator: Allocator, code: []const u8, options: ParserOptions, import_records: *bun.BabyList(ImportRecord), source_index: SrcIndex) Maybe(StyleAttribute, Err(ParserError)) { - var parser_extra = ParserExtra{ - .local_scope = .{}, - .symbols = .{}, - .source_index = source_index, - }; - var input = ParserInput.new(allocator, code); - var parser = Parser.new( - &input, - import_records, - .{ - .css_modules = options.css_modules != null, - }, - &parser_extra, - ); - const sources = sources: { - var s = bun.handleOom(ArrayList([]const u8).initCapacity(allocator, 1)); - s.appendAssumeCapacity(options.filename); - break :sources s; - }; - return .{ .result = StyleAttribute{ - .declarations = switch (DeclarationBlock.parse(&parser, &options)) { - .result => |v| v, - .err => |e| return .{ .err = Err(ParserError).fromParseError(e, "") }, - }, - .sources = sources, - } }; - } - - pub fn toCss(this: *const StyleAttribute, allocator: Allocator, options: PrinterOptions, import_info: ?ImportInfo) PrintErr!ToCssResult { - // #[cfg(feature = "sourcemap")] - // assert!( - // options.source_map.is_none(), - // "Source maps are not supported for style attributes" - // ); - - var symbols = bun.ast.Symbol.Map{}; - var dest = std.Io.Writer.Allocating.init(allocator); - const writer = &dest.writer; - var printer = Printer.new( - allocator, - std.array_list.Managed(u8).init(allocator), - writer, - options, - import_info, - null, - &symbols, - ); - printer.sources = &this.sources; - - try this.declarations.toCss(&printer); - - return ToCssResult{ - .dependencies = printer.dependencies, - .code = dest.written(), - .exports = null, - .references = null, - }; - } - - pub fn minify(this: *@This(), allocator: Allocator, options: MinifyOptions) void { - _ = allocator; // autofix - _ = this; // autofix - _ = options; // autofix - // TODO: IMPLEMENT THIS! - } -}; - -pub fn ValidDeclarationParser(comptime P: type) void { - // The finished representation of a declaration. - _ = P.DeclarationParser.Declaration; - - // Parse the value of a declaration with the given `name`. - // - // Return the finished representation for the declaration - // as returned by `DeclarationListParser::next`, - // or `Err(())` to ignore the entire declaration as invalid. - // - // Declaration name matching should be case-insensitive in the ASCII range. - // This can be done with `std::ascii::Ascii::eq_ignore_ascii_case`, - // or with the `match_ignore_ascii_case!` macro. - // - // The given `input` is a "delimited" parser - // that ends wherever the declaration value should end. - // (In declaration lists, before the next semicolon or end of the current block.) - // - // If `!important` can be used in a given context, - // `input.try_parse(parse_important).is_ok()` should be used at the end - // of the implementation of this method and the result should be part of the return value. - // - // fn parseValue(this: *T, name: []const u8, input: *Parser) Error!T.DeclarationParser.Declaration - _ = P.DeclarationParser.parseValue; -} - -/// Also checks that P is: -/// - ValidDeclarationParser(P) -/// - ValidQualifiedRuleParser(P) -/// - ValidAtRuleParser(P) -pub fn ValidRuleBodyItemParser(comptime P: type) void { - ValidDeclarationParser(P); - ValidQualifiedRuleParser(P); - ValidAtRuleParser(P); - - // Whether we should attempt to parse declarations. If you know you won't, returning false - // here is slightly faster. - _ = P.RuleBodyItemParser.parseDeclarations; - - // Whether we should attempt to parse qualified rules. If you know you won't, returning false - // would be slightly faster. - _ = P.RuleBodyItemParser.parseQualified; - - // We should have: - // P.DeclarationParser.Declaration == P.QualifiedRuleParser.QualifiedRule == P.AtRuleParser.AtRule - if (P.DeclarationParser.Declaration != P.QualifiedRuleParser.QualifiedRule or - P.DeclarationParser.Declaration != P.AtRuleParser.AtRule) - { - @compileError("ValidRuleBodyItemParser: P.DeclarationParser.Declaration != P.QualifiedRuleParser.QualifiedRule or\n P.DeclarationParser.Declaration != P.AtRuleParser.AtRule"); - } -} - -pub fn RuleBodyParser(comptime P: type) type { - ValidRuleBodyItemParser(P); - // Same as P.AtRuleParser.AtRule and P.DeclarationParser.Declaration - const I = P.QualifiedRuleParser.QualifiedRule; - - return struct { - input: *Parser, - parser: *P, - - const This = @This(); - - pub fn new(input: *Parser, parser: *P) This { - return .{ - .input = input, - .parser = parser, - }; - } - - /// TODO: result is actually: - /// type Item = Result, &'i str)>; - /// - /// but nowhere in the source do i actually see it using the string part of the tuple - pub fn next(this: *This) ?(Result(I)) { - while (true) { - this.input.skipWhitespace(); - const start = this.input.state(); - - const tok: *Token = switch (this.input.nextIncludingWhitespaceAndComments()) { - .err => |_| return null, - .result => |vvv| vvv, - }; - - switch (tok.*) { - .close_curly, .whitespace, .semicolon, .comment => continue, - .at_keyword => { - const name = tok.at_keyword; - return parse_at_rule( - this.input.allocator(), - &start, - name, - this.input, - P, - this.parser, - ); - }, - .ident => { - if (P.RuleBodyItemParser.parseDeclarations(this.parser)) { - const name = tok.ident; - const parse_qualified = P.RuleBodyItemParser.parseQualified(this.parser); - const result: Result(I) = result: { - const error_behavior: ParseUntilErrorBehavior = if (parse_qualified) .stop else .consume; - const Closure = struct { - parser: *P, - name: []const u8, - pub fn parsefn(self: *@This(), input: *Parser) Result(I) { - if (input.expectColon().asErr()) |e| return .{ .err = e }; - return P.DeclarationParser.parseValue(self.parser, self.name, input); - } - }; - var closure = Closure{ - .parser = this.parser, - .name = name, - }; - break :result parse_until_after(this.input, Delimiters{ .semicolon = true }, error_behavior, I, &closure, Closure.parsefn); - }; - if (result.isErr() and parse_qualified) { - this.input.reset(&start); - if (parse_qualified_rule( - &start, - this.input, - P, - this.parser, - Delimiters{ .semicolon = true, .curly_bracket = true }, - ).asValue()) |qual| { - return .{ .result = qual }; - } - } - - return result; - } - }, - else => {}, - } - - const result: Result(I) = if (P.RuleBodyItemParser.parseQualified(this.parser)) result: { - this.input.reset(&start); - const delimiters = if (P.RuleBodyItemParser.parseDeclarations(this.parser)) Delimiters{ - .semicolon = true, - .curly_bracket = true, - } else Delimiters{ .curly_bracket = true }; - break :result parse_qualified_rule(&start, this.input, P, this.parser, delimiters); - } else result: { - const token = tok.*; - - const Closure = struct { token: Token, start: ParserState }; - break :result this.input.parseUntilAfter(Delimiters{ .semicolon = true }, I, &Closure{ .token = token, .start = start }, struct { - pub fn parseFn(closure: *const Closure, i: *Parser) Result(I) { - _ = i; // autofix - return .{ .err = closure.start.sourceLocation().newUnexpectedTokenError(closure.token) }; - } - }.parseFn); - }; - - return result; - } - } - }; -} - -pub const ParserOptions = struct { - /// Filename to use in error messages. - filename: []const u8, - /// Whether the enable [CSS modules](https://github.com/css-modules/css-modules). - css_modules: ?css_modules.Config, - /// The source index to assign to all parsed rules. Impacts the source map when - /// the style sheet is serialized. - source_index: u32, - /// Whether to ignore invalid rules and declarations rather than erroring. - error_recovery: bool, - /// A list that will be appended to when a warning occurs. - logger: ?*Log = null, - /// Feature flags to enable. - flags: ParserFlags, - allocator: Allocator, - - pub fn warn(this: *const ParserOptions, warning: ParseError(ParserError)) void { - if (this.logger) |lg| { - lg.addWarningFmtLineCol( - this.filename, - warning.location.line, - warning.location.column, - this.allocator, - "{f}", - .{warning.kind}, - ) catch unreachable; - } - } - - pub fn warnFmt(this: *const ParserOptions, comptime text: []const u8, args: anytype, line: u32, column: u32) void { - if (this.logger) |lg| { - lg.addWarningFmtLineCol( - this.filename, - line, - column, - this.allocator, - text, - args, - ) catch unreachable; - } - } - - pub fn warnFmtWithNotes(this: *const ParserOptions, comptime text: []const u8, args: anytype, line: u32, column: u32, notes: []bun.logger.Data) void { - if (this.logger) |lg| { - lg.addWarningFmtLineColWithNotes( - this.filename, - line, - column, - this.allocator, - text, - args, - notes, - ) catch unreachable; - } - } - - pub fn warnFmtWithNote(this: *const ParserOptions, comptime text: []const u8, args: anytype, line: u32, column: u32, note_fmt: []const u8, note_args: anytype, note_range: bun.logger.Range) void { - if (this.logger) |lg| { - lg.addRangeWarningFmtWithNote( - null, - bun.logger.Loc{ .start = @intCast(line), .end = @intCast(column) }, - this.allocator, - text, - args, - note_fmt, - note_args, - note_range, - ) catch unreachable; - } - } - - pub fn default(allocator: std.mem.Allocator, log: ?*Log) ParserOptions { - return ParserOptions{ - .filename = "", - .css_modules = null, - .source_index = 0, - .error_recovery = false, - .logger = log, - .flags = ParserFlags{}, - .allocator = allocator, - }; - } -}; - -/// Parser feature flags to enable. -pub const ParserFlags = packed struct(u8) { - /// Whether the enable the [CSS nesting](https://www.w3.org/TR/css-nesting-1/) draft syntax. - nesting: bool = false, - /// Whether to enable the [custom media](https://drafts.csswg.org/mediaqueries-5/#custom-mq) draft syntax. - custom_media: bool = false, - /// Whether to enable the non-standard >>> and /deep/ selector combinators used by Vue and Angular. - deep_selector_combinator: bool = false, - __unused: u5 = 0, -}; - -const ParseUntilErrorBehavior = enum { - consume, - stop, -}; - -// const ImportRecordHandler = union(enum) { -// list: *bun.BabyList(ImportRecord), -// // dummy: u32, - -// pub fn add(this: *ImportRecordHandler, allocator: Allocator, record: ImportRecord) u32 { -// return switch (this.*) { -// .list => |list| { -// const len = list.len; -// bun.handleOom(list.append(allocator, record)); -// return len; -// }, -// // .dummy => |*d| { -// // const val = d.*; -// // d.* += 1; -// // return val; -// // }, -// }; -// } -// }; - -pub const Parser = struct { - input: *ParserInput, - at_start_of: ?BlockType = null, - stop_before: Delimiters = Delimiters.NONE, - flags: Opts, - import_records: ?*bun.BabyList(ImportRecord), - extra: ?*ParserExtra, - - const Opts = packed struct(u8) { - css_modules: bool = false, - __unused: u7 = 0, - }; - - pub fn addSymbolForName(this: *Parser, name: []const u8, tag: CssRef.Tag, loc: bun.logger.Loc) bun.bundle_v2.Ref { - // don't call this if css modules is not enabled! - bun.assert(this.flags.css_modules); - bun.assert(this.extra != null); - if (comptime bun.Environment.allow_assert) { - // tag should only have one bit set, or none - bun.assert(@popCount(bun.bits.asInt(CssRef.Tag, tag)) <= 1); - } - - const extra = this.extra.?; - - const entry = bun.handleOom(extra.local_scope.getOrPut(this.allocator(), name)); - if (!entry.found_existing) { - entry.value_ptr.* = LocalEntry{ - .ref = CssRef{ - .inner_index = @intCast(extra.symbols.len), - .tag = tag, - }, - .loc = loc, - }; - extra.symbols.append(this.allocator(), bun.ast.Symbol{ - .kind = .local_css, - .original_name = name, - }) catch |err| bun.handleOom(err); - } else { - const prev_tag = entry.value_ptr.ref.tag; - if (!prev_tag.class and tag.class) { - entry.value_ptr.loc = loc; - entry.value_ptr.ref.tag = bun.bits.@"or"(CssRef.Tag, entry.value_ptr.ref.tag, tag); - } - } - - return entry.value_ptr.ref.toRealRef(extra.source_index.get()); - } - - // TODO: dedupe import records?? - pub fn addImportRecord(this: *Parser, url: []const u8, start_position: usize, kind: ImportKind) Result(u32) { - if (this.import_records) |import_records| { - const idx = import_records.len; - import_records.append(this.allocator(), ImportRecord{ - .path = bun.fs.Path.init(url), - .kind = kind, - .range = bun.logger.Range{ - .loc = bun.logger.Loc{ .start = @intCast(start_position) }, - .len = @intCast(url.len), // TODO: technically this is not correct because the url could be escaped - }, - }) catch |err| bun.handleOom(err); - return .{ .result = idx }; - } else { - return .{ .err = this.newBasicUnexpectedTokenError(.{ .unquoted_url = url }) }; - } - } - - pub inline fn allocator(self: *Parser) Allocator { - return self.input.tokenizer.allocator; - } - - /// Create a new Parser - /// - /// Pass in `import_records` to track imports (`@import` rules, `url()` tokens). If this - /// is `null`, calling `Parser.addImportRecord` will error. - pub fn new(input: *ParserInput, import_records: ?*bun.BabyList(ImportRecord), flags: Opts, extra: ?*ParserExtra) Parser { - return Parser{ - .input = input, - .flags = flags, - .import_records = import_records, - .extra = extra, - }; - } - - pub fn newCustomError(this: *const Parser, err: ParserError) ParseError(ParserError) { - return this.currentSourceLocation().newCustomError(err); - } - - pub fn newBasicError(this: *const Parser, kind: BasicParseErrorKind) BasicParseError { - return BasicParseError{ - .kind = kind, - .location = this.currentSourceLocation(), - }; - } - - pub fn newError(this: *const Parser, kind: BasicParseErrorKind) ParseError(ParserError) { - return .{ - .kind = .{ .basic = kind }, - .location = this.currentSourceLocation(), - }; - } - - pub fn newUnexpectedTokenError(this: *const Parser, token: Token) ParseError(ParserError) { - return this.newError(.{ .unexpected_token = token }); - } - - pub fn newBasicUnexpectedTokenError(this: *const Parser, token: Token) ParseError(ParserError) { - return this.newBasicError(.{ .unexpected_token = token }).intoDefaultParseError(); - } - - pub fn currentSourceLocation(this: *const Parser) SourceLocation { - return this.input.tokenizer.currentSourceLocation(); - } - - pub fn currentSourceMapUrl(this: *const Parser) ?[]const u8 { - return this.input.tokenizer.currentSourceMapUrl(); - } - - /// Return a slice of the CSS input, from the given position to the current one. - pub fn sliceFrom(this: *const Parser, start_position: usize) []const u8 { - return this.input.tokenizer.sliceFrom(start_position); - } - - /// Implementation of Vec::::parse - pub fn parseList(this: *Parser, comptime T: type, comptime parse_one: *const fn (*Parser) Result(T)) Result(ArrayList(T)) { - return this.parseCommaSeparated(T, parse_one); - } - - /// Parse a list of comma-separated values, all with the same syntax. - /// - /// The given closure is called repeatedly with a "delimited" parser - /// (see the `Parser::parse_until_before` method) so that it can over - /// consume the input past a comma at this block/function nesting level. - /// - /// Successful results are accumulated in a vector. - /// - /// This method returns `Err(())` the first time that a closure call does, - /// or if a closure call leaves some input before the next comma or the end - /// of the input. - pub fn parseCommaSeparated( - this: *Parser, - comptime T: type, - comptime parse_one: *const fn (*Parser) Result(T), - ) Result(ArrayList(T)) { - return this.parseCommaSeparatedInternal(T, {}, voidWrap(T, parse_one), false); - } - - pub fn parseCommaSeparatedWithCtx( - this: *Parser, - comptime T: type, - closure: anytype, - comptime parse_one: *const fn (@TypeOf(closure), *Parser) Result(T), - ) Result(ArrayList(T)) { - return this.parseCommaSeparatedInternal(T, closure, parse_one, false); - } - - fn parseCommaSeparatedInternal( - this: *Parser, - comptime T: type, - closure: anytype, - comptime parse_one: *const fn (@TypeOf(closure), *Parser) Result(T), - ignore_errors: bool, - ) Result(ArrayList(T)) { - // Vec grows from 0 to 4 by default on first push(). So allocate with - // capacity 1, so in the somewhat common case of only one item we don't - // way overallocate. Note that we always push at least one item if - // parsing succeeds. - // - // TODO(zack): might be faster to use stack fallback here - // in the common case we may have just 1, but I feel like it is also very common to have >1 - // which means every time we have >1 items we will always incur 1 more additional allocation - var sfb = std.heap.stackFallback(@sizeOf(T), this.allocator()); - const alloc = sfb.get(); - var values = ArrayList(T).initCapacity(alloc, 1) catch unreachable; - - while (true) { - this.skipWhitespace(); // Unnecessary for correctness, but may help try() in parse_one rewind less. - switch (this.parseUntilBefore(Delimiters{ .comma = true }, T, closure, parse_one)) { - .result => |v| { - values.append(alloc, v) catch unreachable; - }, - .err => |e| { - if (!ignore_errors) return .{ .err = e }; - }, - } - - const tok = switch (this.next()) { - .result => |v| v, - .err => { - // need to clone off the stack - const needs_clone = values.items.len == 1; - if (needs_clone) return .{ .result = bun.handleOom(values.clone(this.allocator())) }; - return .{ .result = values }; - }, - }; - if (tok.* != .comma) bun.unreachablePanic("", .{}); - } - } - - /// Execute the given closure, passing it the parser. - /// If the result (returned unchanged) is `Err`, - /// the internal state of the parser (including position within the input) - /// is restored to what it was before the call. - /// - /// func needs to be a function like this: `fn func(*Parser, ...@TypeOf(args_)) T` - pub inline fn tryParse(this: *Parser, comptime func: anytype, args_: anytype) bun.meta.ReturnOf(func) { - const start = this.state(); - const result = result: { - const args = brk: { - var args: std.meta.ArgsTuple(@TypeOf(func)) = undefined; - args[0] = this; - - inline for (args_, 1..) |a, i| { - args[i] = a; - } - - break :brk args; - }; - - break :result @call(.auto, func, args); - }; - if (result == .err) { - this.reset(&start); - } - return result; - } - - pub inline fn tryParseImpl(this: *Parser, comptime Ret: type, comptime func: anytype, args: anytype) Ret { - const start = this.state(); - const result = result: { - break :result @call(.auto, func, args); - }; - if (result == .err) { - this.reset(&start); - } - return result; - } - - pub inline fn parseNestedBlock(this: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) { - return parse_nested_block(this, T, closure, parsefn); - } - - pub fn isExhausted(this: *Parser) bool { - return this.expectExhausted().isOk(); - } - - /// Parse the input until exhaustion and check that it contains no “error” token. - /// - /// See `Token::is_parse_error`. This also checks nested blocks and functions recursively. - pub fn expectNoErrorToken(this: *Parser) Result(void) { - while (true) { - const tok = switch (this.nextIncludingWhitespaceAndComments()) { - .err => return .success, - .result => |v| v, - }; - switch (tok.*) { - .function, .open_paren, .open_square, .open_curly => { - if (this.parseNestedBlock(void, {}, struct { - pub fn parse(_: void, i: *Parser) Result(void) { - if (i.expectNoErrorToken().asErr()) |e| { - return .{ .err = e }; - } - return .success; - } - }.parse).asErr()) |err| { - return .{ .err = err }; - } - return .success; - }, - else => { - if (tok.isParseError()) { - return .{ .err = this.newUnexpectedTokenError(tok.*) }; - } - }, - } - } - } - - pub fn expectPercentage(this: *Parser) Result(f32) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .percentage) return .{ .result = tok.percentage.unit_value }; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectComma(this: *Parser) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .comma => return .success, - else => {}, - } - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - /// Parse a that does not have a fractional part, and return the integer value. - pub fn expectInteger(this: *Parser) Result(i32) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .number and tok.number.int_value != null) return .{ .result = tok.number.int_value.? }; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - /// Parse a and return the integer value. - pub fn expectNumber(this: *Parser) Result(f32) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .number) return .{ .result = tok.number.value }; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectDelim(this: *Parser, delim: u8) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .delim and tok.delim == delim) return .success; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectParenthesisBlock(this: *Parser) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .open_paren) return .success; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectColon(this: *Parser) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .colon) return .success; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectString(this: *Parser) Result([]const u8) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .quoted_string) return .{ .result = tok.quoted_string }; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectIdent(this: *Parser) Result([]const u8) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .ident) return .{ .result = tok.ident }; - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - /// Parse either a or a , and return the unescaped value. - pub fn expectIdentOrString(this: *Parser) Result([]const u8) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .ident => |i| return .{ .result = i }, - .quoted_string => |s| return .{ .result = s }, - else => {}, - } - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectIdentMatching(this: *Parser, name: []const u8) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .ident => |i| if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, i)) return .success, - else => {}, - } - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectFunction(this: *Parser) Result([]const u8) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .function => |fn_name| return .{ .result = fn_name }, - else => {}, - } - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectFunctionMatching(this: *Parser, name: []const u8) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .function => |fn_name| if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, fn_name)) return .success, - else => {}, - } - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn expectCurlyBracketBlock(this: *Parser) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .open_curly => return .success, - else => return .{ .err = start_location.newUnexpectedTokenError(tok.*) }, - } - } - - pub fn expectSquareBracketBlock(this: *Parser) Result(void) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .open_square => return .success, - else => return .{ .err = start_location.newUnexpectedTokenError(tok.*) }, - } - } - - /// Parse a and return the unescaped value. - pub fn expectUrl(this: *Parser) Result([]const u8) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .unquoted_url => |value| return .{ .result = value }, - .function => |name| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("url", name)) { - const result = this.parseNestedBlock([]const u8, {}, struct { - fn parse(_: void, parser: *Parser) Result([]const u8) { - return switch (parser.expectString()) { - .result => |v| .{ .result = v }, - .err => |e| .{ .err = e }, - }; - } - }.parse); - return switch (result) { - .result => |v| .{ .result = v }, - .err => |e| .{ .err = e }, - }; - } - }, - else => {}, - } - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - /// Parse either a or a , and return the unescaped value. - pub fn expectUrlOrString(this: *Parser) Result([]const u8) { - const start_location = this.currentSourceLocation(); - const tok = switch (this.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .unquoted_url => |value| return .{ .result = value }, - .quoted_string => |value| return .{ .result = value }, - .function => |name| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("url", name)) { - const result = this.parseNestedBlock([]const u8, {}, struct { - fn parse(_: void, parser: *Parser) Result([]const u8) { - return switch (parser.expectString()) { - .result => |v| .{ .result = v }, - .err => |e| .{ .err = e }, - }; - } - }.parse); - return switch (result) { - .result => |v| .{ .result = v }, - .err => |e| .{ .err = e }, - }; - } - }, - else => {}, - } - return .{ .err = start_location.newUnexpectedTokenError(tok.*) }; - } - - pub fn position(this: *Parser) usize { - bun.debugAssert(bun.strings.isOnCharBoundary(this.input.tokenizer.src, this.input.tokenizer.position)); - return this.input.tokenizer.position; - } - - fn parseEmpty(_: *Parser) Result(void) { - return .success; - } - - /// Like `parse_until_before`, but also consume the delimiter token. - /// - /// This can be useful when you don’t need to know which delimiter it was - /// (e.g. if these is only one in the given set) - /// or if it was there at all (as opposed to reaching the end of the input). - pub fn parseUntilAfter( - this: *Parser, - delimiters: Delimiters, - comptime T: type, - closure: anytype, - comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T), - ) Result(T) { - return parse_until_after( - this, - delimiters, - ParseUntilErrorBehavior.consume, - T, - closure, - parse_fn, - ); - } - - pub fn parseUntilBefore(this: *Parser, delimiters: Delimiters, comptime T: type, closure: anytype, comptime parse_fn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) { - return parse_until_before(this, delimiters, .consume, T, closure, parse_fn); - } - - pub fn parseEntirely(this: *Parser, comptime T: type, closure: anytype, comptime parsefn: *const fn (@TypeOf(closure), *Parser) Result(T)) Result(T) { - const result = switch (parsefn(closure, this)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (this.expectExhausted().asErr()) |e| return .{ .err = e }; - return .{ .result = result }; - } - - /// Check whether the input is exhausted. That is, if `.next()` would return a token. - /// Return a `Result` so that the `?` operator can be used: `input.expect_exhausted()?` - /// - /// This ignores whitespace and comments. - pub fn expectExhausted(this: *Parser) Result(void) { - const start = this.state(); - const result: Result(void) = switch (this.next()) { - .result => |t| .{ .err = start.sourceLocation().newUnexpectedTokenError(t.*) }, - .err => |e| brk: { - if (e.kind == .basic and e.kind.basic == .end_of_input) break :brk .success; - bun.unreachablePanic("Unexpected error encountered: {f}", .{e.kind}); - }, - }; - this.reset(&start); - return result; - } - - pub fn @"skip cdc and cdo"(this: *@This()) void { - if (this.at_start_of) |block_type| { - this.at_start_of = null; - consume_until_end_of_block(block_type, &this.input.tokenizer); - } - - this.input.tokenizer.@"skip cdc and cdo"(); - } - - pub fn skipWhitespace(this: *@This()) void { - if (this.at_start_of) |block_type| { - this.at_start_of = null; - consume_until_end_of_block(block_type, &this.input.tokenizer); - } - - this.input.tokenizer.skipWhitespace(); - } - - pub fn next(this: *@This()) Result(*Token) { - this.skipWhitespace(); - return this.nextIncludingWhitespaceAndComments(); - } - - /// Same as `Parser::next`, but does not skip whitespace tokens. - pub fn nextIncludingWhitespace(this: *@This()) Result(*Token) { - while (true) { - switch (this.nextIncludingWhitespaceAndComments()) { - .result => |tok| if (tok.* == .comment) {} else break, - .err => |e| return .{ .err = e }, - } - } - return .{ .result = &this.input.cached_token.?.token }; - } - - pub fn nextByte(this: *@This()) ?u8 { - const byte = this.input.tokenizer.nextByte(); - if (bun.bits.contains(Delimiters, this.stop_before, .fromByte(byte))) { - return null; - } - return byte; - } - - pub fn reset(this: *Parser, state_: *const ParserState) void { - this.input.tokenizer.reset(state_); - this.at_start_of = state_.at_start_of; - if (this.import_records) |import_records| import_records.len = state_.import_record_count; - } - - pub fn state(this: *Parser) ParserState { - return ParserState{ - .position = this.input.tokenizer.getPosition(), - .current_line_start_position = this.input.tokenizer.current_line_start_position, - .current_line_number = @intCast(this.input.tokenizer.current_line_number), - .at_start_of = this.at_start_of, - .import_record_count = if (this.import_records) |import_records| import_records.len else 0, - }; - } - - /// Same as `Parser::next`, but does not skip whitespace or comment tokens. - /// - /// **Note**: This should only be used in contexts like a CSS pre-processor - /// where comments are preserved. - /// When parsing higher-level values, per the CSS Syntax specification, - /// comments should always be ignored between tokens. - pub fn nextIncludingWhitespaceAndComments(this: *Parser) Result(*Token) { - if (this.at_start_of) |block_type| { - this.at_start_of = null; - consume_until_end_of_block(block_type, &this.input.tokenizer); - } - - const byte = this.input.tokenizer.nextByte(); - if (bun.bits.contains(Delimiters, this.stop_before, .fromByte(byte))) { - return .{ .err = this.newError(BasicParseErrorKind.end_of_input) }; - } - - const token_start_position = this.input.tokenizer.getPosition(); - const using_cached_token = this.input.cached_token != null and this.input.cached_token.?.start_position == token_start_position; - - const token = if (using_cached_token) token: { - const cached_token = &this.input.cached_token.?; - this.input.tokenizer.reset(&cached_token.end_state); - if (cached_token.token == .function) { - this.input.tokenizer.seeFunction(cached_token.token.function); - } - break :token &cached_token.token; - } else token: { - const new_token = switch (this.input.tokenizer.next()) { - .result => |v| v, - .err => return .{ .err = this.newError(BasicParseErrorKind.end_of_input) }, - }; - this.input.cached_token = CachedToken{ - .token = new_token, - .start_position = token_start_position, - .end_state = this.input.tokenizer.state(), - }; - break :token &this.input.cached_token.?.token; - }; - - if (BlockType.opening(token)) |block_type| { - this.at_start_of = block_type; - } - - return .{ .result = token }; - } - - /// Create a new unexpected token or EOF ParseError at the current location - pub fn newErrorForNextToken(this: *Parser) ParseError(ParserError) { - const token = switch (this.next()) { - .result => |t| t.*, - .err => |e| return e, - }; - return this.newError(BasicParseErrorKind{ .unexpected_token = token }); - } -}; - -/// A set of characters, to be used with the `Parser::parse_until*` methods. -/// -/// The union of two sets can be obtained with the `|` operator. Example: -/// -/// ```{rust,ignore} -/// input.parse_until_before(Delimiter::CurlyBracketBlock | Delimiter::Semicolon) -/// ``` -pub const Delimiters = packed struct(u8) { - /// The delimiter set with only the `{` opening curly bracket - curly_bracket: bool = false, - /// The delimiter set with only the `;` semicolon - semicolon: bool = false, - /// The delimiter set with only the `!` exclamation point - bang: bool = false, - /// The delimiter set with only the `,` comma - comma: bool = false, - close_curly_bracket: bool = false, - close_square_bracket: bool = false, - close_parenthesis: bool = false, - __unused: u1 = 0, - - const NONE: Delimiters = .{}; - - pub fn getDelimiter(comptime tag: @TypeOf(.enum_literal)) Delimiters { - var empty = Delimiters{}; - @field(empty, @tagName(tag)) = true; - return empty; - } - - const TABLE: [256]Delimiters = brk: { - var table: [256]Delimiters = [_]Delimiters{.{}} ** 256; - table[';'] = getDelimiter(.semicolon); - table['!'] = getDelimiter(.bang); - table[','] = getDelimiter(.comma); - table['{'] = getDelimiter(.curly_bracket); - table['}'] = getDelimiter(.close_curly_bracket); - table[']'] = getDelimiter(.close_square_bracket); - table[')'] = getDelimiter(.close_parenthesis); - break :brk table; - }; - - // pub fn bitwiseOr(lhs: Delimiters, rhs: Delimiters) Delimiters { - // return @bitCast(@as(u8, @bitCast(lhs)) | @as(u8, @bitCast(rhs))); - // } - - // pub fn contains(lhs: Delimiters, rhs: Delimiters) bool { - // return @as(u8, @bitCast(lhs)) & @as(u8, @bitCast(rhs)) != 0; - // } - - pub fn fromByte(byte: ?u8) Delimiters { - if (byte) |b| return TABLE[b]; - return .{}; - } -}; - -pub const ParserInput = struct { - tokenizer: Tokenizer, - cached_token: ?CachedToken = null, - - pub fn new(allocator: Allocator, code: []const u8) ParserInput { - return ParserInput{ - .tokenizer = Tokenizer.init(allocator, code), - }; - } -}; - -/// A capture of the internal state of a `Parser` (including the position within the input), -/// obtained from the `Parser::position` method. -/// -/// Can be used with the `Parser::reset` method to restore that state. -/// Should only be used with the `Parser` instance it came from. -pub const ParserState = struct { - position: usize, - current_line_start_position: usize, - current_line_number: u32, - import_record_count: u32, - at_start_of: ?BlockType, - - pub fn sourceLocation(this: *const ParserState) SourceLocation { - return .{ - .line = this.current_line_number, - .column = @intCast(this.position - this.current_line_start_position + 1), - }; - } -}; - -const BlockType = enum { - parenthesis, - square_bracket, - curly_bracket, - - fn opening(token: *const Token) ?BlockType { - return switch (token.*) { - .function, .open_paren => .parenthesis, - .open_square => .square_bracket, - .open_curly => .curly_bracket, - else => null, - }; - } - - fn closing(token: *const Token) ?BlockType { - return switch (token.*) { - .close_paren => .parenthesis, - .close_square => .square_bracket, - .close_curly => .curly_bracket, - else => null, - }; - } -}; - -pub const nth = struct { - const NthResult = struct { i32, i32 }; - /// Parse the *An+B* notation, as found in the `:nth-child()` selector. - /// The input is typically the arguments of a function, - /// in which case the caller needs to check if the arguments’ parser is exhausted. - /// Return `Ok((A, B))`, or `Err(())` for a syntax error. - pub fn parse_nth(input: *Parser) Result(NthResult) { - const tok = switch (input.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .number => { - if (tok.number.int_value) |b| return .{ .result = .{ 0, b } }; - }, - .dimension => { - if (tok.dimension.num.int_value) |a| { - // @compileError(todo_stuff.match_ignore_ascii_case); - const unit = tok.dimension.unit; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "n")) { - return parse_b(input, a); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "n-")) { - return parse_signless_b(input, a, -1); - } else { - if (parse_n_dash_digits(input.allocator(), unit).asValue()) |b| { - return .{ .result = .{ a, b } }; - } else { - return .{ .err = input.newUnexpectedTokenError(.{ .ident = unit }) }; - } - } - } - }, - .ident => { - const value = tok.ident; - // @compileError(todo_stuff.match_ignore_ascii_case); - if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(value, "even")) { - return .{ .result = .{ 2, 0 } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(value, "odd")) { - return .{ .result = .{ 2, 1 } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(value, "n")) { - return parse_b(input, 1); - } else if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(value, "-n")) { - return parse_b(input, -1); - } else if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(value, "n-")) { - return parse_signless_b(input, 1, -1); - } else if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(value, "-n-")) { - return parse_signless_b(input, -1, -1); - } else { - const slice, const a: i32 = if (bun.strings.startsWithChar(value, '-')) .{ value[1..], -1 } else .{ value, 1 }; - if (parse_n_dash_digits(input.allocator(), slice).asValue()) |b| return .{ .result = .{ a, b } }; - return .{ .err = input.newUnexpectedTokenError(.{ .ident = value }) }; - } - }, - .delim => { - const next_tok = switch (input.nextIncludingWhitespace()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (next_tok.* == .ident) { - const value = next_tok.ident; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(value, "n")) { - return parse_b(input, 1); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(value, "-n")) { - return parse_signless_b(input, 1, -1); - } else { - if (parse_n_dash_digits(input.allocator(), value).asValue()) |b| { - return .{ .result = .{ 1, b } }; - } else { - return .{ .err = input.newUnexpectedTokenError(.{ .ident = value }) }; - } - } - } else { - return .{ .err = input.newUnexpectedTokenError(next_tok.*) }; - } - }, - else => {}, - } - return .{ .err = input.newUnexpectedTokenError(tok.*) }; - } - - fn parse_b(input: *Parser, a: i32) Result(NthResult) { - const start = input.state(); - const tok = switch (input.next()) { - .result => |v| v, - .err => { - input.reset(&start); - return .{ .result = .{ a, 0 } }; - }, - }; - - if (tok.* == .delim and tok.delim == '+') return parse_signless_b(input, a, 1); - if (tok.* == .delim and tok.delim == '-') return parse_signless_b(input, a, -1); - if (tok.* == .number and tok.number.has_sign and tok.number.int_value != null) return .{ .result = NthResult{ a, tok.number.int_value.? } }; - input.reset(&start); - return .{ .result = .{ a, 0 } }; - } - - fn parse_signless_b(input: *Parser, a: i32, b_sign: i32) Result(NthResult) { - const tok = switch (input.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (tok.* == .number and !tok.number.has_sign and tok.number.int_value != null) { - const b = tok.number.int_value.?; - return .{ .result = .{ a, b_sign * b } }; - } - return .{ .err = input.newUnexpectedTokenError(tok.*) }; - } - - fn parse_n_dash_digits(allocator: Allocator, str: []const u8) Maybe(i32, void) { - const bytes = str; - if (bytes.len >= 3 and - bun.strings.eqlCaseInsensitiveASCIIICheckLength(bytes[0..2], "n-") and - brk: { - for (bytes[2..]) |b| { - if (b < '0' or b > '9') break :brk false; - } - break :brk true; - }) - { - return parse_number_saturate(allocator, str[1..]); // Include the minus sign - } else { - return .{ .err = {} }; - } - } - - fn parse_number_saturate(allocator: Allocator, string: []const u8) Maybe(i32, void) { - var input = ParserInput.new(allocator, string); - var parser = Parser.new( - &input, - null, - .{}, - null, - ); - const tok = switch (parser.nextIncludingWhitespaceAndComments()) { - .result => |v| v, - .err => { - return .{ .err = {} }; - }, - }; - const int = if (tok.* == .number and tok.number.int_value != null) tok.number.int_value.? else { - return .{ .err = {} }; - }; - if (!parser.isExhausted()) { - return .{ .err = {} }; - } - return .{ .result = int }; - } -}; - -const CachedToken = struct { - token: Token, - start_position: usize, - end_state: ParserState, -}; - -const Tokenizer = struct { - src: []const u8, - position: usize = 0, - source_map_url: ?[]const u8 = null, - current_line_start_position: usize = 0, - current_line_number: u32 = 0, - allocator: Allocator, - var_or_env_functions: SeenStatus = .dont_care, - current: Token = undefined, - previous: Token = undefined, - - const SeenStatus = enum { - dont_care, - looking_for_them, - seen_at_least_one, - }; - - const FORM_FEED_BYTE = 0x0C; - const REPLACEMENT_CHAR = 0xFFFD; - const REPLACEMENT_CHAR_UNICODE: [3]u8 = [3]u8{ 0xEF, 0xBF, 0xBD }; - const MAX_ONE_B: u32 = 0x80; - const MAX_TWO_B: u32 = 0x800; - const MAX_THREE_B: u32 = 0x10000; - - pub fn init(allocator: Allocator, src: []const u8) Tokenizer { - var lexer = Tokenizer{ - .src = src, - .allocator = allocator, - .position = 0, - }; - - lexer.position = 0; - - return lexer; - } - - pub fn currentSourceMapUrl(this: *const Tokenizer) ?[]const u8 { - return this.source_map_url; - } - - pub fn getPosition(this: *const Tokenizer) usize { - bun.debugAssert(bun.strings.isOnCharBoundary(this.src, this.position)); - return this.position; - } - - pub fn state(this: *const Tokenizer) ParserState { - return ParserState{ - .position = this.position, - .current_line_start_position = this.current_line_start_position, - .current_line_number = this.current_line_number, - .at_start_of = null, - .import_record_count = 0, - }; - } - - pub fn skipWhitespace(this: *Tokenizer) void { - while (!this.isEof()) { - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - ' ', '\t' => this.advance(1), - '\n', 0x0C, '\r' => this.consumeNewline(), - '/' => { - if (this.startsWith("/*")) { - _ = this.consumeComment(); - } else return; - }, - else => return, - } - } - } - - pub fn currentSourceLocation(this: *const Tokenizer) SourceLocation { - return SourceLocation{ - .line = this.current_line_number, - .column = @intCast((this.position - this.current_line_start_position) + 1), - }; - } - - pub fn prev(this: *Tokenizer) Token { - bun.assert(this.position > 0); - return this.previous; - } - - pub inline fn isEof(this: *Tokenizer) bool { - return this.position >= this.src.len; - } - - pub fn seeFunction(this: *Tokenizer, name: []const u8) void { - if (this.var_or_env_functions == .looking_for_them) { - if (std.ascii.eqlIgnoreCase(name, "var") and std.ascii.eqlIgnoreCase(name, "env")) { - this.var_or_env_functions = .seen_at_least_one; - } - } - } - - /// TODO: fix this, remove the additional shit I added - /// return error if it is eof - pub inline fn next(this: *Tokenizer) Maybe(Token, void) { - return this.nextImpl(); - } - - pub fn nextImpl(this: *Tokenizer) Maybe(Token, void) { - if (this.isEof()) return .{ .err = {} }; - - // todo_stuff.match_byte; - const b = this.byteAt(0); - const token: Token = switch (b) { - ' ', '\t' => this.consumeWhitespace(false), - '\n', FORM_FEED_BYTE, '\r' => this.consumeWhitespace(true), - '"' => this.consumeString(false), - '#' => brk: { - this.advance(1); - if (this.isIdentStart()) break :brk .{ .idhash = this.consumeName() }; - if (!this.isEof() and switch (this.nextByteUnchecked()) { - // Any other valid case here already resulted in IDHash. - '0'...'9', '-' => true, - else => false, - }) break :brk .{ .unrestrictedhash = this.consumeName() }; - break :brk .{ .delim = '#' }; - }, - '$' => brk: { - if (this.startsWith("$=")) { - this.advance(2); - break :brk .suffix_match; - } - this.advance(1); - break :brk .{ .delim = '$' }; - }, - '\'' => this.consumeString(true), - '(' => brk: { - this.advance(1); - break :brk .open_paren; - }, - ')' => brk: { - this.advance(1); - break :brk .close_paren; - }, - '*' => brk: { - if (this.startsWith("*=")) { - this.advance(2); - break :brk .substring_match; - } - this.advance(1); - break :brk .{ .delim = '*' }; - }, - '+' => brk: { - if ((this.hasAtLeast(1) and switch (this.byteAt(1)) { - '0'...'9' => true, - else => false, - }) or (this.hasAtLeast(2) and - this.byteAt(1) == '.' and switch (this.byteAt(2)) { - '0'...'9' => true, - else => false, - })) { - break :brk this.consumeNumeric(); - } - - this.advance(1); - break :brk .{ .delim = '+' }; - }, - ',' => brk: { - this.advance(1); - break :brk .comma; - }, - '-' => brk: { - if ((this.hasAtLeast(1) and switch (this.byteAt(1)) { - '0'...'9' => true, - else => false, - }) or (this.hasAtLeast(2) and this.byteAt(1) == '.' and switch (this.byteAt(2)) { - '0'...'9' => true, - else => false, - })) break :brk this.consumeNumeric(); - - if (this.startsWith("-->")) { - this.advance(3); - break :brk .cdc; - } - - if (this.isIdentStart()) break :brk this.consumeIdentLike(); - - this.advance(1); - break :brk .{ .delim = '-' }; - }, - '.' => brk: { - if (this.hasAtLeast(1) and switch (this.byteAt(1)) { - '0'...'9' => true, - else => false, - }) { - break :brk this.consumeNumeric(); - } - this.advance(1); - break :brk .{ .delim = '.' }; - }, - '/' => brk: { - if (this.startsWith("/*")) break :brk .{ .comment = this.consumeComment() }; - this.advance(1); - break :brk .{ .delim = '/' }; - }, - '0'...'9' => this.consumeNumeric(), - ':' => brk: { - this.advance(1); - break :brk .colon; - }, - ';' => brk: { - this.advance(1); - break :brk .semicolon; - }, - '<' => brk: { - if (this.startsWith("")) this.advance(3) else return, - else => return, - } - } - } - - pub fn consumeNumeric(this: *Tokenizer) Token { - // Parse [+-]?\d*(\.\d+)?([eE][+-]?\d+)? - // But this is always called so that there is at least one digit in \d*(\.\d+)? - - // Do all the math in f64 so that large numbers overflow to +/-inf - // and i32::{MIN, MAX} are within range. - const has_sign: bool, const sign: f64 = brk: { - switch (this.nextByteUnchecked()) { - '-' => break :brk .{ true, -1.0 }, - '+' => break :brk .{ true, 1.0 }, - else => break :brk .{ false, 1.0 }, - } - }; - - if (has_sign) this.advance(1); - - var integral_part: f64 = 0.0; - while (byteToDecimalDigit(this.nextByteUnchecked())) |digit| { - integral_part = integral_part * 10.0 + @as(f64, @floatFromInt(digit)); - this.advance(1); - if (this.isEof()) break; - } - - var is_integer = true; - - var fractional_part: f64 = 0.0; - if (this.hasAtLeast(1) and this.nextByteUnchecked() == '.' and switch (this.byteAt(1)) { - '0'...'9' => true, - else => false, - }) { - is_integer = false; - this.advance(1); // Consume '.' - var factor: f64 = 0.1; - while (byteToDecimalDigit(this.nextByteUnchecked())) |digit| { - fractional_part += @as(f64, @floatFromInt(digit)) * factor; - factor *= 0.1; - this.advance(1); - if (this.isEof()) break; - } - } - - var value: f64 = sign * (integral_part + fractional_part); - - if (this.hasAtLeast(1) and switch (this.nextByteUnchecked()) { - 'e', 'E' => true, - else => false, - }) { - if (switch (this.byteAt(1)) { - '0'...'9' => true, - else => false, - } or (this.hasAtLeast(2) and switch (this.byteAt(1)) { - '+', '-' => true, - else => false, - } and switch (this.byteAt(2)) { - '0'...'9' => true, - else => false, - })) { - is_integer = false; - this.advance(1); - const has_sign2: bool, const sign2: f64 = brk: { - switch (this.nextByteUnchecked()) { - '-' => break :brk .{ true, -1.0 }, - '+' => break :brk .{ true, 1.0 }, - else => break :brk .{ false, 1.0 }, - } - }; - - if (has_sign2) this.advance(1); - - var exponent: f64 = 0.0; - while (byteToDecimalDigit(this.nextByteUnchecked())) |digit| { - exponent = exponent * 10.0 + @as(f64, @floatFromInt(digit)); - this.advance(1); - if (this.isEof()) break; - } - value *= bun.pow(10, sign2 * exponent); - } - } - - const int_value: ?i32 = if (is_integer) - bun.intFromFloat(i32, value) - else - null; - - if (!this.isEof() and this.nextByteUnchecked() == '%') { - this.advance(1); - return .{ .percentage = .{ .unit_value = @floatCast(value / 100), .int_value = int_value, .has_sign = has_sign } }; - } - - if (this.isIdentStart()) { - const unit = this.consumeName(); - return .{ - .dimension = .{ - .num = .{ .value = @floatCast(value), .int_value = int_value, .has_sign = has_sign }, - .unit = unit, - }, - }; - } - - return .{ - .number = .{ .value = @floatCast(value), .int_value = int_value, .has_sign = has_sign }, - }; - } - - pub fn consumeWhitespace(this: *Tokenizer, comptime newline: bool) Token { - const start_position = this.position; - if (newline) { - this.consumeNewline(); - } else { - this.advance(1); - } - - while (!this.isEof()) { - // todo_stuff.match_byte - const b = this.nextByteUnchecked(); - switch (b) { - ' ', '\t' => this.advance(1), - '\n', FORM_FEED_BYTE, '\r' => this.consumeNewline(), - else => break, - } - } - - return .{ .whitespace = this.sliceFrom(start_position) }; - } - - pub fn consumeString(this: *Tokenizer, comptime single_quote: bool) Token { - const quoted_string = this.consumeQuotedString(single_quote); - if (quoted_string.bad) return .{ .bad_string = quoted_string.str }; - return .{ .quoted_string = quoted_string.str }; - } - - pub fn consumeIdentLike(this: *Tokenizer) Token { - const value = this.consumeName(); - if (!this.isEof() and this.nextByteUnchecked() == '(') { - this.advance(1); - if (std.ascii.eqlIgnoreCase(value, "url")) return if (this.consumeUnquotedUrl()) |tok| return tok else .{ .function = value }; - this.seeFunction(value); - return .{ .function = value }; - } - return .{ .ident = value }; - } - - pub fn consumeName(this: *Tokenizer) []const u8 { - const start_pos = this.position; - var value_bytes: CopyOnWriteStr = undefined; - - while (true) { - if (this.isEof()) return this.sliceFrom(start_pos); - - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - 'a'...'z', 'A'...'Z', '0'...'9', '_', '-' => this.advance(1), - '\\', 0 => { - // * The tokenizer’s input is UTF-8 since it’s `&str`. - // * start_pos is at a code point boundary - // * so is the current position (which is before '\\' or '\0' - // - // So `value_bytes` is well-formed UTF-8. - value_bytes = .{ .borrowed = this.sliceFrom(start_pos) }; - break; - }, - 0x80...0xBF => this.consumeContinuationByte(), - // This is the range of the leading byte of a 2-3 byte character - // encoding - 0xC0...0xEF => this.advance(1), - 0xF0...0xFF => this.consume4byteIntro(), - else => return this.sliceFrom(start_pos), - } - } - - while (!this.isEof()) { - const b = this.nextByteUnchecked(); - // todo_stuff.match_byte - switch (b) { - 'a'...'z', 'A'...'Z', '0'...'9', '_', '-' => { - this.advance(1); - value_bytes.append(this.allocator, &[_]u8{b}); - }, - '\\' => { - if (this.hasNewlineAt(1)) break; - this.advance(1); - this.consumeEscapeAndWrite(&value_bytes); - }, - 0 => { - this.advance(1); - value_bytes.append(this.allocator, REPLACEMENT_CHAR_UNICODE[0..]); - }, - 0x80...0xBF => { - // This byte *is* part of a multi-byte code point, - // we’ll end up copying the whole code point before this loop does something else. - this.consumeContinuationByte(); - value_bytes.append(this.allocator, &[_]u8{b}); - }, - 0xC0...0xEF => { - // This byte *is* part of a multi-byte code point, - // we’ll end up copying the whole code point before this loop does something else. - this.advance(1); - value_bytes.append(this.allocator, &[_]u8{b}); - }, - 0xF0...0xFF => { - this.consume4byteIntro(); - value_bytes.append(this.allocator, &[_]u8{b}); - }, - else => { - // ASCII - break; - }, - } - } - - return value_bytes.toSlice(); - } - - pub fn consumeQuotedString(this: *Tokenizer, comptime single_quote: bool) struct { str: []const u8, bad: bool = false } { - this.advance(1); // Skip the initial quote - const start_pos = this.position; - var string_bytes: CopyOnWriteStr = undefined; - - while (true) { - if (this.isEof()) return .{ .str = this.sliceFrom(start_pos) }; - - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - '"' => { - if (!single_quote) { - const value = this.sliceFrom(start_pos); - this.advance(1); - return .{ .str = value }; - } - this.advance(1); - }, - '\'' => { - if (single_quote) { - const value = this.sliceFrom(start_pos); - this.advance(1); - return .{ .str = value }; - } - this.advance(1); - }, - // The CSS spec says NULL bytes ('\0') should be turned into replacement characters: 0xFFFD - '\\', 0 => { - // * The tokenizer’s input is UTF-8 since it’s `&str`. - // * start_pos is at a code point boundary - // * so is the current position (which is before '\\' or '\0' - // - // So `string_bytes` is well-formed UTF-8. - string_bytes = .{ .borrowed = this.sliceFrom(start_pos) }; - break; - }, - '\n', '\r', FORM_FEED_BYTE => return .{ .str = this.sliceFrom(start_pos), .bad = true }, - 0x80...0xBF => this.consumeContinuationByte(), - 0xF0...0xFF => this.consume4byteIntro(), - else => { - this.advance(1); - }, - } - } - - while (!this.isEof()) { - const b = this.nextByteUnchecked(); - // todo_stuff.match_byte - switch (b) { - // string_bytes is well-formed UTF-8, see other comments - '\n', '\r', FORM_FEED_BYTE => return .{ .str = string_bytes.toSlice(), .bad = true }, - '"' => { - this.advance(1); - if (!single_quote) break; - }, - '\'' => { - this.advance(1); - if (single_quote) break; - }, - '\\' => { - this.advance(1); - if (!this.isEof()) { - switch (this.nextByteUnchecked()) { - // Escaped newline - '\n', FORM_FEED_BYTE, '\r' => this.consumeNewline(), - else => this.consumeEscapeAndWrite(&string_bytes), - } - } - // else: escaped EOF, do nothing. - continue; - }, - 0 => { - this.advance(1); - string_bytes.append(this.allocator, REPLACEMENT_CHAR_UNICODE[0..]); - continue; - }, - 0x80...0xBF => this.consumeContinuationByte(), - 0xF0...0xFF => this.consume4byteIntro(), - else => { - this.advance(1); - }, - } - - string_bytes.append(this.allocator, &[_]u8{b}); - } - - return .{ .str = string_bytes.toSlice() }; - } - - pub fn consumeUnquotedUrl(this: *Tokenizer) ?Token { - // This is only called after "url(", so the current position is a code point boundary. - const start_position = this.position; - const from_start = this.src[this.position..]; - var newlines: u32 = 0; - var last_newline: usize = 0; - var found_printable_char = false; - - var offset: usize = 0; - var b: u8 = undefined; - while (true) { - defer offset += 1; - - if (offset < from_start.len) { - b = from_start[offset]; - } else { - this.position = this.src.len; - break; - } - - // todo_stuff.match_byte - switch (b) { - ' ', '\t' => {}, - '\n', FORM_FEED_BYTE => { - newlines += 1; - last_newline = offset; - }, - '\r' => { - if (offset + 1 < from_start.len and from_start[offset + 1] != '\n') { - newlines += 1; - last_newline = offset; - } - }, - '"', '\'' => return null, // Do not advance - ')' => { - // Don't use advance, because we may be skipping - // newlines here, and we want to avoid the assert. - this.position += offset + 1; - break; - }, - else => { - // Don't use advance, because we may be skipping - // newlines here, and we want to avoid the assert. - this.position += offset; - found_printable_char = true; - break; - }, - } - } - - if (newlines > 0) { - this.current_line_number += newlines; - // No need for wrapping_add here, because there's no possible - // way to wrap. - this.current_line_start_position = start_position + last_newline + 1; - } - - if (found_printable_char) { - // This function only consumed ASCII (whitespace) bytes, - // so the current position is a code point boundary. - return this.consumeUnquotedUrlInternal(); - } - return .{ .unquoted_url = "" }; - } - - pub fn consumeUnquotedUrlInternal(this: *Tokenizer) Token { - // This function is only called with start_pos at a code point boundary.; - const start_pos = this.position; - var string_bytes: CopyOnWriteStr = undefined; - - while (true) { - if (this.isEof()) return .{ .unquoted_url = this.sliceFrom(start_pos) }; - - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - ' ', '\t', '\n', '\r', FORM_FEED_BYTE => { - var value: CopyOnWriteStr = .{ .borrowed = this.sliceFrom(start_pos) }; - return this.consumeUrlEnd(start_pos, &value); - }, - ')' => { - const value = this.sliceFrom(start_pos); - this.advance(1); - return .{ .unquoted_url = value }; - }, - // non-printable - 0x01...0x08, - 0x0B, - 0x0E...0x1F, - 0x7F, - - // not valid in this context - '"', - '\'', - '(', - => { - this.advance(1); - return this.consumeBadUrl(start_pos); - }, - '\\', 0 => { - // * The tokenizer’s input is UTF-8 since it’s `&str`. - // * start_pos is at a code point boundary - // * so is the current position (which is before '\\' or '\0' - // - // So `string_bytes` is well-formed UTF-8. - string_bytes = .{ .borrowed = this.sliceFrom(start_pos) }; - break; - }, - 0x80...0xBF => this.consumeContinuationByte(), - 0xF0...0xFF => this.consume4byteIntro(), - else => { - // ASCII or other leading byte. - this.advance(1); - }, - } - } - - while (!this.isEof()) { - const b = this.nextByteUnchecked(); - // todo_stuff.match_byte - switch (b) { - ' ', '\t', '\n', '\r', FORM_FEED_BYTE => { - // string_bytes is well-formed UTF-8, see other comments. - // const string = string_bytes.toSlice(); - // return this.consumeUrlEnd(start_pos, &string); - return this.consumeUrlEnd(start_pos, &string_bytes); - }, - ')' => { - this.advance(1); - break; - }, - // non-printable - 0x01...0x08, - 0x0B, - 0x0E...0x1F, - 0x7F, - - // invalid in this context - '"', - '\'', - '(', - => { - this.advance(1); - return this.consumeBadUrl(start_pos); - }, - '\\' => { - this.advance(1); - if (this.hasNewlineAt(0)) return this.consumeBadUrl(start_pos); - - // This pushes one well-formed code point to string_bytes - this.consumeEscapeAndWrite(&string_bytes); - }, - 0 => { - this.advance(1); - string_bytes.append(this.allocator, REPLACEMENT_CHAR_UNICODE[0..]); - }, - 0x80...0xBF => { - // We’ll end up copying the whole code point - // before this loop does something else. - this.consumeContinuationByte(); - string_bytes.append(this.allocator, &[_]u8{b}); - }, - 0xF0...0xFF => { - // We’ll end up copying the whole code point - // before this loop does something else. - this.consume4byteIntro(); - string_bytes.append(this.allocator, &[_]u8{b}); - }, - // If this byte is part of a multi-byte code point, - // we’ll end up copying the whole code point before this loop does something else. - else => { - // ASCII or other leading byte. - this.advance(1); - string_bytes.append(this.allocator, &[_]u8{b}); - }, - } - } - - // string_bytes is well-formed UTF-8, see other comments. - return .{ .unquoted_url = string_bytes.toSlice() }; - } - - pub fn consumeUrlEnd(this: *Tokenizer, start_pos: usize, string: *CopyOnWriteStr) Token { - while (!this.isEof()) { - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - ')' => { - this.advance(1); - break; - }, - ' ', '\t' => this.advance(1), - '\n', FORM_FEED_BYTE, '\r' => this.consumeNewline(), - else => |b| { - this.consumeKnownByte(b); - return this.consumeBadUrl(start_pos); - }, - } - } - - return .{ .unquoted_url = string.toSlice() }; - } - - pub fn consumeBadUrl(this: *Tokenizer, start_pos: usize) Token { - // Consume up to the closing ) - while (!this.isEof()) { - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - ')' => { - const contents = this.sliceFrom(start_pos); - this.advance(1); - return .{ .bad_url = contents }; - }, - '\\' => { - this.advance(1); - if (this.nextByte()) |b| { - if (b == ')' or b == '\\') this.advance(1); // Skip an escaped ')' or '\' - } - }, - '\n', FORM_FEED_BYTE, '\r' => this.consumeNewline(), - else => |b| this.consumeKnownByte(b), - } - } - return .{ .bad_url = this.sliceFrom(start_pos) }; - } - - pub fn consumeEscapeAndWrite(this: *Tokenizer, bytes: *CopyOnWriteStr) void { - const val = this.consumeEscape(); - var utf8bytes: [4]u8 = undefined; - const len = std.unicode.utf8Encode(@truncate(val), utf8bytes[0..]) catch @panic("Invalid"); - bytes.append(this.allocator, utf8bytes[0..len]); - } - - pub fn consumeEscape(this: *Tokenizer) u32 { - if (this.isEof()) return 0xFFFD; // Unicode replacement character - - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - '0'...'9', 'A'...'F', 'a'...'f' => { - const c = this.consumeHexDigits().value; - if (!this.isEof()) { - // todo_stuff.match_byte - switch (this.nextByteUnchecked()) { - ' ', '\t' => this.advance(1), - '\n', FORM_FEED_BYTE, '\r' => this.consumeNewline(), - else => {}, - } - } - - if (c != 0 and std.unicode.utf8ValidCodepoint(@truncate(c))) return c; - return REPLACEMENT_CHAR; - }, - 0 => { - this.advance(1); - return REPLACEMENT_CHAR; - }, - else => return this.consumeChar(), - } - } - - pub fn consumeHexDigits(this: *Tokenizer) struct { value: u32, num_digits: u32 } { - var value: u32 = 0; - var digits: u32 = 0; - while (digits < 6 and !this.isEof()) { - if (byteToHexDigit(this.nextByteUnchecked())) |digit| { - value = value * 16 + digit; - digits += 1; - this.advance(1); - } else break; - } - - return .{ .value = value, .num_digits = digits }; - } - - pub fn consumeChar(this: *Tokenizer) u32 { - const c = this.nextChar(); - const len_utf8 = lenUtf8(c); - this.position += len_utf8; - // Note that due to the special case for the 4-byte sequence - // intro, we must use wrapping add here. - this.current_line_start_position +%= len_utf8 - lenUtf16(c); - return c; - } - - fn lenUtf8(code: u32) usize { - if (code < MAX_ONE_B) { - return 1; - } else if (code < MAX_TWO_B) { - return 2; - } else if (code < MAX_THREE_B) { - return 3; - } else { - return 4; - } - } - - fn lenUtf16(ch: u32) usize { - if ((ch & 0xFFFF) == ch) { - return 1; - } else { - return 2; - } - } - - fn byteToHexDigit(b: u8) ?u32 { - - // todo_stuff.match_byte - return switch (b) { - '0'...'9' => b - '0', - 'a'...'f' => b - 'a' + 10, - 'A'...'F' => b - 'A' + 10, - else => null, - }; - } - - fn byteToDecimalDigit(b: u8) ?u32 { - if (b >= '0' and b <= '9') { - return b - '0'; - } - return null; - } - - pub fn consumeComment(this: *Tokenizer) []const u8 { - this.advance(2); - const start_position = this.position; - while (!this.isEof()) { - const b = this.nextByteUnchecked(); - // todo_stuff.match_byte - switch (b) { - '*' => { - const end_position = this.position; - this.advance(1); - if (this.nextByte() == '/') { - this.advance(1); - const contents = this.src[start_position..end_position]; - this.checkForSourceMap(contents); - return contents; - } - }, - '\n', FORM_FEED_BYTE, '\r' => { - this.consumeNewline(); - }, - 0x80...0xBF => this.consumeContinuationByte(), - 0xF0...0xFF => this.consume4byteIntro(), - else => { - // ASCII or other leading byte - this.advance(1); - }, - } - } - const contents = this.sliceFrom(start_position); - this.checkForSourceMap(contents); - return contents; - } - - pub fn checkForSourceMap(this: *Tokenizer, contents: []const u8) void { - { - const directive = "# sourceMappingURL="; - const directive_old = "@ sourceMappingURL="; - if (std.mem.startsWith(u8, contents, directive) or std.mem.startsWith(u8, contents, directive_old)) { - this.source_map_url = splitSourceMap(contents[directive.len..]); - } - } - - { - const directive = "# sourceURL="; - const directive_old = "@ sourceURL="; - if (std.mem.startsWith(u8, contents, directive) or std.mem.startsWith(u8, contents, directive_old)) { - this.source_map_url = splitSourceMap(contents[directive.len..]); - } - } - } - - pub fn splitSourceMap(contents: []const u8) ?[]const u8 { - // FIXME: Use bun CodepointIterator - var iter = std.unicode.Utf8Iterator{ .bytes = contents, .i = 0 }; - while (iter.nextCodepoint()) |c| { - switch (c) { - ' ', '\t', FORM_FEED_BYTE, '\r', '\n' => { - const start = 0; - const end = iter.i; - return contents[start..end]; - }, - else => {}, - } - } - return null; - } - - pub fn consumeNewline(this: *Tokenizer) void { - const byte = this.nextByteUnchecked(); - if (bun.Environment.allow_assert) { - std.debug.assert(byte == '\r' or byte == '\n' or byte == FORM_FEED_BYTE); - } - this.position += 1; - if (byte == '\r' and this.nextByte() == '\n') { - this.position += 1; - } - this.current_line_start_position = this.position; - this.current_line_number += 1; - } - - /// Advance over a single byte; the byte must be a UTF-8 - /// continuation byte. - /// - /// Binary Hex Comments - /// 0xxxxxxx 0x00..0x7F Only byte of a 1-byte character encoding - /// 110xxxxx 0xC0..0xDF First byte of a 2-byte character encoding - /// 1110xxxx 0xE0..0xEF First byte of a 3-byte character encoding - /// 11110xxx 0xF0..0xF7 First byte of a 4-byte character encoding - /// 10xxxxxx 0x80..0xBF Continuation byte: one of 1-3 bytes following the first <-- - pub fn consumeContinuationByte(this: *Tokenizer) void { - if (bun.Environment.allow_assert) std.debug.assert(this.nextByteUnchecked() & 0xC0 == 0x80); - // Continuation bytes contribute to column overcount. Note - // that due to the special case for the 4-byte sequence intro, - // we must use wrapping add here. - this.current_line_start_position +%= 1; - this.position += 1; - } - - /// Advance over a single byte; the byte must be a UTF-8 sequence - /// leader for a 4-byte sequence. - /// - /// Binary Hex Comments - /// 0xxxxxxx 0x00..0x7F Only byte of a 1-byte character encoding - /// 110xxxxx 0xC0..0xDF First byte of a 2-byte character encoding - /// 1110xxxx 0xE0..0xEF First byte of a 3-byte character encoding - /// 11110xxx 0xF0..0xF7 First byte of a 4-byte character encoding <-- - /// 10xxxxxx 0x80..0xBF Continuation byte: one of 1-3 bytes following the first - pub fn consume4byteIntro(this: *Tokenizer) void { - if (bun.Environment.allow_assert) std.debug.assert(this.nextByteUnchecked() & 0xF0 == 0xF0); - // This takes two UTF-16 characters to represent, so we - // actually have an undercount. - // this.current_line_start_position = self.current_line_start_position.wrapping_sub(1); - this.current_line_start_position -%= 1; - this.position += 1; - } - - pub fn isIdentStart(this: *Tokenizer) bool { - - // todo_stuff.match_byte - return !this.isEof() and switch (this.nextByteUnchecked()) { - 'a'...'z', 'A'...'Z', '_', 0 => true, - - // todo_stuff.match_byte - '-' => this.hasAtLeast(1) and switch (this.byteAt(1)) { - 'a'...'z', 'A'...'Z', '-', '_', 0 => true, - '\\' => !this.hasNewlineAt(1), - else => |b| !std.ascii.isAscii(b), - }, - '\\' => !this.hasNewlineAt(1), - else => |b| !std.ascii.isAscii(b), - }; - } - - /// If true, the input has at least `n` bytes left *after* the current one. - /// That is, `tokenizer.char_at(n)` will not panic. - fn hasAtLeast(this: *Tokenizer, n: usize) bool { - return this.position + n < this.src.len; - } - - fn hasNewlineAt(this: *Tokenizer, offset: usize) bool { - return this.position + offset < this.src.len and switch (this.byteAt(offset)) { - '\n', '\r', FORM_FEED_BYTE => true, - else => false, - }; - } - - pub fn startsWith(this: *Tokenizer, comptime needle: []const u8) bool { - return bun.strings.hasPrefixComptime(this.src[this.position..], needle); - } - - /// Advance over N bytes in the input. This function can advance - /// over ASCII bytes (excluding newlines), or UTF-8 sequence - /// leaders (excluding leaders for 4-byte sequences). - pub fn advance(this: *Tokenizer, n: usize) void { - if (bun.Environment.allow_assert) { - // Each byte must either be an ASCII byte or a sequence - // leader, but not a 4-byte leader; also newlines are - // rejected. - for (0..n) |i| { - const b = this.byteAt(i); - std.debug.assert(std.ascii.isAscii(b) or (b & 0xF0 != 0xF0 and b & 0xC0 != 0x80)); - std.debug.assert(b != '\r' and b != '\n' and b != '\x0C'); - } - } - this.position += n; - } - - /// Advance over any kind of byte, excluding newlines. - pub fn consumeKnownByte(this: *Tokenizer, byte: u8) void { - if (bun.Environment.allow_assert) std.debug.assert(byte != '\r' and byte != '\n' and byte != FORM_FEED_BYTE); - this.position += 1; - // Continuation bytes contribute to column overcount. - if (byte & 0xF0 == 0xF0) { - // This takes two UTF-16 characters to represent, so we - // actually have an undercount. - this.current_line_start_position -%= 1; - } else if (byte & 0xC0 == 0x80) { - // Note that due to the special case for the 4-byte - // sequence intro, we must use wrapping add here. - this.current_line_start_position +%= 1; - } - } - - pub inline fn byteAt(this: *Tokenizer, n: usize) u8 { - return this.src[this.position + n]; - } - - pub inline fn nextByte(this: *Tokenizer) ?u8 { - if (this.isEof()) return null; - return this.src[this.position]; - } - - pub inline fn nextChar(this: *Tokenizer) u32 { - const len = bun.strings.utf8ByteSequenceLength(this.src[this.position]); - return bun.strings.decodeWTF8RuneT(this.src[this.position..].ptr[0..4], len, u32, bun.strings.unicode_replacement); - } - - pub inline fn nextByteUnchecked(this: *Tokenizer) u8 { - return this.src[this.position]; - } - - pub inline fn sliceFrom(this: *Tokenizer, start: usize) []const u8 { - return this.src[start..this.position]; - } -}; - -const TokenKind = enum { - /// An [](https://drafts.csswg.org/css-syntax/#typedef-ident-token) - ident, - - /// Value is the ident - function, - - /// Value is the ident - at_keyword, - - /// A [``](https://drafts.csswg.org/css-syntax/#hash-token-diagram) with the type flag set to "unrestricted" - /// - /// The value does not include the `#` marker. - unrestrictedhash, - - /// A [``](https://drafts.csswg.org/css-syntax/#hash-token-diagram) with the type flag set to "id" - /// - /// The value does not include the `#` marker. - idhash, - - quoted_string, - - bad_string, - - /// `url()` is represented by a `.function` token - unquoted_url, - - bad_url, - - /// Value of a single codepoint - delim, - - /// A can be fractional or an integer, and can contain an optional + or - sign - number, - - percentage, - - dimension, - - whitespace, - - /// `` - cdc, - - /// `~=` (https://www.w3.org/TR/selectors-4/#attribute-representation) - include_match, - - /// `|=` (https://www.w3.org/TR/selectors-4/#attribute-representation) - dash_match, - - /// `^=` (https://www.w3.org/TR/selectors-4/#attribute-substrings) - prefix_match, - - /// `$=`(https://www.w3.org/TR/selectors-4/#attribute-substrings) - suffix_match, - - /// `*=` (https://www.w3.org/TR/selectors-4/#attribute-substrings) - substring_match, - - colon, - semicolon, - comma, - open_square, - close_square, - open_paren, - close_paren, - open_curly, - close_curly, - - /// Not an actual token in the spec, but we keep it anyway - comment, - - pub fn toString(this: TokenKind) []const u8 { - return switch (this) { - .at_keyword => "@-keyword", - .bad_string => "bad string token", - .bad_url => "bad URL token", - .cdc => "\"-->\"", - .cdo => "\"` - cdc, - - /// `~=` (https://www.w3.org/TR/selectors-4/#attribute-representation) - include_match, - - /// `|=` (https://www.w3.org/TR/selectors-4/#attribute-representation) - dash_match, - - /// `^=` (https://www.w3.org/TR/selectors-4/#attribute-substrings) - prefix_match, - - /// `$=`(https://www.w3.org/TR/selectors-4/#attribute-substrings) - suffix_match, - - /// `*=` (https://www.w3.org/TR/selectors-4/#attribute-substrings) - substring_match, - - colon, - semicolon, - comma, - open_square, - close_square, - open_paren, - close_paren, - open_curly, - close_curly, - - /// Not an actual token in the spec, but we keep it anyway - comment: []const u8, - - pub fn eql(lhs: *const Token, rhs: *const Token) bool { - return implementEql(Token, lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return implementHash(@This(), this, hasher); - } - - /// Return whether this token represents a parse error. - /// - /// `BadUrl` and `BadString` are tokenizer-level parse errors. - /// - /// `CloseParenthesis`, `CloseSquareBracket`, and `CloseCurlyBracket` are *unmatched* - /// and therefore parse errors when returned by one of the `Parser::next*` methods. - pub fn isParseError(this: *const Token) bool { - return switch (this.*) { - .bad_url, .bad_string, .close_paren, .close_square, .close_curly => true, - else => false, - }; - } - - pub fn format( - this: *const Token, - writer: *std.Io.Writer, - ) !void { - return switch (this.*) { - .ident => |value| try serializer.serializeIdentifier(value, writer), - .at_keyword => |value| { - try writer.writeByte('@'); - try serializer.serializeIdentifier(value, writer); - }, - .unrestrictedhash => |value| { - try writer.writeByte('#'); - try serializer.serializeName(value, writer); - }, - .idhash => |value| { - try writer.writeByte('#'); - try serializer.serializeIdentifier(value, writer); - }, - .quoted_string => |value| try serializer.serializeString(value, writer), - .unquoted_url => |value| { - try writer.writeAll("url("); - try serializer.serializeUnquotedUrl(value, writer); - try writer.writeByte(')'); - }, - .delim => |value| { - // See comment for this variant in declaration of Token - // The value of delim is only ever ascii - bun.debugAssert(value <= 0x7F); - try writer.writeByte(@truncate(value)); - }, - .number => |num| try serializer.writeNumeric(num.value, num.int_value, num.has_sign, writer), - .percentage => |num| { - try serializer.writeNumeric(num.unit_value * 100, num.int_value, num.has_sign, writer); - try writer.writeAll("%"); - }, - .dimension => |dim| { - try serializer.writeNumeric(dim.num.value, dim.num.int_value, dim.num.has_sign, writer); - // Disambiguate with scientific notation. - const unit = dim.unit; - if (std.mem.eql(u8, unit, "e") or std.mem.eql(u8, unit, "E") or - std.mem.startsWith(u8, unit, "e-") or std.mem.startsWith(u8, unit, "E-")) - { - try writer.writeAll("\\65 "); - try serializer.serializeName(unit[1..], writer); - } else { - try serializer.serializeIdentifier(unit, writer); - } - }, - .whitespace => |content| try writer.writeAll(content), - .comment => |content| { - try writer.writeAll("/*"); - try writer.writeAll(content); - try writer.writeAll("*/"); - }, - .colon => try writer.writeByte(':'), - .semicolon => try writer.writeByte(';'), - .comma => try writer.writeByte(','), - .include_match => try writer.writeAll("~="), - .dash_match => try writer.writeAll("|="), - .prefix_match => try writer.writeAll("^="), - .suffix_match => try writer.writeAll("$="), - .substring_match => try writer.writeAll("*="), - .cdo => try writer.writeAll(""), - .function => |name| { - try serializer.serializeIdentifier(name, writer); - try writer.writeByte('('); - }, - .open_paren => try writer.writeAll("("), - .open_square => try writer.writeAll("["), - .open_curly => try writer.writeAll("{"), - .bad_url => |contents| { - try writer.writeAll("url("); - try writer.writeAll(contents); - try writer.writeByte(')'); - }, - .bad_string => |value| { - try writer.writeByte('"'); - var string_writer = serializer.CssStringWriter(@TypeOf(writer)).new(writer); - try string_writer.writeStr(value); - }, - .close_paren => try writer.writeAll(")"), - .close_square => try writer.writeAll("]"), - .close_curly => try writer.writeAll("}"), - }; - } - - pub fn raw(this: Token) []const u8 { - return switch (this) { - .ident => this.ident, - // .function => - }; - } - - pub inline fn kind(this: Token) TokenKind { - return @as(TokenKind, this); - } - - pub inline fn kindString(this: Token) []const u8 { - return this.kind.toString(); - } - - // ~toCssImpl - const This = @This(); - - pub fn toCssGeneric(this: *const This, writer: anytype) !void { - return switch (this.*) { - .ident => { - try serializer.serializeIdentifier(this.ident, writer); - }, - .at_keyword => { - try writer.writeAll("@"); - try serializer.serializeIdentifier(this.at_keyword, writer); - }, - .unrestrictedhash, .idhash => |v| { - try writer.writeAll("#"); - try serializer.serializeName(v, writer); - }, - .quoted_string => |x| { - try serializer.serializeName(x, writer); - }, - .unquoted_url => |x| { - try writer.writeAll("url("); - try serializer.serializeUnquotedUrl(x, writer); - try writer.writeAll(")"); - }, - .delim => |x| { - bun.assert(x <= 0x7F); - try writer.writeByte(@intCast(x)); - }, - .number => |n| { - try serializer.writeNumeric(n.value, n.int_value, n.has_sign, writer); - }, - .percentage => |p| { - try serializer.writeNumeric(p.unit_value * 100.0, p.int_value, p.has_sign, writer); - }, - .dimension => |d| { - try serializer.writeNumeric(d.num.value, d.num.int_value, d.num.has_sign, writer); - // Disambiguate with scientific notation. - const unit = d.unit; - // TODO(emilio): This doesn't handle e.g. 100E1m, which gets us - // an unit of "E1m"... - if ((unit.len == 1 and unit[0] == 'e') or - (unit.len == 1 and unit[0] == 'E') or - bun.strings.startsWith(unit, "e-") or - bun.strings.startsWith(unit, "E-")) - { - try writer.writeAll("\\65 "); - try serializer.serializeName(unit[1..], writer); - } else { - try serializer.serializeIdentifier(unit, writer); - } - }, - .whitespace => |content| { - try writer.writeAll(content); - }, - .comment => |content| { - try writer.writeAll("/*"); - try writer.writeAll(content); - try writer.writeAll("*/"); - }, - .colon => try writer.writeAll(":"), - .semicolon => try writer.writeAll(";"), - .comma => try writer.writeAll(","), - .include_match => try writer.writeAll("~="), - .dash_match => try writer.writeAll("|="), - .prefix_match => try writer.writeAll("^="), - .suffix_match => try writer.writeAll("$="), - .substring_match => try writer.writeAll("*="), - .cdo => try writer.writeAll(""), - - .function => |name| { - try serializer.serializeIdentifier(name, writer); - try writer.writeAll("("); - }, - .open_paren => try writer.writeAll("("), - .open_square => try writer.writeAll("["), - .open_curly => try writer.writeAll("{"), - - .bad_url => |contents| { - try writer.writeAll("url("); - try writer.writeAll(contents); - try writer.writeByte(')'); - }, - .bad_string => |value| { - // During tokenization, an unescaped newline after a quote causes - // the token to be a BadString instead of a QuotedString. - // The BadString token ends just before the newline - // (which is in a separate WhiteSpace token), - // and therefore does not have a closing quote. - try writer.writeByte('"'); - var string_writer = serializer.CssStringWriter(@TypeOf(writer)).new(writer); - try string_writer.writeStr(value); - }, - .close_paren => try writer.writeAll(")"), - .close_square => try writer.writeAll("]"), - .close_curly => try writer.writeAll("}"), - }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - return switch (this.*) { - .ident => |value| serializer.serializeIdentifier(value, dest) catch return dest.addFmtError(), - .at_keyword => |value| { - try dest.writeStr("@"); - return serializer.serializeIdentifier(value, dest) catch return dest.addFmtError(); - }, - .unrestrictedhash => |value| { - try dest.writeStr("#"); - return serializer.serializeName(value, dest) catch return dest.addFmtError(); - }, - .idhash => |value| { - try dest.writeStr("#"); - return serializer.serializeIdentifier(value, dest) catch return dest.addFmtError(); - }, - .quoted_string => |value| serializer.serializeString(value, dest) catch return dest.addFmtError(), - .unquoted_url => |value| { - try dest.writeStr("url("); - serializer.serializeUnquotedUrl(value, dest) catch return dest.addFmtError(); - return dest.writeStr(")"); - }, - .delim => |value| { - // See comment for this variant in declaration of Token - // The value of delim is only ever ascii - bun.debugAssert(value <= 0x7F); - return dest.writeChar(@truncate(value)); - }, - .number => |num| serializer.writeNumeric(num.value, num.int_value, num.has_sign, dest) catch return dest.addFmtError(), - .percentage => |num| { - serializer.writeNumeric(num.unit_value * 100, num.int_value, num.has_sign, dest) catch return dest.addFmtError(); - return dest.writeStr("%"); - }, - .dimension => |dim| { - serializer.writeNumeric(dim.num.value, dim.num.int_value, dim.num.has_sign, dest) catch return dest.addFmtError(); - // Disambiguate with scientific notation. - const unit = dim.unit; - if (std.mem.eql(u8, unit, "e") or std.mem.eql(u8, unit, "E") or - std.mem.startsWith(u8, unit, "e-") or std.mem.startsWith(u8, unit, "E-")) - { - try dest.writeStr("\\65 "); - serializer.serializeName(unit[1..], dest) catch return dest.addFmtError(); - } else { - serializer.serializeIdentifier(unit, dest) catch return dest.addFmtError(); - } - return; - }, - .whitespace => |content| dest.writeStr(content), - .comment => |content| { - try dest.writeStr("/*"); - try dest.writeStr(content); - return dest.writeStr("*/"); - }, - .colon => dest.writeStr(":"), - .semicolon => dest.writeStr(";"), - .comma => dest.writeStr(","), - .include_match => dest.writeStr("~="), - .dash_match => dest.writeStr("|="), - .prefix_match => dest.writeStr("^="), - .suffix_match => dest.writeStr("$="), - .substring_match => dest.writeStr("*="), - .cdo => dest.writeStr(""), - .function => |name| { - serializer.serializeIdentifier(name, dest) catch return dest.addFmtError(); - return dest.writeStr("("); - }, - .open_paren => dest.writeStr("("), - .open_square => dest.writeStr("["), - .open_curly => dest.writeStr("{"), - .bad_url => |contents| { - try dest.writeStr("url("); - try dest.writeStr(contents); - return dest.writeChar(')'); - }, - .bad_string => |value| { - try dest.writeChar('"'); - var writer = serializer.CssStringWriter(@TypeOf(dest)).new(dest); - return writer.writeStr(value) catch return dest.addFmtError(); - }, - .close_paren => dest.writeStr(")"), - .close_square => dest.writeStr("]"), - .close_curly => dest.writeStr("}"), - }; - } -}; - -const Num = struct { - has_sign: bool, - value: f32, - int_value: ?i32, - - pub fn eql(lhs: *const Num, rhs: *const Num) bool { - return implementEql(Num, lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return implementHash(@This(), this, hasher); - } -}; - -const Dimension = struct { - num: Num, - /// e.g. "px" - unit: []const u8, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return implementHash(@This(), this, hasher); - } -}; - -const CopyOnWriteStr = union(enum) { - borrowed: []const u8, - owned: std.array_list.Managed(u8), - - pub fn append(this: *@This(), allocator: Allocator, slice: []const u8) void { - switch (this.*) { - .borrowed => { - var list = bun.handleOom(std.array_list.Managed(u8).initCapacity(allocator, this.borrowed.len + slice.len)); - list.appendSliceAssumeCapacity(this.borrowed); - list.appendSliceAssumeCapacity(slice); - this.* = .{ .owned = list }; - }, - .owned => { - bun.handleOom(this.owned.appendSlice(slice)); - }, - } - } - - pub fn toSlice(this: *@This()) []const u8 { - return switch (this.*) { - .borrowed => this.borrowed, - .owned => this.owned.items[0..], - }; - } -}; - -pub const color = struct { - /// The opaque alpha value of 1.0. - pub const OPAQUE: f32 = 1.0; - - const ColorError = error{ - parse, - }; - - /// Either an angle or a number. - pub const AngleOrNumber = union(enum) { - /// ``. - number: struct { - /// The numeric value parsed, as a float. - value: f32, - }, - /// `` - angle: struct { - /// The value as a number of degrees. - degrees: f32, - }, - }; - - const RGB = struct { u8, u8, u8 }; - pub const named_colors = bun.ComptimeStringMap(RGB, .{ - .{ "aliceblue", .{ 240, 248, 255 } }, - .{ "antiquewhite", .{ 250, 235, 215 } }, - .{ "aqua", .{ 0, 255, 255 } }, - .{ "aquamarine", .{ 127, 255, 212 } }, - .{ "azure", .{ 240, 255, 255 } }, - .{ "beige", .{ 245, 245, 220 } }, - .{ "bisque", .{ 255, 228, 196 } }, - .{ "black", .{ 0, 0, 0 } }, - .{ "blanchedalmond", .{ 255, 235, 205 } }, - .{ "blue", .{ 0, 0, 255 } }, - .{ "blueviolet", .{ 138, 43, 226 } }, - .{ "brown", .{ 165, 42, 42 } }, - .{ "burlywood", .{ 222, 184, 135 } }, - .{ "cadetblue", .{ 95, 158, 160 } }, - .{ "chartreuse", .{ 127, 255, 0 } }, - .{ "chocolate", .{ 210, 105, 30 } }, - .{ "coral", .{ 255, 127, 80 } }, - .{ "cornflowerblue", .{ 100, 149, 237 } }, - .{ "cornsilk", .{ 255, 248, 220 } }, - .{ "crimson", .{ 220, 20, 60 } }, - .{ "cyan", .{ 0, 255, 255 } }, - .{ "darkblue", .{ 0, 0, 139 } }, - .{ "darkcyan", .{ 0, 139, 139 } }, - .{ "darkgoldenrod", .{ 184, 134, 11 } }, - .{ "darkgray", .{ 169, 169, 169 } }, - .{ "darkgreen", .{ 0, 100, 0 } }, - .{ "darkgrey", .{ 169, 169, 169 } }, - .{ "darkkhaki", .{ 189, 183, 107 } }, - .{ "darkmagenta", .{ 139, 0, 139 } }, - .{ "darkolivegreen", .{ 85, 107, 47 } }, - .{ "darkorange", .{ 255, 140, 0 } }, - .{ "darkorchid", .{ 153, 50, 204 } }, - .{ "darkred", .{ 139, 0, 0 } }, - .{ "darksalmon", .{ 233, 150, 122 } }, - .{ "darkseagreen", .{ 143, 188, 143 } }, - .{ "darkslateblue", .{ 72, 61, 139 } }, - .{ "darkslategray", .{ 47, 79, 79 } }, - .{ "darkslategrey", .{ 47, 79, 79 } }, - .{ "darkturquoise", .{ 0, 206, 209 } }, - .{ "darkviolet", .{ 148, 0, 211 } }, - .{ "deeppink", .{ 255, 20, 147 } }, - .{ "deepskyblue", .{ 0, 191, 255 } }, - .{ "dimgray", .{ 105, 105, 105 } }, - .{ "dimgrey", .{ 105, 105, 105 } }, - .{ "dodgerblue", .{ 30, 144, 255 } }, - .{ "firebrick", .{ 178, 34, 34 } }, - .{ "floralwhite", .{ 255, 250, 240 } }, - .{ "forestgreen", .{ 34, 139, 34 } }, - .{ "fuchsia", .{ 255, 0, 255 } }, - .{ "gainsboro", .{ 220, 220, 220 } }, - .{ "ghostwhite", .{ 248, 248, 255 } }, - .{ "gold", .{ 255, 215, 0 } }, - .{ "goldenrod", .{ 218, 165, 32 } }, - .{ "gray", .{ 128, 128, 128 } }, - .{ "green", .{ 0, 128, 0 } }, - .{ "greenyellow", .{ 173, 255, 47 } }, - .{ "grey", .{ 128, 128, 128 } }, - .{ "honeydew", .{ 240, 255, 240 } }, - .{ "hotpink", .{ 255, 105, 180 } }, - .{ "indianred", .{ 205, 92, 92 } }, - .{ "indigo", .{ 75, 0, 130 } }, - .{ "ivory", .{ 255, 255, 240 } }, - .{ "khaki", .{ 240, 230, 140 } }, - .{ "lavender", .{ 230, 230, 250 } }, - .{ "lavenderblush", .{ 255, 240, 245 } }, - .{ "lawngreen", .{ 124, 252, 0 } }, - .{ "lemonchiffon", .{ 255, 250, 205 } }, - .{ "lightblue", .{ 173, 216, 230 } }, - .{ "lightcoral", .{ 240, 128, 128 } }, - .{ "lightcyan", .{ 224, 255, 255 } }, - .{ "lightgoldenrodyellow", .{ 250, 250, 210 } }, - .{ "lightgray", .{ 211, 211, 211 } }, - .{ "lightgreen", .{ 144, 238, 144 } }, - .{ "lightgrey", .{ 211, 211, 211 } }, - .{ "lightpink", .{ 255, 182, 193 } }, - .{ "lightsalmon", .{ 255, 160, 122 } }, - .{ "lightseagreen", .{ 32, 178, 170 } }, - .{ "lightskyblue", .{ 135, 206, 250 } }, - .{ "lightslategray", .{ 119, 136, 153 } }, - .{ "lightslategrey", .{ 119, 136, 153 } }, - .{ "lightsteelblue", .{ 176, 196, 222 } }, - .{ "lightyellow", .{ 255, 255, 224 } }, - .{ "lime", .{ 0, 255, 0 } }, - .{ "limegreen", .{ 50, 205, 50 } }, - .{ "linen", .{ 250, 240, 230 } }, - .{ "magenta", .{ 255, 0, 255 } }, - .{ "maroon", .{ 128, 0, 0 } }, - .{ "mediumaquamarine", .{ 102, 205, 170 } }, - .{ "mediumblue", .{ 0, 0, 205 } }, - .{ "mediumorchid", .{ 186, 85, 211 } }, - .{ "mediumpurple", .{ 147, 112, 219 } }, - .{ "mediumseagreen", .{ 60, 179, 113 } }, - .{ "mediumslateblue", .{ 123, 104, 238 } }, - .{ "mediumspringgreen", .{ 0, 250, 154 } }, - .{ "mediumturquoise", .{ 72, 209, 204 } }, - .{ "mediumvioletred", .{ 199, 21, 133 } }, - .{ "midnightblue", .{ 25, 25, 112 } }, - .{ "mintcream", .{ 245, 255, 250 } }, - .{ "mistyrose", .{ 255, 228, 225 } }, - .{ "moccasin", .{ 255, 228, 181 } }, - .{ "navajowhite", .{ 255, 222, 173 } }, - .{ "navy", .{ 0, 0, 128 } }, - .{ "oldlace", .{ 253, 245, 230 } }, - .{ "olive", .{ 128, 128, 0 } }, - .{ "olivedrab", .{ 107, 142, 35 } }, - .{ "orange", .{ 255, 165, 0 } }, - .{ "orangered", .{ 255, 69, 0 } }, - .{ "orchid", .{ 218, 112, 214 } }, - .{ "palegoldenrod", .{ 238, 232, 170 } }, - .{ "palegreen", .{ 152, 251, 152 } }, - .{ "paleturquoise", .{ 175, 238, 238 } }, - .{ "palevioletred", .{ 219, 112, 147 } }, - .{ "papayawhip", .{ 255, 239, 213 } }, - .{ "peachpuff", .{ 255, 218, 185 } }, - .{ "peru", .{ 205, 133, 63 } }, - .{ "pink", .{ 255, 192, 203 } }, - .{ "plum", .{ 221, 160, 221 } }, - .{ "powderblue", .{ 176, 224, 230 } }, - .{ "purple", .{ 128, 0, 128 } }, - .{ "rebeccapurple", .{ 102, 51, 153 } }, - .{ "red", .{ 255, 0, 0 } }, - .{ "rosybrown", .{ 188, 143, 143 } }, - .{ "royalblue", .{ 65, 105, 225 } }, - .{ "saddlebrown", .{ 139, 69, 19 } }, - .{ "salmon", .{ 250, 128, 114 } }, - .{ "sandybrown", .{ 244, 164, 96 } }, - .{ "seagreen", .{ 46, 139, 87 } }, - .{ "seashell", .{ 255, 245, 238 } }, - .{ "sienna", .{ 160, 82, 45 } }, - .{ "silver", .{ 192, 192, 192 } }, - .{ "skyblue", .{ 135, 206, 235 } }, - .{ "slateblue", .{ 106, 90, 205 } }, - .{ "slategray", .{ 112, 128, 144 } }, - .{ "slategrey", .{ 112, 128, 144 } }, - .{ "snow", .{ 255, 250, 250 } }, - .{ "springgreen", .{ 0, 255, 127 } }, - .{ "steelblue", .{ 70, 130, 180 } }, - .{ "tan", .{ 210, 180, 140 } }, - .{ "teal", .{ 0, 128, 128 } }, - .{ "thistle", .{ 216, 191, 216 } }, - .{ "tomato", .{ 255, 99, 71 } }, - .{ "turquoise", .{ 64, 224, 208 } }, - .{ "violet", .{ 238, 130, 238 } }, - .{ "wheat", .{ 245, 222, 179 } }, - .{ "white", .{ 255, 255, 255 } }, - .{ "whitesmoke", .{ 245, 245, 245 } }, - .{ "yellow", .{ 255, 255, 0 } }, - .{ "yellowgreen", .{ 154, 205, 50 } }, - }); - - /// Returns the named color with the given name. - /// - pub fn parseNamedColor(ident: []const u8) ?struct { u8, u8, u8 } { - return named_colors.get(ident); - } - - /// Parse a color hash, without the leading '#' character. - pub fn parseHashColor(value: []const u8) ?struct { u8, u8, u8, f32 } { - return parseHashColorImpl(value) catch return null; - } - - pub fn parseHashColorImpl(value: []const u8) ColorError!struct { u8, u8, u8, f32 } { - return switch (value.len) { - 8 => .{ - (try fromHex(value[0])) * 16 + (try fromHex(value[1])), - (try fromHex(value[2])) * 16 + (try fromHex(value[3])), - (try fromHex(value[4])) * 16 + (try fromHex(value[5])), - @as(f32, @floatFromInt((try fromHex(value[6])) * 16 + (try fromHex(value[7])))) / 255.0, - }, - 6 => { - const r = (try fromHex(value[0])) * 16 + (try fromHex(value[1])); - const g = (try fromHex(value[2])) * 16 + (try fromHex(value[3])); - const b = (try fromHex(value[4])) * 16 + (try fromHex(value[5])); - return .{ - r, g, b, - - OPAQUE, - }; - }, - 4 => .{ - (try fromHex(value[0])) * 17, - (try fromHex(value[1])) * 17, - (try fromHex(value[2])) * 17, - @as(f32, @floatFromInt((try fromHex(value[3])) * 17)) / 255.0, - }, - 3 => .{ - (try fromHex(value[0])) * 17, - (try fromHex(value[1])) * 17, - (try fromHex(value[2])) * 17, - OPAQUE, - }, - else => ColorError.parse, - }; - } - - pub fn fromHex(c: u8) ColorError!u8 { - return switch (c) { - '0'...'9' => c - '0', - 'a'...'f' => c - 'a' + 10, - 'A'...'F' => c - 'A' + 10, - else => ColorError.parse, - }; - } - - /// - /// except with h pre-multiplied by 3, to avoid some rounding errors. - pub fn hslToRgb(hue: f32, saturation: f32, lightness: f32) struct { f32, f32, f32 } { - bun.debugAssert(saturation >= 0.0 and saturation <= 1.0); - const Helpers = struct { - pub fn hueToRgb(m1: f32, m2: f32, _h3: f32) f32 { - var h3 = _h3; - if (h3 < 0.0) { - h3 += 3.0; - } - if (h3 > 3.0) { - h3 -= 3.0; - } - if (h3 * 2.0 < 1.0) { - return m1 + (m2 - m1) * h3 * 2.0; - } else if (h3 * 2.0 < 3.0) { - return m2; - } else if (h3 < 2.0) { - return m1 + (m2 - m1) * (2.0 - h3) * 2.0; - } else { - return m1; - } - } - }; - const m2 = if (lightness <= 0.5) - lightness * (saturation + 1.0) - else - lightness + saturation - lightness * saturation; - const m1 = lightness * 2.0 - m2; - const hue_times_3 = hue * 3.0; - const red = Helpers.hueToRgb(m1, m2, hue_times_3 + 1.0); - const green = Helpers.hueToRgb(m1, m2, hue_times_3); - const blue = Helpers.hueToRgb(m1, m2, hue_times_3 - 1.0); - return .{ red, green, blue }; - } -}; - -// pub const Bitflags - -pub const serializer = struct { - /// Write a CSS name, like a custom property name. - /// - /// You should only use this when you know what you're doing, when in doubt, - /// consider using `serialize_identifier`. - pub fn serializeName(value: []const u8, writer: anytype) !void { - var chunk_start: usize = 0; - for (value, 0..) |b, i| { - const escaped: ?[]const u8 = switch (b) { - '0'...'9', 'A'...'Z', 'a'...'z', '_', '-' => continue, - // the unicode replacement character - 0 => bun.strings.encodeUTF8Comptime(0xFFD), - else => if (!std.ascii.isAscii(b)) continue else null, - }; - - try writer.writeAll(value[chunk_start..i]); - if (escaped) |esc| { - try writer.writeAll(esc); - } else if ((b >= 0x01 and b <= 0x1F) or b == 0x7F) { - try hexEscape(b, writer); - } else { - try charEscape(b, writer); - } - chunk_start = i + 1; - } - return writer.writeAll(value[chunk_start..]); - } - - /// Write a double-quoted CSS string token, escaping content as necessary. - pub fn serializeString(value: []const u8, writer: anytype) !void { - try writer.writeAll("\""); - var string_writer = CssStringWriter(@TypeOf(writer)).new(writer); - try string_writer.writeStr(value); - return writer.writeAll("\""); - } - - pub fn serializeDimension(value: f32, unit: []const u8, dest: *Printer) PrintErr!void { - // Check if the value is an integer - use Rust-compatible conversion - const int_value: ?i32 = if (fract(value) == 0.0) - bun.intFromFloat(i32, value) - else - null; - const token = Token{ .dimension = .{ - .num = .{ - .has_sign = value < 0.0, - .value = value, - .int_value = int_value, - }, - .unit = unit, - } }; - if (value != 0.0 and @abs(value) < 1.0) { - // TODO: calculate the actual number of chars here - var buf: [64]u8 = undefined; - var fbs = std.Io.Writer.fixed(&buf); - token.toCssGeneric(&fbs) catch return dest.addFmtError(); - const s = fbs.buffered(); - if (value < 0.0) { - try dest.writeStr("-"); - return dest.writeStr(bun.strings.trimLeadingPattern2(s, '-', '0')); - } else { - return dest.writeStr(bun.strings.trimLeadingChar(s, '0')); - } - } else { - return token.toCssGeneric(dest) catch return dest.addFmtError(); - } - } - - /// Write a CSS identifier, escaping characters as necessary. - pub fn serializeIdentifier(value: []const u8, writer: anytype) !void { - if (value.len == 0) { - return; - } - - if (bun.strings.startsWith(value, "--")) { - try writer.writeAll("--"); - return serializeName(value[2..], writer); - } else if (bun.strings.eql(value, "-")) { - return writer.writeAll("\\-"); - } else { - var slice = value; - if (slice[0] == '-') { - try writer.writeAll("-"); - slice = slice[1..]; - } - if (slice.len > 0 and slice[0] >= '0' and slice[0] <= '9') { - try hexEscape(slice[0], writer); - slice = slice[1..]; - } - return serializeName(slice, writer); - } - } - - pub fn serializeUnquotedUrl(value: []const u8, writer: anytype) !void { - var chunk_start: usize = 0; - for (value, 0..) |b, i| { - const hex = switch (b) { - 0...' ', 0x7F => true, - '(', ')', '"', '\'', '\\' => false, - else => continue, - }; - try writer.writeAll(value[chunk_start..i]); - if (hex) { - try hexEscape(b, writer); - } else { - try charEscape(b, writer); - } - chunk_start = i + 1; - } - return writer.writeAll(value[chunk_start..]); - } - - // pub fn writeNumeric(value: f32, int_value: ?i32, has_sign: bool, writer: anytype) !void { - // // `value >= 0` is true for negative 0. - // if (has_sign and !std.math.signbit(value)) { - // try writer.writeAll("+"); - // } - - // if (value == 0.0 and signfns.isSignNegative(value)) { - // // Negative zero. Work around #20596. - // try writer.writeAll("-0"); - // if (int_value == null and @mod(value, 1) == 0) { - // try writer.writeAll(".0"); - // } - // } else { - // var buf: [124]u8 = undefined; - // const bytes = bun.fmt.FormatDouble.dtoa(&buf, @floatCast(value)); - // try writer.writeAll(bytes); - // } - // } - - pub fn writeNumeric(value: f32, int_value: ?i32, has_sign: bool, writer: anytype) !void { - // `value >= 0` is true for negative 0. - if (has_sign and !std.math.signbit(value)) { - try writer.writeAll("+"); - } - - const notation: Notation = if (value == 0.0 and std.math.signbit(value)) notation: { - // Negative zero. Work around #20596. - try writer.writeAll("-0"); - break :notation Notation{ - .decimal_point = false, - .scientific = false, - }; - } else notation: { - var buf: [129]u8 = undefined; - const str, const maybe_notaton = try dtoa_short(&buf, value, 6); - try writer.writeAll(str); - if (maybe_notaton) |notation| break :notation notation; - return; - }; - - if (int_value == null and fract(value) == 0) { - if (!notation.decimal_point and !notation.scientific) { - try writer.writeAll(".0"); - } - } - - return; - } - - pub fn hexEscape(ascii_byte: u8, writer: anytype) !void { - const HEX_DIGITS = "0123456789abcdef"; - var bytes: [4]u8 = undefined; - const slice: []const u8 = if (ascii_byte > 0x0F) slice: { - const high: usize = @intCast(ascii_byte >> 4); - const low: usize = @intCast(ascii_byte & 0x0F); - bytes[0] = '\\'; - bytes[1] = HEX_DIGITS[high]; - bytes[2] = HEX_DIGITS[low]; - bytes[3] = ' '; - break :slice bytes[0..4]; - } else slice: { - bytes[0] = '\\'; - bytes[1] = HEX_DIGITS[ascii_byte]; - bytes[2] = ' '; - break :slice bytes[0..3]; - }; - return writer.writeAll(slice); - } - - pub fn charEscape(ascii_byte: u8, writer: anytype) !void { - const bytes = [_]u8{ '\\', ascii_byte }; - return writer.writeAll(&bytes); - } - - pub fn CssStringWriter(comptime W: type) type { - return struct { - inner: W, - - /// Wrap a text writer to create a `CssStringWriter`. - pub fn new(inner: W) @This() { - return .{ .inner = inner }; - } - - pub fn writeStr(this: *@This(), str: []const u8) !void { - var chunk_start: usize = 0; - for (str, 0..) |b, i| { - const escaped = switch (b) { - '"' => "\\\"", - '\\' => "\\\\", - // replacement character - 0 => bun.strings.encodeUTF8Comptime(0xFFD), - 0x01...0x1F, 0x7F => null, - else => continue, - }; - try this.inner.writeAll(str[chunk_start..i]); - if (escaped) |e| { - try this.inner.writeAll(e); - } else { - try serializer.hexEscape(b, this.inner); - } - chunk_start = i + 1; - } - return this.inner.writeAll(str[chunk_start..]); - } - }; - } -}; - -pub const implementEql = generic.implementEql; -pub const implementHash = generic.implementHash; -pub const implementDeepClone = generic.implementDeepClone; - -pub const parse_utility = struct { - /// Parse a value from a string. - /// - /// (This is a convenience wrapper for `parse` and probably should not be overridden.) - /// - /// NOTE: `input` should live as long as the returned value. Otherwise, strings in the - /// returned parsed value will point to undefined memory. - pub fn parseString( - allocator: Allocator, - comptime T: type, - input: []const u8, - comptime parse_one: *const fn (*Parser) Result(T), - ) Result(T) { - // I hope this is okay - var import_records = bun.BabyList(bun.ImportRecord){}; - defer import_records.deinit(allocator); - var i = ParserInput.new(allocator, input); - var parser = Parser.new(&i, &import_records, .{}, null); - const result = switch (parse_one(&parser)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (parser.expectExhausted().asErr()) |e| return .{ .err = e }; - return .{ .result = result }; - } -}; - -pub const to_css = struct { - /// Serialize `self` in CSS syntax and return a string. - /// - /// (This is a convenience wrapper for `to_css` and probably should not be overridden.) - pub fn string( - allocator: Allocator, - comptime T: type, - this: *const T, - options: PrinterOptions, - import_info: ?ImportInfo, - local_names: ?*const LocalsResultsMap, - symbols: *const bun.ast.Symbol.Map, - ) PrintErr![]const u8 { - var s = std.Io.Writer.Allocating.init(allocator); - errdefer s.deinit(); - const writer = &s.writer; - // PERF: think about how cheap this is to create - var printer = Printer.new(allocator, std.array_list.Managed(u8).init(allocator), writer, options, import_info, local_names, symbols); - defer printer.deinit(); - switch (T) { - CSSString => try CSSStringFns.toCss(this, &printer), - else => try this.toCss(&printer), - } - return s.written(); - } - - pub fn fromList(comptime T: type, this: []const T, dest: *Printer) PrintErr!void { - const len = this.len; - for (this, 0..) |*val, idx| { - try val.toCss(dest); - if (idx < len - 1) { - try dest.delim(',', false); - } - } - return; - } - - pub fn fromBabyList(comptime T: type, this: *const bun.BabyList(T), dest: *Printer) PrintErr!void { - const len = this.len; - for (this.sliceConst(), 0..) |*val, idx| { - try val.toCss(dest); - if (idx < len - 1) { - try dest.delim(',', false); - } - } - return; - } - - pub fn integer(comptime T: type, this: T, dest: *Printer) PrintErr!void { - const MAX_LEN = comptime maxDigits(T); - var buf: [MAX_LEN]u8 = undefined; - const str = std.fmt.bufPrint(buf[0..], "{d}", .{this}) catch unreachable; - return dest.writeStr(str); - } - - pub fn float32(this: f32, writer: *Printer) !void { - var scratch: [129]u8 = undefined; - const str, _ = try dtoa_short(&scratch, this, 6); - return writer.writeAll(str); - } - - fn maxDigits(comptime T: type) usize { - const max_val = std.math.maxInt(T); - return std.fmt.count("{d}", .{max_val}); - } -}; - -/// Parse `!important`. -/// -/// Typical usage is `input.try_parse(parse_important).is_ok()` -/// at the end of a `DeclarationParser::parse_value` implementation. -pub fn parseImportant(input: *Parser) Result(void) { - if (input.expectDelim('!').asErr()) |e| return .{ .err = e }; - return switch (input.expectIdentMatching("important")) { - .result => |v| .{ .result = v }, - .err => |e| .{ .err = e }, - }; -} - -pub const signfns = struct { - pub inline fn isSignPositive(x: f32) bool { - return !isSignNegative(x); - } - pub inline fn isSignNegative(x: f32) bool { - // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus - // applies to zeros and NaNs as well. - // SAFETY: This is just transmuting to get the sign bit, it's fine. - return @as(u32, @bitCast(x)) & 0x8000_0000 != 0; - } - /// Returns a number that represents the sign of `self`. - /// - /// - `1.0` if the number is positive, `+0.0` or `INFINITY` - /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` - /// - NaN if the number is NaN - pub fn signum(x: f32) f32 { - if (std.math.isNan(x)) return std.math.nan(f32); - return copysign(1, x); - } - - pub inline fn signF32(x: f32) f32 { - if (x == 0.0) return if (isSignNegative(x)) 0.0 else -0.0; - return signum(x); - } -}; - -/// TODO(zack) is this correct -/// Copies the sign of `sign` to `self`, returning a new f32 value -pub inline fn copysign(self: f32, sign: f32) f32 { - // Convert both floats to their bit representations - const self_bits = @as(u32, @bitCast(self)); - const sign_bits = @as(u32, @bitCast(sign)); - - // Clear the sign bit of self and combine with the sign bit of sign - const result_bits = (self_bits & 0x7FFFFFFF) | (sign_bits & 0x80000000); - - // Convert the result back to f32 - return @as(f32, @bitCast(result_bits)); -} - -pub fn deepClone(comptime V: type, allocator: Allocator, list: *const ArrayList(V)) ArrayList(V) { - var newlist = bun.handleOom(ArrayList(V).initCapacity(allocator, list.items.len)); - - for (list.items) |*item| { - newlist.appendAssumeCapacity(generic.deepClone(V, item, allocator)); - } - - return newlist; -} - -pub fn deepDeinit(comptime V: type, allocator: Allocator, list: *ArrayList(V)) void { - if (comptime !@hasDecl(V, "deinit")) return; - for (list.items) |*item| { - item.deinit(allocator); - } - - list.deinit(allocator); -} - -const Notation = struct { - decimal_point: bool, - scientific: bool, - - pub fn integer() Notation { - return .{ - .decimal_point = false, - .scientific = false, - }; - } -}; - -/// Writes float with precision. -/// -/// Returns null if value was an infinite number -pub fn dtoa_short(buf: *[129]u8, value: f32, comptime precision: u8) !struct { []u8, ?Notation } { - // We can't give Infinity/-Infinity to dtoa_short_impl so - // we'l handle them here. - // - // We need to print a valid finite number otherwise browsers like Safari will - // render certain things wrong (see https://github.com/oven-sh/bun/issues/18064) - // - // We'll use 3.40282e38 which is approximately the largest finite number in 32-bit IEEE754 floating point - if (std.math.isPositiveInf(value)) { - buf[0.."3.40282e38".len].* = "3.40282e38".*; - return .{ buf[0.."3.40282e38".len], null }; - } else if (std.math.isNegativeInf(value)) { - buf[0.."-3.40282e38".len].* = "-3.40282e38".*; - return .{ buf[0.."-3.40282e38".len], null }; - } - // We shouldn't receive NaN here. - // NaN is not a valid CSS token and any inlined calculations from `calc()` we ensure - // are not NaN. - bun.debugAssert(!std.math.isNan(value)); - const str, const notation = dtoa_short_impl(buf, value, precision); - return .{ str, notation }; -} - -pub fn dtoa_short_impl(buf: *[129]u8, value: f32, comptime precision: u8) struct { []u8, Notation } { - buf[0] = '0'; - bun.debugAssert(std.math.isFinite(value)); - const buf_len = bun.fmt.FormatDouble.dtoa(@ptrCast(buf[1..].ptr), @floatCast(value)).len; - return restrict_prec(buf[0 .. buf_len + 1], precision); -} - -fn restrict_prec(buf: []u8, comptime prec: u8) struct { []u8, Notation } { - const len: u8 = @intCast(buf.len); - - // Put a leading zero to capture any carry. - // Caller must prepare an empty byte for us; - bun.debugAssert(buf[0] == '0'); - buf[0] = '0'; - // Remove the sign for now. We will put it back at the end. - const sign = switch (buf[1]) { - '+', '-' => brk: { - const s = buf[1]; - buf[1] = '0'; - break :brk s; - }, - else => null, - }; - - // Locate dot, exponent, and the first significant digit. - var _pos_dot: ?u8 = null; - var pos_exp: ?u8 = null; - var _prec_start: ?u8 = null; - for (1..len) |i| { - if (buf[i] == '.') { - bun.debugAssert(_pos_dot == null); - _pos_dot = @intCast(i); - } else if (buf[i] == 'e') { - pos_exp = @intCast(i); - // We don't change exponent part, so stop here. - break; - } else if (_prec_start == null and buf[i] != '0') { - bun.debugAssert(buf[i] >= '1' and buf[i] <= '9'); - _prec_start = @intCast(i); - } - } - - const prec_start = if (_prec_start) |i| - i - else - // If there is no non-zero digit at all, it is just zero. - return .{ - buf[0..1], - Notation.integer(), - }; - - // Coefficient part ends at 'e' or the length. - const coeff_end = pos_exp orelse len; - // Decimal dot is effectively at the end of coefficient part if no - // dot presents before that. - const had_pos_dot = _pos_dot != null; - const pos_dot = _pos_dot orelse coeff_end; - // Find the end position of the number within the given precision. - const prec_end: u8 = brk: { - const end = prec_start + prec; - break :brk if (pos_dot > prec_start and pos_dot <= end) end + 1 else end; - }; - var new_coeff_end = coeff_end; - if (prec_end < coeff_end) { - // Round to the given precision. - const next_char = buf[prec_end]; - new_coeff_end = prec_end; - if (next_char >= '5') { - var i = prec_end; - while (i != 0) { - i -= 1; - if (buf[i] == '.') { - continue; - } - if (buf[i] != '9') { - buf[i] += 1; - new_coeff_end = i + 1; - break; - } - buf[i] = '0'; - } - } - } - if (new_coeff_end < pos_dot) { - // If the precision isn't enough to reach the dot, set all digits - // in-between to zero and keep the number until the dot. - for (new_coeff_end..pos_dot) |i| { - buf[i] = '0'; - } - new_coeff_end = pos_dot; - } else if (had_pos_dot) { - // Strip any trailing zeros. - var i = new_coeff_end; - while (i != 0) { - i -= 1; - if (buf[i] != '0') { - if (buf[i] == '.') { - new_coeff_end = i; - } - break; - } - new_coeff_end = i; - } - } - // Move exponent part if necessary. - const real_end = if (pos_exp) |posexp| brk: { - const exp_len = len - posexp; - if (new_coeff_end != posexp) { - for (0..exp_len) |i| { - buf[new_coeff_end + i] = buf[posexp + i]; - } - } - break :brk new_coeff_end + exp_len; - } else new_coeff_end; - // Add back the sign and strip the leading zero. - const result = if (sign) |sgn| brk: { - if (buf[1] == '0' and buf[2] != '.') { - buf[1] = sgn; - break :brk buf[1..real_end]; - } - bun.debugAssert(buf[0] == '0'); - buf[0] = sgn; - break :brk buf[0..real_end]; - } else brk: { - if (buf[0] == '0' and buf[1] != '.') { - break :brk buf[1..real_end]; - } - break :brk buf[0..real_end]; - }; - // Generate the notation info. - const notation = Notation{ - .decimal_point = pos_dot < new_coeff_end, - .scientific = pos_exp != null, - }; - return .{ result, notation }; -} - -pub inline fn fract(val: f32) f32 { - return val - @trunc(val); -} - -pub fn f32_length_with_5_digits(n_input: f32) usize { - var n = std.math.round(n_input * 100000.0); - var count: usize = 0; - var i: usize = 0; - - while (n >= 1.0) : (i += 1) { - const rem = @mod(n, 10.0); - if (i > 4 or rem != 0.0) { - count += 1; - } - n = n / 10.0; - } - - return count; -} - -const bun = @import("bun"); -const context = @import("./context.zig"); -const css_decls = @import("./declaration.zig"); -const errors_ = @import("./error.zig"); - -const logger = bun.logger; -const Log = logger.Log; - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/declaration.zig b/src/css/declaration.zig deleted file mode 100644 index 9b6abc75da62..000000000000 --- a/src/css/declaration.zig +++ /dev/null @@ -1,461 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const Error = css.Error; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Result = css.Result; - -pub const DeclarationList = ArrayList(css.Property); - -const BackgroundHandler = css.css_properties.background.BackgroundHandler; -const BorderHandler = css.css_properties.border.BorderHandler; -const FallbackHandler = css.css_properties.prefix_handler.FallbackHandler; -const MarginHandler = css.css_properties.margin_padding.MarginHandler; -const PaddingHandler = css.css_properties.margin_padding.PaddingHandler; -const ScrollMarginHandler = css.css_properties.margin_padding.ScrollMarginHandler; -const FontHandler = css.css_properties.font.FontHandler; -const InsetHandler = css.css_properties.margin_padding.InsetHandler; -const SizeHandler = css.css_properties.size.SizeHandler; -const FlexHandler = css.css_properties.flex.FlexHandler; -const AlignHandler = css.css_properties.@"align".AlignHandler; -const TransitionHandler = css.css_properties.transition.TransitionHandler; -const TransformHandler = css.css_properties.transform.TransformHandler; -const ColorSchemeHandler = css.css_properties.ui.ColorSchemeHandler; -const BoxShadowHandler = css.css_properties.box_shadow.BoxShadowHandler; -// const GridHandler = css.css_properties.g - -/// A CSS declaration block. -/// -/// Properties are separated into a list of `!important` declararations, -/// and a list of normal declarations. This reduces memory usage compared -/// with storing a boolean along with each property. -/// -/// TODO: multiarraylist will probably be faster here, as it makes one allocation -/// instead of two. -pub const DeclarationBlock = struct { - /// A list of `!important` declarations in the block. - important_declarations: ArrayList(css.Property) = .{}, - /// A list of normal declarations in the block. - declarations: ArrayList(css.Property) = .{}, - - const This = @This(); - - const DebugFmt = struct { - self: *const DeclarationBlock, - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - var arraylist = std.Io.Writer.Allocating.init(bun.default_allocator); - const w = &arraylist.writer; - defer arraylist.deinit(); - var symbols = bun.ast.Symbol.Map{}; - var printer = css.Printer.new(bun.default_allocator, std.array_list.Managed(u8).init(bun.default_allocator), w, css.PrinterOptions.default(), null, null, &symbols); - defer printer.deinit(); - this.self.toCss(&printer) catch |e| return try writer.print("\n", .{@errorName(e)}); - try writer.writeAll(arraylist.written()); - } - }; - - pub fn debug(this: *const @This()) DebugFmt { - return DebugFmt{ .self = this }; - } - - pub fn isEmpty(this: *const This) bool { - return this.declarations.items.len == 0 and this.important_declarations.items.len == 0; - } - - pub fn parse(input: *css.Parser, options: *const css.ParserOptions) Result(DeclarationBlock) { - var important_declarations = DeclarationList{}; - var declarations = DeclarationList{}; - var decl_parser = PropertyDeclarationParser{ - .important_declarations = &important_declarations, - .declarations = &declarations, - .options = options, - }; - var parser = css.RuleBodyParser(PropertyDeclarationParser).new(input, &decl_parser); - - while (parser.next()) |res| { - if (res.asErr()) |e| { - if (options.error_recovery) { - options.warn(e); - continue; - } - // errdefer doesn't fire on `return .{ .err = ... }` — Result(T) is a tagged - // union, not an error union. Free any declarations accumulated so far. - css.deepDeinit(css.Property, input.allocator(), &declarations); - css.deepDeinit(css.Property, input.allocator(), &important_declarations); - return .{ .err = e }; - } - } - - return .{ .result = DeclarationBlock{ - .important_declarations = important_declarations, - .declarations = declarations, - } }; - } - - pub fn len(this: *const DeclarationBlock) usize { - return this.declarations.items.len + this.important_declarations.items.len; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - const length = this.len(); - var i: usize = 0; - - const DECLS: []const []const u8 = &[_][]const u8{ "declarations", "important_declarations" }; - - inline for (DECLS) |decl_field_name| { - const decls = &@field(this, decl_field_name); - const is_important = comptime std.mem.eql(u8, decl_field_name, "important_declarations"); - - for (decls.items) |*decl| { - try decl.toCss(dest, is_important); - if (i != length - 1) { - try dest.writeChar(';'); - try dest.whitespace(); - } - i += 1; - } - } - - return; - } - - /// Writes the declarations to a CSS block, including starting and ending braces. - pub fn toCssBlock(this: *const This, dest: *Printer) PrintErr!void { - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - - var i: usize = 0; - const length = this.len(); - - const DECLS: []const []const u8 = &[_][]const u8{ "declarations", "important_declarations" }; - - inline for (DECLS) |decl_field_name| { - const decls = &@field(this, decl_field_name); - const is_important = comptime std.mem.eql(u8, decl_field_name, "important_declarations"); - for (decls.items) |*decl| { - try dest.newline(); - try decl.toCss(dest, is_important); - if (i != length - 1 or !dest.minify) { - try dest.writeChar(';'); - } - i += 1; - } - } - - dest.dedent(); - try dest.newline(); - return dest.writeChar('}'); - } - - pub fn minify( - this: *This, - handler: *DeclarationHandler, - important_handler: *DeclarationHandler, - context: *css.PropertyHandlerContext, - ) void { - const handle = struct { - inline fn handle( - self: *This, - ctx: *css.PropertyHandlerContext, - hndlr: *DeclarationHandler, - comptime decl_field: []const u8, - comptime important: bool, - ) void { - for (@field(self, decl_field).items) |*prop| { - ctx.is_important = important; - - const handled = hndlr.handleProperty(prop, ctx); - - if (!handled) { - bun.handleOom(hndlr.decls.append(ctx.allocator, prop.*)); - // replacing with a property which does not require allocation - // to "delete" - prop.* = css.Property{ .all = .@"revert-layer" }; - } - } - } - }.handle; - - handle(this, context, important_handler, "important_declarations", true); - handle(this, context, handler, "declarations", false); - - handler.finalize(context); - important_handler.finalize(context); - var old_import = this.important_declarations; - var old_declarations = this.declarations; - this.important_declarations = .{}; - this.declarations = .{}; - defer { - old_import.deinit(context.allocator); - old_declarations.deinit(context.allocator); - } - this.important_declarations = important_handler.decls; - this.declarations = handler.decls; - important_handler.decls = .{}; - handler.decls = .{}; - } - - pub fn hashPropertyIds(this: *const @This(), hasher: *std.hash.Wyhash) void { - for (this.declarations.items) |*decl| { - decl.propertyId().hash(hasher); - } - - for (this.important_declarations.items) |*decl| { - decl.propertyId().hash(hasher); - } - } - - pub fn eql(this: *const This, other: *const This) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const This, allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const PropertyDeclarationParser = struct { - important_declarations: *ArrayList(css.Property), - declarations: *ArrayList(css.Property), - options: *const css.ParserOptions, - - const This = @This(); - - pub const AtRuleParser = struct { - pub const Prelude = void; - pub const AtRule = void; - - pub fn parsePrelude(_: *This, name: []const u8, input: *css.Parser) Result(Prelude) { - return .{ - .err = input.newError(css.BasicParseErrorKind{ .at_rule_invalid = name }), - }; - } - - pub fn parseBlock(_: *This, _: Prelude, _: *const css.ParserState, input: *css.Parser) Result(AtRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.at_rule_body_invalid) }; - } - - pub fn ruleWithoutBlock(_: *This, _: Prelude, _: *const css.ParserState) css.Maybe(AtRule, void) { - return .{ .err = {} }; - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = void; - pub const QualifiedRule = void; - - pub fn parsePrelude(this: *This, input: *css.Parser) Result(Prelude) { - _ = this; // autofix - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - - pub fn parseBlock(this: *This, prelude: Prelude, start: *const css.ParserState, input: *css.Parser) Result(QualifiedRule) { - _ = this; // autofix - _ = prelude; // autofix - _ = start; // autofix - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - }; - - pub const DeclarationParser = struct { - pub const Declaration = void; - - pub fn parseValue(this: *This, name: []const u8, input: *css.Parser) Result(Declaration) { - return parse_declaration( - name, - input, - this.declarations, - this.important_declarations, - this.options, - ); - } - }; - - pub const RuleBodyItemParser = struct { - pub fn parseQualified(this: *This) bool { - _ = this; // autofix - return false; - } - - pub fn parseDeclarations(this: *This) bool { - _ = this; // autofix - return true; - } - }; -}; - -pub fn parse_declaration( - name: []const u8, - input: *css.Parser, - declarations: *DeclarationList, - important_declarations: *DeclarationList, - options: *const css.ParserOptions, -) Result(void) { - return parse_declaration_impl(name, input, declarations, important_declarations, options, {}); -} - -pub fn parse_declaration_impl( - name: []const u8, - input: *css.Parser, - declarations: *DeclarationList, - important_declarations: *DeclarationList, - options: *const css.ParserOptions, - composes_ctx: anytype, -) Result(void) { - const property_id = css.PropertyId.fromStr(name); - var delimiters = css.Delimiters{ .bang = true }; - if (property_id != .custom or property_id.custom != .custom) { - delimiters.curly_bracket = true; - } - const Closure = struct { - property_id: css.PropertyId, - options: *const css.ParserOptions, - }; - var closure = Closure{ - .property_id = property_id, - .options = options, - }; - const source_location = input.currentSourceLocation(); - var property = switch (input.parseUntilBefore(delimiters, css.Property, &closure, struct { - pub fn parseFn(this: *Closure, input2: *css.Parser) Result(css.Property) { - return css.Property.parse(this.property_id, input2, this.options); - } - }.parseFn)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const important = input.tryParse(struct { - pub fn parsefn(i: *css.Parser) Result(void) { - if (i.expectDelim('!').asErr()) |e| return .{ .err = e }; - return i.expectIdentMatching("important"); - } - }.parsefn, .{}).isOk(); - if (input.expectExhausted().asErr()) |e| return .{ .err = e }; - - if (comptime @TypeOf(composes_ctx) != void) { - if (input.flags.css_modules and property == .composes) { - switch (composes_ctx.composes_state) { - .disallow_entirely => {}, - .allow => { - composes_ctx.recordComposes(input.allocator(), &property.composes); - }, - .disallow_nested => |info| { - options.warnFmtWithNotes( - "\"composes\" is not allowed inside nested selectors", - .{}, - info.line, - info.column, - &[_]bun.logger.Data{}, - ); - }, - .disallow_not_single_class => |info| { - options.warnFmtWithNotes( - "\"composes\" only works inside single class selectors", - .{}, - source_location.line, - source_location.column, - options.allocator.dupe( - bun.logger.Data, - &[_]bun.logger.Data{ - bun.logger.Data{ - .text = bun.handleOom(options.allocator.dupe(u8, "The parent selector is not a single class selector because of the syntax here:")), - .location = info.toLoggerLocation(options.filename), - }, - }, - ) catch |err| bun.handleOom(err), - ); - }, - } - } - } - if (important) { - bun.handleOom(important_declarations.append(input.allocator(), property)); - } else { - bun.handleOom(declarations.append(input.allocator(), property)); - } - - return .success; -} - -pub const DeclarationHandler = struct { - background: BackgroundHandler = .{}, - border: BorderHandler = .{}, - flex: FlexHandler = .{}, - @"align": AlignHandler = .{}, - size: SizeHandler = .{}, - margin: MarginHandler = .{}, - padding: PaddingHandler = .{}, - scroll_margin: ScrollMarginHandler = .{}, - transition: TransitionHandler = .{}, - font: FontHandler = .{}, - inset: InsetHandler = .{}, - transform: TransformHandler = .{}, - box_shadow: BoxShadowHandler = .{}, - color_scheme: ColorSchemeHandler = .{}, - fallback: FallbackHandler = .{}, - direction: ?css.css_properties.text.Direction, - decls: DeclarationList, - - pub fn finalize(this: *DeclarationHandler, context: *css.PropertyHandlerContext) void { - const allocator = context.allocator; - _ = allocator; // autofix - if (this.direction) |direction| { - this.direction = null; - bun.handleOom(this.decls.append(context.allocator, css.Property{ .direction = direction })); - } - // if (this.unicode_bidi) |unicode_bidi| { - // this.unicode_bidi = null; - // this.decls.append(context.allocator, css.Property{ .unicode_bidi = unicode_bidi }) catch |err| bun.handleOom(err); - // } - - this.background.finalize(&this.decls, context); - this.border.finalize(&this.decls, context); - this.flex.finalize(&this.decls, context); - this.@"align".finalize(&this.decls, context); - this.size.finalize(&this.decls, context); - this.margin.finalize(&this.decls, context); - this.padding.finalize(&this.decls, context); - this.scroll_margin.finalize(&this.decls, context); - this.transition.finalize(&this.decls, context); - this.font.finalize(&this.decls, context); - this.inset.finalize(&this.decls, context); - this.transform.finalize(&this.decls, context); - this.box_shadow.finalize(&this.decls, context); - this.color_scheme.finalize(&this.decls, context); - this.fallback.finalize(&this.decls, context); - } - - pub fn handleProperty(this: *DeclarationHandler, property: *const css.Property, context: *css.PropertyHandlerContext) bool { - // return this.background.handleProperty(property, &this.decls, context); - return this.background.handleProperty(property, &this.decls, context) or - this.border.handleProperty(property, &this.decls, context) or - this.flex.handleProperty(property, &this.decls, context) or - this.@"align".handleProperty(property, &this.decls, context) or - this.size.handleProperty(property, &this.decls, context) or - this.margin.handleProperty(property, &this.decls, context) or - this.padding.handleProperty(property, &this.decls, context) or - this.scroll_margin.handleProperty(property, &this.decls, context) or - this.transition.handleProperty(property, &this.decls, context) or - this.font.handleProperty(property, &this.decls, context) or - this.inset.handleProperty(property, &this.decls, context) or - this.transform.handleProperty(property, &this.decls, context) or - this.box_shadow.handleProperty(property, &this.decls, context) or - this.color_scheme.handleProperty(property, &this.decls, context) or - this.fallback.handleProperty(property, &this.decls, context); - } - - pub fn default() DeclarationHandler { - return .{ - .decls = .{}, - .direction = null, - }; - } -}; - -const bun = @import("bun"); -const logger = bun.logger; - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/dependencies.zig b/src/css/dependencies.zig deleted file mode 100644 index f0ea58211118..000000000000 --- a/src/css/dependencies.zig +++ /dev/null @@ -1,151 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const css_values = @import("./values/values.zig"); -const Url = css_values.url.Url; -pub const Error = css.Error; -// const Location = css.Location; - -/// Options for `analyze_dependencies` in `PrinterOptions`. -pub const DependencyOptions = struct { - /// Whether to remove `@import` rules. - remove_imports: bool, -}; - -/// A dependency. -pub const Dependency = union(enum) { - /// An `@import` dependency. - import: ImportDependency, - /// A `url()` dependency. - url: UrlDependency, -}; - -/// A line and column position within a source file. -pub const Location = struct { - /// The line number, starting from 1. - line: u32, - /// The column number, starting from 1. - column: u32, - - pub fn fromSourceLocation(loc: css.SourceLocation) Location { - return Location{ - .line = loc.line + 1, - .column = loc.column, - }; - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// An `@import` dependency. -pub const ImportDependency = struct { - /// The url to import. - url: []const u8, - /// The placeholder that the URL was replaced with. - placeholder: []const u8, - /// An optional `supports()` condition. - supports: ?[]const u8, - /// A media query. - media: ?[]const u8, - /// The location of the dependency in the source file. - loc: SourceRange, - - pub fn new(allocator: Allocator, rule: *const css.css_rules.import.ImportRule, filename: []const u8, local_names: ?*const css.LocalsResultsMap, symbols: *const bun.ast.Symbol.Map) ImportDependency { - const supports = if (rule.supports) |*supports| brk: { - const s = css.to_css.string( - allocator, - css.css_rules.supports.SupportsCondition, - supports, - css.PrinterOptions.default(), - null, - local_names, - symbols, - ) catch bun.Output.panic( - "Unreachable code: failed to stringify SupportsCondition.\n\nThis is a bug in Bun's CSS printer. Please file a bug report at https://github.com/oven-sh/bun/issues/new/choose", - .{}, - ); - break :brk s; - } else null; - - const media = if (rule.media.media_queries.items.len > 0) media: { - const s = css.to_css.string(allocator, css.MediaList, &rule.media, css.PrinterOptions.default(), null, local_names, symbols) catch bun.Output.panic( - "Unreachable code: failed to stringify MediaList.\n\nThis is a bug in Bun's CSS printer. Please file a bug report at https://github.com/oven-sh/bun/issues/new/choose", - .{}, - ); - break :media s; - } else null; - - const placeholder = css.css_modules.hash(allocator, "{s}_{s}", .{ filename, rule.url }, false); - - return ImportDependency{ - // TODO(zack): should we clone this? lightningcss does that - .url = rule.url, - .placeholder = placeholder, - .supports = supports, - .media = media, - .loc = SourceRange.new( - filename, - css.dependencies.Location{ .line = rule.loc.line + 1, .column = rule.loc.column }, - 8, - rule.url.len + 2, - ), // TODO: what about @import url(...)? - }; - } -}; - -/// A `url()` dependency. -pub const UrlDependency = struct { - /// The url of the dependency. - url: []const u8, - /// The placeholder that the URL was replaced with. - placeholder: []const u8, - /// The location of the dependency in the source file. - loc: SourceRange, - - pub fn new(allocator: Allocator, url: *const Url, filename: []const u8, import_records: *const bun.BabyList(bun.ImportRecord)) UrlDependency { - const theurl = import_records.at(url.import_record_idx).path.pretty; - const placeholder = css.css_modules.hash( - allocator, - "{s}_{s}", - .{ filename, theurl }, - false, - ); - return UrlDependency{ - .url = theurl, - .placeholder = placeholder, - .loc = SourceRange.new(filename, url.loc, 4, theurl.len), - }; - } -}; - -/// Represents the range of source code where a dependency was found. -pub const SourceRange = struct { - /// The filename in which the dependency was found. - file_path: []const u8, - /// The starting line and column position of the dependency. - start: Location, - /// The ending line and column position of the dependency. - end: Location, - - pub fn new(filename: []const u8, loc: Location, offset: u32, len: usize) SourceRange { - return SourceRange{ - .file_path = filename, - .start = Location{ - .line = loc.line, - .column = loc.column + offset, - }, - .end = Location{ - .line = loc.line, - .column = loc.column + offset + @as(u32, @intCast(len)) - 1, - }, - }; - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/error.zig b/src/css/error.zig deleted file mode 100644 index f1ff8d6b3595..000000000000 --- a/src/css/error.zig +++ /dev/null @@ -1,417 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const css_values = @import("./values/values.zig"); -pub const Error = css.Error; -const Location = css.Location; - -/// A printer error. -pub const PrinterError = Err(PrinterErrorKind); - -pub fn fmtPrinterError() PrinterError { - return .{ - .kind = .fmt_error, - .loc = null, - }; -} - -/// An error with a source location. -pub fn Err(comptime T: type) type { - return struct { - /// The type of error that occurred. - kind: T, - /// The location where the error occurred. - loc: ?ErrorLocation, - - pub fn format( - this: @This(), - writer: *std.Io.Writer, - ) !void { - if (@hasDecl(T, "format")) { - return this.kind.format(writer); - } - @compileError("format not implemented for " ++ @typeName(T)); - } - - pub const toErrorInstance = @import("../css_jsc/error_jsc.zig").toErrorInstance; - - pub fn fromParseError(err: ParseError(ParserError), filename: []const u8) Err(ParserError) { - if (T != ParserError) { - @compileError("Called .fromParseError() when T is not ParserError"); - } - - const kind = switch (err.kind) { - .basic => |b| switch (b) { - .unexpected_token => |t| ParserError{ .unexpected_token = t }, - .end_of_input => ParserError.end_of_input, - .at_rule_invalid => |a| ParserError{ .at_rule_invalid = a }, - .at_rule_body_invalid => ParserError.at_rule_body_invalid, - .qualified_rule_invalid => ParserError.qualified_rule_invalid, - }, - .custom => |c| c, - }; - - return .{ - .kind = kind, - .loc = ErrorLocation{ - .filename = filename, - .line = err.location.line, - .column = err.location.column, - }, - }; - } - - pub fn addToLogger(this: @This(), log: *logger.Log, source: *const logger.Source, allocator: std.mem.Allocator) !void { - try log.addMsg(.{ - .kind = .err, - .data = .{ - .location = if (this.loc) |*loc| try loc.toLocation(source, allocator) else null, - .text = try std.fmt.allocPrint(allocator, "{f}", .{this.kind}), - }, - }); - - log.errors += 1; - } - }; -} - -/// Extensible parse errors that can be encountered by client parsing implementations. -pub fn ParseError(comptime T: type) type { - return struct { - /// Details of this error - kind: ParserErrorKind(T), - /// Location where this error occurred - location: css.SourceLocation, - - pub fn basic(this: @This()) BasicParseError { - return switch (this.kind) { - .basic => |kind| BasicParseError{ - .kind = kind, - .location = this.location, - }, - .custom => @panic("Not a basic parse error. This is a bug in Bun's css parser."), - }; - } - }; -} - -pub fn ParserErrorKind(comptime T: type) type { - return union(enum) { - /// A fundamental parse error from a built-in parsing routine. - basic: BasicParseErrorKind, - /// A parse error reported by downstream consumer code. - custom: T, - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - return switch (this) { - inline else => |kind| try kind.format(writer), - }; - } - }; -} - -/// Details about a `BasicParseError` -pub const BasicParseErrorKind = union(enum) { - /// An unexpected token was encountered. - unexpected_token: css.Token, - /// The end of the input was encountered unexpectedly. - end_of_input, - /// An `@` rule was encountered that was invalid. - at_rule_invalid: []const u8, - /// The body of an '@' rule was invalid. - at_rule_body_invalid, - /// A qualified rule was encountered that was invalid. - qualified_rule_invalid, - - pub fn format(this: BasicParseErrorKind, writer: *std.Io.Writer) !void { - return switch (this) { - .unexpected_token => |token| { - try writer.print("unexpected token: {f}", .{token}); - }, - .end_of_input => { - try writer.print("unexpected end of input", .{}); - }, - .at_rule_invalid => |rule| { - try writer.print("invalid @ rule encountered: '@{s}'", .{rule}); - }, - .at_rule_body_invalid => { - // try writer.print("invalid @ body rule encountered: '@{s}'", .{}); - try writer.print("invalid @ body rule encountered", .{}); - }, - .qualified_rule_invalid => { - try writer.print("invalid qualified rule encountered", .{}); - }, - }; - } -}; - -/// A line and column location within a source file. -pub const ErrorLocation = struct { - /// The filename in which the error occurred. - filename: []const u8, - /// The line number, starting from 0. - line: u32, - /// The column number, starting from 1. - column: u32, - - pub fn withFilename(this: ErrorLocation, filename: []const u8) ErrorLocation { - return ErrorLocation{ - .filename = filename, - .line = this.line, - .column = this.column, - }; - } - - pub fn format(this: *const @This(), writer: *std.Io.Writer) !void { - try writer.print("{s}:{d}:{d}", .{ this.filename, this.line, this.column }); - } - - pub fn toLocation(this: @This(), source: *const logger.Source, allocator: Allocator) !logger.Location { - return logger.Location{ - .file = source.path.text, - .namespace = source.path.namespace, - .line = @intCast(this.line + 1), - .column = @intCast(this.column), - .line_text = if (bun.strings.getLinesInText(source.contents, this.line, 1)) |lines| try allocator.dupe(u8, lines.buffer[0]) else null, - }; - } -}; - -/// A printer error type. -pub const PrinterErrorKind = union(enum) { - /// An ambiguous relative `url()` was encountered in a custom property declaration. - ambiguous_url_in_custom_property: struct { - /// The ambiguous URL. - url: []const u8, - }, - /// A [std::fmt::Error](std::fmt::Error) was encountered in the underlying destination. - fmt_error, - /// The CSS modules `composes` property cannot be used within nested rules. - invalid_composes_nesting, - /// The CSS modules `composes` property cannot be used with a simple class selector. - invalid_composes_selector, - /// The CSS modules pattern must end with `[local]` for use in CSS grid. - invalid_css_modules_pattern_in_grid, - no_import_records, - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - return switch (this) { - .ambiguous_url_in_custom_property => |data| writer.print("Ambiguous relative URL '{s}' in custom property declaration", .{data.url}), - .fmt_error => writer.writeAll("Formatting error occurred"), - .invalid_composes_nesting => writer.writeAll("The 'composes' property cannot be used within nested rules"), - .invalid_composes_selector => writer.writeAll("The 'composes' property can only be used with a simple class selector"), - .invalid_css_modules_pattern_in_grid => writer.writeAll("CSS modules pattern must end with '[local]' when used in CSS grid"), - .no_import_records => writer.writeAll("No import records found"), - }; - } -}; - -/// A parser error. -pub const ParserError = union(enum) { - /// An at rule body was invalid. - at_rule_body_invalid, - /// An at rule prelude was invalid. - at_rule_prelude_invalid, - /// An unknown or unsupported at rule was encountered. - at_rule_invalid: []const u8, - /// Unexpectedly encountered the end of input data. - end_of_input, - /// A declaration was invalid. - invalid_declaration, - /// A media query was invalid. - invalid_media_query, - /// Invalid CSS nesting. - invalid_nesting, - /// The @nest rule is deprecated. - deprecated_nest_rule, - /// An invalid selector in an `@page` rule. - invalid_page_selector, - /// An invalid value was encountered. - invalid_value, - /// Invalid qualified rule. - qualified_rule_invalid, - /// A selector was invalid. - selector_error: SelectorError, - /// An `@import` rule was encountered after any rule besides `@charset` or `@layer`. - unexpected_import_rule, - /// A `@namespace` rule was encountered after any rules besides `@charset`, `@import`, or `@layer`. - unexpected_namespace_rule, - /// An unexpected token was encountered. - unexpected_token: css.Token, - /// Maximum nesting depth was reached. - maximum_nesting_depth, - unexpected_value: struct { - expected: []const u8, - received: []const u8, - }, - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - return switch (this) { - .at_rule_body_invalid => writer.writeAll("Invalid at-rule body"), - .at_rule_prelude_invalid => writer.writeAll("Invalid at-rule prelude"), - .at_rule_invalid => |name| writer.print("Unknown at-rule @{s}", .{name}), - .end_of_input => writer.writeAll("Unexpected end of input"), - .invalid_declaration => writer.writeAll("Invalid declaration"), - .invalid_media_query => writer.writeAll("Invalid media query"), - .invalid_nesting => writer.writeAll("Invalid CSS nesting"), - .deprecated_nest_rule => writer.writeAll("The @nest rule is deprecated, use standard CSS nesting instead"), - .invalid_page_selector => writer.writeAll("Invalid @page selector"), - .invalid_value => writer.writeAll("Invalid value"), - .qualified_rule_invalid => writer.writeAll("Invalid qualified rule"), - .selector_error => |err| writer.print("Invalid selector. {f}", .{err}), - .unexpected_import_rule => writer.writeAll("@import rules must come before any other rules except @charset and @layer"), - .unexpected_namespace_rule => writer.writeAll("@namespace rules must come before any other rules except @charset, @import, and @layer"), - .unexpected_token => |token| writer.print("Unexpected token: {f}", .{token}), - .maximum_nesting_depth => writer.writeAll("Maximum CSS nesting depth exceeded"), - .unexpected_value => |v| writer.print("Expected {s}, received {s}", .{ v.expected, v.received }), - }; - } -}; - -/// The fundamental parsing errors that can be triggered by built-in parsing routines. -pub const BasicParseError = struct { - /// Details of this error - kind: BasicParseErrorKind, - /// Location where this error occurred - location: css.SourceLocation, - - pub fn intoParseError( - this: @This(), - comptime T: type, - ) ParseError(T) { - return ParseError(T){ - .kind = .{ .basic = this.kind }, - .location = this.location, - }; - } - - pub inline fn intoDefaultParseError( - this: @This(), - ) ParseError(ParserError) { - return ParseError(ParserError){ - .kind = .{ .basic = this.kind }, - .location = this.location, - }; - } -}; - -/// A selector parsing error. -pub const SelectorError = union(enum) { - /// An unexpected token was found in an attribute selector. - bad_value_in_attr: css.Token, - /// An unexpected token was found in a class selector. - class_needs_ident: css.Token, - /// A dangling combinator was found. - dangling_combinator, - /// An empty selector. - empty_selector, - /// A `|` was expected in an attribute selector. - expected_bar_in_attr: css.Token, - /// A namespace was expected. - expected_namespace: []const u8, - /// An unexpected token was encountered in a namespace. - explicit_namespace_unexpected_token: css.Token, - /// An invalid pseudo class was encountered after a pseudo element. - invalid_pseudo_class_after_pseudo_element, - /// An invalid pseudo class was encountered after a `-webkit-scrollbar` pseudo element. - invalid_pseudo_class_after_webkit_scrollbar, - /// A `-webkit-scrollbar` state was encountered before a `-webkit-scrollbar` pseudo element. - invalid_pseudo_class_before_webkit_scrollbar, - /// Invalid qualified name in attribute selector. - invalid_qual_name_in_attr: css.Token, - /// The current token is not allowed in this state. - invalid_state, - /// The selector is required to have the `&` nesting selector at the start. - missing_nesting_prefix, - /// The selector is missing a `&` nesting selector. - missing_nesting_selector, - /// No qualified name in attribute selector. - no_qualified_name_in_attribute_selector: css.Token, - /// An invalid token was encountered in a pseudo element. - pseudo_element_expected_ident: css.Token, - /// An unexpected identifier was encountered. - unexpected_ident: []const u8, - /// An unexpected token was encountered inside an attribute selector. - unexpected_token_in_attribute_selector: css.Token, - /// An unsupported pseudo class or pseudo element was encountered. - unsupported_pseudo_class_or_element: []const u8, - unexpected_selector_after_pseudo_element: css.Token, - ambiguous_css_module_class: []const u8, - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - return switch (this) { - .dangling_combinator => try writer.writeAll("Found a dangling combinator with no selector"), - .empty_selector => try writer.writeAll("Empty selector is not allowed"), - .invalid_state => try writer.writeAll("Token is not allowed in this state"), - .missing_nesting_prefix => try writer.writeAll("Selector must start with the '&' nesting selector"), - .missing_nesting_selector => try writer.writeAll("Missing '&' nesting selector"), - .invalid_pseudo_class_after_pseudo_element => try writer.writeAll("Invalid pseudo-class after pseudo-element"), - .invalid_pseudo_class_after_webkit_scrollbar => try writer.writeAll("Invalid pseudo-class after -webkit-scrollbar"), - .invalid_pseudo_class_before_webkit_scrollbar => try writer.writeAll("-webkit-scrollbar state found before -webkit-scrollbar pseudo-element"), - - .expected_namespace => |str| try writer.print("Expected namespace '{s}'", .{str}), - .unexpected_ident => |str| try writer.print("Unexpected identifier '{s}'", .{str}), - .unsupported_pseudo_class_or_element => |str| try writer.print("Unsupported pseudo-class or pseudo-element '{s}'", .{str}), - - .bad_value_in_attr => |tok| try writer.print("Invalid value in attribute selector: {f}", .{tok}), - .class_needs_ident => |tok| try writer.print("Expected identifier after '.' in class selector, found: {f}", .{tok}), - .expected_bar_in_attr => |tok| try writer.print("Expected '|' in attribute selector, found: {f}", .{tok}), - .explicit_namespace_unexpected_token => |tok| try writer.print("Unexpected token in namespace: {f}", .{tok}), - .invalid_qual_name_in_attr => |tok| try writer.print("Invalid qualified name in attribute selector: {f}", .{tok}), - .no_qualified_name_in_attribute_selector => |tok| try writer.print("Missing qualified name in attribute selector: {f}", .{tok}), - .pseudo_element_expected_ident => |tok| try writer.print("Expected identifier in pseudo-element, found: {f}", .{tok}), - .unexpected_token_in_attribute_selector => |tok| try writer.print("Unexpected token in attribute selector: {f}", .{tok}), - .unexpected_selector_after_pseudo_element => |tok| try writer.print("Unexpected selector after pseudo-element: {f}", .{tok}), - .ambiguous_css_module_class => |name| try writer.print("CSS module class: '{s}' is currently not supported.", .{name}), - }; - } -}; - -pub fn ErrorWithLocation(comptime T: type) type { - return struct { - kind: T, - loc: css.Location, - }; -} - -pub const MinifyErr = error{ - minify_err, -}; -pub const MinifyError = ErrorWithLocation(MinifyErrorKind); -/// A transformation error. -pub const MinifyErrorKind = union(enum) { - /// A circular `@custom-media` rule was detected. - circular_custom_media: struct { - /// The name of the `@custom-media` rule that was referenced circularly. - name: []const u8, - }, - /// Attempted to reference a custom media rule that doesn't exist. - custom_media_not_defined: struct { - /// The name of the `@custom-media` rule that was not defined. - name: []const u8, - }, - /// Boolean logic with media types in @custom-media rules is not supported. - unsupported_custom_media_boolean_logic: struct { - /// The source location of the `@custom-media` rule with unsupported boolean logic. - custom_media_loc: Location, - }, - - pub fn format(this: *const @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - return switch (this.*) { - .circular_custom_media => |name| try writer.print("Circular @custom-media rule: \"{s}\"", .{name.name}), - .custom_media_not_defined => |name| try writer.print("Custom media rule \"{s}\" not defined", .{name.name}), - .unsupported_custom_media_boolean_logic => |custom_media_loc| try writer.print( - "Unsupported boolean logic in custom media rule at line {d}, column {d}", - .{ - custom_media_loc.custom_media_loc.line, - custom_media_loc.custom_media_loc.column, - }, - ), - }; - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; - -const logger = bun.logger; -const Log = logger.Log; diff --git a/src/css/generics.zig b/src/css/generics.zig deleted file mode 100644 index bf637de23d2e..000000000000 --- a/src/css/generics.zig +++ /dev/null @@ -1,674 +0,0 @@ -pub inline fn implementDeepClone(comptime T: type, this: *const T, allocator: Allocator) T { - const tyinfo = @typeInfo(T); - - if (comptime bun.meta.isSimpleCopyType(T)) { - return this.*; - } - - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - return switch (result) { - .array_list => deepClone(result.child, allocator, this), - .baby_list => @panic("Not implemented."), - .small_list => this.deepClone(allocator), - }; - } - - if (comptime T == []const u8) { - return this.*; - } - - if (comptime T == bun.logger.Loc) { - return this.*; - } - - if (comptime @typeInfo(T) == .pointer) { - const TT = std.meta.Child(T); - return implementEql(TT, this.*); - } - - return switch (tyinfo) { - .@"struct" => { - var strct: T = undefined; - inline for (tyinfo.@"struct".fields) |field| { - if (comptime canTransitivelyImplementDeepClone(field.type) and @hasDecl(field.type, "__generateDeepClone")) { - @field(strct, field.name) = implementDeepClone(field.type, &field(this, field.name, allocator)); - } else { - @field(strct, field.name) = deepClone(field.type, &@field(this, field.name), allocator); - } - } - return strct; - }, - .@"union" => { - inline for (bun.meta.EnumFields(T), tyinfo.@"union".fields) |enum_field, union_field| { - if (@intFromEnum(this.*) == enum_field.value) { - if (comptime canTransitivelyImplementDeepClone(union_field.type) and @hasDecl(union_field.type, "__generateDeepClone")) { - return @unionInit(T, enum_field.name, implementDeepClone(union_field.type, &@field(this, enum_field.name), allocator)); - } - return @unionInit(T, enum_field.name, deepClone(union_field.type, &@field(this, enum_field.name), allocator)); - } - } - unreachable; - }, - else => @compileError("Unhandled type " ++ @typeName(T)), - }; -} - -/// A function to implement `lhs.eql(&rhs)` for the many types in the CSS parser that needs this. -/// -/// This is the equivalent of doing `#[derive(PartialEq])` in Rust. -/// -/// This function only works on simple types like: -/// - Simple equality types (e.g. integers, floats, strings, enums, etc.) -/// - Types which implement a `.eql(lhs: *const @This(), rhs: *const @This()) bool` function -/// -/// Or compound types composed of simple types such as: -/// - Pointers to simple types -/// - Optional simple types -/// - Structs, Arrays, and Unions -pub fn implementEql(comptime T: type, this: *const T, other: *const T) bool { - const tyinfo = @typeInfo(T); - if (comptime bun.meta.isSimpleEqlType(T)) { - return this.* == other.*; - } - if (comptime T == []const u8) { - return bun.strings.eql(this.*, other.*); - } - if (comptime @typeInfo(T) == .pointer) { - const TT = std.meta.Child(T); - return implementEql(TT, this.*, other.*); - } - if (comptime @typeInfo(T) == .optional) { - const TT = std.meta.Child(T); - if (this.* != null and other.* != null) return implementEql(TT, &this.*.?, &other.*.?); - return false; - } - if (comptime T == VendorPrefix) { - return VendorPrefix.eql(this.*, other.*); - } - if (comptime T == bun.logger.Loc) { - return this.*.start == other.*.start; - } - return switch (tyinfo) { - .optional => @compileError("Handled above, this means Zack wrote a bug."), - .pointer => @compileError("Handled above, this means Zack wrote a bug."), - .array => { - const Child = std.meta.Child(T); - if (comptime bun.meta.isSimpleEqlType(Child)) { - return std.mem.eql(Child, &this.*, &other.*); - } - if (this.len != other.len) return false; - if (comptime canTransitivelyImplementEql(Child) and @hasDecl(Child, "__generateEql")) { - for (this.*, other.*) |*a, *b| { - if (!implementEql(Child, &a, &b)) return false; - } - } else { - for (this.*, other.*) |*a, *b| { - if (!eql(Child, a, b)) return false; - } - } - return true; - }, - .@"struct" => { - inline for (tyinfo.@"struct".fields) |field| { - if (!eql(field.type, &@field(this, field.name), &@field(other, field.name))) return false; - } - return true; - }, - .@"union" => { - if (tyinfo.@"union".tag_type == null) @compileError("Unions must have a tag type"); - if (@intFromEnum(this.*) != @intFromEnum(other.*)) return false; - const enum_fields = bun.meta.EnumFields(T); - inline for (enum_fields, std.meta.fields(T)) |enum_field, union_field| { - if (enum_field.value == @intFromEnum(this.*)) { - if (union_field.type != void) { - if (comptime canTransitivelyImplementEql(union_field.type) and @hasDecl(union_field.type, "__generateEql")) { - return implementEql(union_field.type, &@field(this, enum_field.name), &@field(other, enum_field.name)); - } - return eql(union_field.type, &@field(this, enum_field.name), &@field(other, enum_field.name)); - } else { - return true; - } - } - } - unreachable; - }, - else => @compileError("Unsupported type: " ++ @typeName(T)), - }; -} - -pub fn implementHash(comptime T: type, this: *const T, hasher: *std.hash.Wyhash) void { - const tyinfo = @typeInfo(T); - if (comptime T == void) return; - if (comptime bun.meta.isSimpleEqlType(T)) { - return hasher.update(std.mem.asBytes(&this)); - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - const list = switch (result) { - .array_list => this.items[0..], - .baby_list => this.sliceConst(), - .small_list => this.slice(), - }; - bun.writeAnyToHasher(hasher, list.len); - for (list) |*item| { - hash(tyinfo.array.child, item, hasher); - } - return; - } - if (comptime T == []const u8) { - return hasher.update(this.*); - } - if (comptime @typeInfo(T) == .pointer) { - @compileError("Invalid type for implementHash(): " ++ @typeName(T)); - } - if (comptime @typeInfo(T) == .optional) { - @compileError("Invalid type for implementHash(): " ++ @typeName(T)); - } - return switch (tyinfo) { - .optional => { - if (this.* == null) { - bun.writeAnyToHasher(hasher, "null"); - } else { - bun.writeAnyToHasher(hasher, "some"); - hash(tyinfo.optional.child, &this.*.?, hasher); - } - }, - .pointer => { - hash(tyinfo.pointer.child, &this.*, hasher); - }, - .array => { - bun.writeAnyToHasher(hasher, this.len); - for (this.*[0..]) |*item| { - hash(tyinfo.array.child, item, hasher); - } - }, - .@"struct" => { - inline for (tyinfo.@"struct".fields) |field| { - if (comptime hasHash(field.type)) { - hash(field.type, &@field(this, field.name), hasher); - } else if (@hasDecl(field.type, "__generateHash") and @typeInfo(field.type) == .@"struct") { - implementHash(field.type, &@field(this, field.name), hasher); - } else { - @compileError("Can't hash these fields: " ++ @typeName(field.type) ++ ". On " ++ @typeName(T)); - } - } - return; - }, - .@"enum" => { - bun.writeAnyToHasher(hasher, @intFromEnum(this.*)); - }, - .@"union" => { - if (tyinfo.@"union".tag_type == null) @compileError("Unions must have a tag type"); - bun.writeAnyToHasher(hasher, @intFromEnum(this.*)); - const enum_fields = bun.meta.EnumFields(T); - inline for (enum_fields, std.meta.fields(T)) |enum_field, union_field| { - if (enum_field.value == @intFromEnum(this.*)) { - const field = union_field; - if (comptime hasHash(field.type)) { - hash(field.type, &@field(this, field.name), hasher); - } else if (@hasDecl(field.type, "__generateHash") and @typeInfo(field.type) == .@"struct") { - implementHash(field.type, &@field(this, field.name), hasher); - } else { - @compileError("Can't hash these fields: " ++ @typeName(field.type) ++ ". On " ++ @typeName(T)); - } - } - } - return; - }, - else => @compileError("Unsupported type: " ++ @typeName(T)), - }; -} - -pub fn slice(comptime T: type, val: *const T) []const bun.meta.looksLikeListContainerType(T).?.child { - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - return switch (result.list) { - .array_list => val.items, - .baby_list => val.sliceConst(), - .small_list => val.slice(), - }; - } - @compileError("Unsupported type for `slice`: " ++ @typeName(T)); -} - -pub fn isCompatible(comptime T: type, val: *const T, browsers: bun.css.targets.Browsers) bool { - if (@hasDecl(T, "isCompatible")) return T.isCompatible(val, browsers); - const tyinfo = @typeInfo(T); - if (tyinfo == .pointer) { - const TT = std.meta.Child(T); - return isCompatible(TT, val.*, browsers); - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - const slc = switch (result.list) { - .array_list => val.items, - .baby_list => val.sliceConst(), - .small_list => val.sliceConst(), - }; - for (slc) |*item| { - if (!isCompatible(result.child, item, browsers)) return false; - } - return true; - } - @compileError("Unsupported type for `isCompatible`: " ++ @typeName(T)); -} - -pub inline fn parseWithOptions(comptime T: type, input: *Parser, options: *const ParserOptions) Result(T) { - if (T != f32 and T != i32 and @hasDecl(T, "parseWithOptions")) return T.parseWithOptions(input, options); - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - switch (result.list) { - .array_list => return input.parseCommaSeparated(result.child, parseFor(result.child)), - .baby_list => {}, - .small_list => {}, - } - } - return switch (T) { - f32 => CSSNumberFns.parse(input), - CSSInteger => CSSIntegerFns.parse(input), - CustomIdent => CustomIdentFns.parse(input), - DashedIdent => DashedIdentFns.parse(input), - Ident => IdentFns.parse(input), - else => T.parse(input), - }; -} - -pub inline fn parse(comptime T: type, input: *Parser) Result(T) { - if (comptime @typeInfo(T) == .pointer) { - const TT = std.meta.Child(T); - return switch (parse(TT, input)) { - .result => |v| .{ .result = bun.create(input.allocator(), TT, v) }, - .err => |e| .{ .err = e }, - }; - } - if (comptime @typeInfo(T) == .optional) { - const TT = std.meta.Child(T); - return .{ .result = input.tryParse(parseFor(TT), .{}).asValue() }; - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - switch (result.list) { - .array_list => return input.parseCommaSeparated(result.child, parseFor(result.child)), - .baby_list => {}, - .small_list => {}, - } - } - return switch (T) { - f32 => CSSNumberFns.parse(input), - CSSInteger => CSSIntegerFns.parse(input), - CustomIdent => CustomIdentFns.parse(input), - DashedIdent => DashedIdentFns.parse(input), - Ident => IdentFns.parse(input), - else => T.parse(input), - }; -} - -pub inline fn parseFor(comptime T: type) @TypeOf(struct { - fn parsefn(input: *Parser) Result(T) { - return parse(T, input); - } -}.parsefn) { - return struct { - fn parsefn(input: *Parser) Result(T) { - return parse(T, input); - } - }.parsefn; -} - -pub fn hasToCss(comptime T: type) bool { - const tyinfo = @typeInfo(T); - if (comptime T == []const u8) return false; - if (tyinfo == .pointer) { - const TT = std.meta.Child(T); - return hasToCss(TT); - } - if (tyinfo == .optional) { - const TT = std.meta.Child(T); - return hasToCss(TT); - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - switch (result.list) { - .array_list => return true, - .baby_list => return true, - .small_list => return true, - } - } - return switch (T) { - f32 => true, - else => @hasDecl(T, "toCss"), - }; -} - -pub inline fn toCss(comptime T: type, this: *const T, dest: *Printer) PrintErr!void { - if (@typeInfo(T) == .pointer) { - const TT = std.meta.Child(T); - return toCss(TT, this.*, dest); - } - if (@typeInfo(T) == .optional) { - const TT = std.meta.Child(T); - - if (this.*) |*val| { - return toCss(TT, val, dest); - } - return; - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - switch (result.list) { - .array_list => { - return css.to_css.fromList(result.child, this.items, dest); - }, - .baby_list => @compileError("TODO"), - .small_list => @compileError("TODO"), - } - } - return switch (T) { - f32 => CSSNumberFns.toCss(this, dest), - CSSInteger => CSSIntegerFns.toCss(this, dest), - CustomIdent => CustomIdentFns.toCss(this, dest), - DashedIdent => DashedIdentFns.toCss(this, dest), - Ident => IdentFns.toCss(this, dest), - else => T.toCss(this, dest), - }; -} - -pub fn eqlList(comptime T: type, lhs: *const ArrayList(T), rhs: *const ArrayList(T)) bool { - if (lhs.items.len != rhs.items.len) return false; - for (lhs.items, rhs.items) |*left, *right| { - if (!eql(T, left, right)) return false; - } - return true; -} - -pub fn canTransitivelyImplementEql(comptime T: type) bool { - return switch (@typeInfo(T)) { - .@"struct", .@"union" => true, - else => false, - }; -} - -pub inline fn eql(comptime T: type, lhs: *const T, rhs: *const T) bool { - const tyinfo = comptime @typeInfo(T); - @setEvalBranchQuota(10_000); - if (comptime tyinfo == .pointer) { - if (comptime T == []const u8) return bun.strings.eql(lhs.*, rhs.*); - if (comptime tyinfo.pointer.size == .one) { - const TT = std.meta.Child(T); - return eql(TT, lhs.*, rhs.*); - } else if (comptime tyinfo.pointer.size == .slice) { - if (lhs.*.len != rhs.*.len) return false; - for (lhs.*[0..], rhs.*[0..]) |*a, *b| { - if (!eql(tyinfo.pointer.child, a, b)) return false; - } - return true; - } else { - @compileError("Unsupported pointer size: " ++ @tagName(tyinfo.pointer.size) ++ " (" ++ @typeName(T) ++ ")"); - } - } - if (comptime tyinfo == .optional) { - const TT = std.meta.Child(T); - if (lhs.* == null and rhs.* == null) return true; - if (lhs.* != null and rhs.* != null) return eql(TT, &lhs.*.?, &rhs.*.?); - return false; - } - if (comptime bun.meta.isSimpleEqlType(T)) { - return lhs.* == rhs.*; - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - return switch (result.list) { - .array_list => eqlList(result.child, lhs, rhs), - .baby_list => return lhs.eql(rhs), - .small_list => lhs.eql(rhs), - }; - } - if (@hasDecl(T, "IMPL_BITFLAGS")) { - return T.eql(lhs.*, rhs.*); - } - return switch (T) { - f32 => lhs.* == rhs.*, - CSSInteger => lhs.* == rhs.*, - CustomIdent, DashedIdent, Ident => bun.strings.eql(lhs.v, rhs.v), - []const u8 => bun.strings.eql(lhs.*, rhs.*), - bun.logger.Loc => lhs.eql(rhs.*), - else => if (@typeInfo(T) == .@"struct" and @typeInfo(T).@"struct".layout == .@"packed") - lhs.* == rhs.* - else - T.eql(lhs, rhs), - }; -} - -pub fn canTransitivelyImplementDeepClone(comptime T: type) bool { - return switch (@typeInfo(T)) { - .@"struct", .@"union" => true, - else => false, - }; -} - -pub inline fn deepClone(comptime T: type, this: *const T, allocator: Allocator) T { - const tyinfo = comptime @typeInfo(T); - if (comptime tyinfo == .pointer) { - if (comptime tyinfo.pointer.size == .one) { - const TT = std.meta.Child(T); - return bun.create(allocator, TT, deepClone(TT, this.*, allocator)); - } - if (comptime tyinfo.pointer.size == .slice) { - var slc = bun.handleOom(allocator.alloc(tyinfo.pointer.child, this.len)); - if (comptime bun.meta.isSimpleCopyType(tyinfo.pointer.child) or tyinfo.pointer.child == []const u8) { - @memcpy(slc, this.*); - } else { - for (this.*, 0..) |*e, i| { - slc[i] = deepClone(tyinfo.pointer.child, e, allocator); - } - } - return slc; - } - @compileError("Deep clone not supported for this kind of pointer: " ++ @tagName(tyinfo.pointer.size) ++ " (" ++ @typeName(T) ++ ")"); - } - if (comptime tyinfo == .optional) { - const TT = std.meta.Child(T); - if (this.* != null) return deepClone(TT, &this.*.?, allocator); - return null; - } - if (comptime bun.meta.isSimpleCopyType(T)) { - return this.*; - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - return switch (result.list) { - .array_list => css.deepClone(result.child, allocator, this), - .baby_list => this.deepCloneInfallible(allocator), - .small_list => this.deepClone(allocator), - }; - } - // Strings in the CSS parser are always arena allocated - // So it is safe to skip const strings as they will never be mutated - if (comptime T == []const u8) { - return this.*; - } - - if (!@hasDecl(T, "deepClone")) { - @compileError(@typeName(T) ++ " does not have a deepClone() function"); - } - - return this.deepClone(allocator); -} - -pub inline fn tryFromAngle(comptime T: type, angle: Angle) ?T { - return switch (T) { - CSSNumber => CSSNumberFns.tryFromAngle(angle), - Angle => return Angle.tryFromAngle(angle), - else => T.tryFromAngle(angle), - }; -} - -pub inline fn trySign(comptime T: type, val: *const T) ?f32 { - return switch (T) { - CSSNumber => CSSNumberFns.sign(val), - else => { - if (@hasDecl(T, "sign")) return T.sign(val); - return T.trySign(val); - }, - }; -} - -pub inline fn tryMap( - comptime T: type, - val: *const T, - comptime map_fn: *const fn (a: f32) f32, -) ?T { - return switch (T) { - CSSNumber => map_fn(val.*), - else => { - if (@hasDecl(T, "map")) return T.map(val, map_fn); - return T.tryMap(val, map_fn); - }, - }; -} - -pub inline fn tryOpTo( - comptime T: type, - comptime R: type, - lhs: *const T, - rhs: *const T, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R, -) ?R { - return switch (T) { - CSSNumber => op_fn(ctx, lhs.*, rhs.*), - else => { - if (@hasDecl(T, "opTo")) return T.opTo(lhs, rhs, R, ctx, op_fn); - return T.tryOpTo(lhs, rhs, R, ctx, op_fn); - }, - }; -} - -pub inline fn tryOp( - comptime T: type, - lhs: *const T, - rhs: *const T, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, -) ?T { - return switch (T) { - Angle => Angle.tryOp(lhs, rhs, ctx, op_fn), - CSSNumber => op_fn(ctx, lhs.*, rhs.*), - else => { - if (@hasDecl(T, "op")) return T.op(lhs, rhs, ctx, op_fn); - return T.tryOp(lhs, rhs, ctx, op_fn); - }, - }; -} - -pub inline fn partialCmp(comptime T: type, lhs: *const T, rhs: *const T) ?std.math.Order { - return switch (T) { - f32 => partialCmpF32(lhs, rhs), - CSSInteger => std.math.order(lhs.*, rhs.*), - css_values.angle.Angle => css_values.angle.Angle.partialCmp(lhs, rhs), - else => T.partialCmp(lhs, rhs), - }; -} - -pub inline fn partialCmpF32(lhs: *const f32, rhs: *const f32) ?std.math.Order { - const lte = lhs.* <= rhs.*; - const rte = lhs.* >= rhs.*; - if (!lte and !rte) return null; - if (!lte and rte) return .gt; - if (lte and !rte) return .lt; - return .eq; -} - -pub const HASH_SEED: u64 = 0; - -pub fn hashArrayList(comptime V: type, this: *const ArrayList(V), hasher: *std.hash.Wyhash) void { - for (this.items) |*item| { - hash(V, item, hasher); - } -} -pub fn hashBabyList(comptime V: type, this: *const bun.BabyList(V), hasher: *std.hash.Wyhash) void { - for (this.sliceConst()) |*item| { - hash(V, item, hasher); - } -} - -pub fn hasHash(comptime T: type) bool { - const tyinfo = @typeInfo(T); - if (comptime T == []const u8) return true; - if (comptime bun.meta.isSimpleEqlType(T)) return true; - if (tyinfo == .pointer) { - const TT = std.meta.Child(T); - return hasHash(TT); - } - if (tyinfo == .optional) { - const TT = std.meta.Child(T); - return hasHash(TT); - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - switch (result.list) { - .array_list => return true, - .baby_list => return true, - .small_list => return true, - } - } - return switch (T) { - else => @hasDecl(T, "hash"), - }; -} - -pub fn hash(comptime T: type, this: *const T, hasher: *std.hash.Wyhash) void { - if (comptime T == void) return; - const tyinfo = @typeInfo(T); - if (comptime tyinfo == .pointer and T != []const u8) { - const TT = std.meta.Child(T); - if (tyinfo.pointer.size == .one) { - return hash(TT, this.*, hasher); - } else if (tyinfo.pointer.size == .slice) { - for (this.*) |*item| { - hash(TT, item, hasher); - } - return; - } else { - @compileError("Can't hash this pointer type: " ++ @typeName(T)); - } - } - if (comptime @typeInfo(T) == .optional) { - const TT = std.meta.Child(T); - if (this.* != null) return hash(TT, &this.*.?, hasher); - return; - } - if (comptime bun.meta.looksLikeListContainerType(T)) |result| { - switch (result.list) { - .array_list => return hashArrayList(result.child, this, hasher), - .baby_list => return hashBabyList(result.child, this, hasher), - .small_list => return this.hash(hasher), - } - } - if (comptime bun.meta.isSimpleEqlType(T)) { - const bytes = std.mem.asBytes(&this); - hasher.update(bytes); - return; - } - return switch (T) { - []const u8 => hasher.update(this.*), - else => T.hash(this, hasher), - }; -} - -const css = @import("./css_parser.zig"); -const CSSInteger = css.CSSInteger; -const CSSIntegerFns = css.CSSIntegerFns; -const CSSNumber = css.CSSNumber; -const CSSNumberFns = css.CSSNumberFns; -const CustomIdent = css.CustomIdent; -const CustomIdentFns = css.CustomIdentFns; -const DashedIdent = css.DashedIdent; -const DashedIdentFns = css.DashedIdentFns; -const Ident = css.Ident; -const IdentFns = css.IdentFns; -const Parser = css.Parser; -const ParserOptions = css.ParserOptions; -const PrintErr = css.PrintErr; -const Printer = css.Printer; -const Result = css.Result; -const VendorPrefix = css.VendorPrefix; -const css_values = css.css_values; -const Angle = css_values.angle.Angle; - -const bun = @import("bun"); -const logger = bun.logger; - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/logical.zig b/src/css/logical.zig deleted file mode 100644 index eb54072ca5d4..000000000000 --- a/src/css/logical.zig +++ /dev/null @@ -1,26 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const Error = css.Error; - -pub const PropertyCategory = enum { - logical, - physical, - - pub fn default() PropertyCategory { - return .physical; - } -}; - -pub const LogicalGroup = enum { - border_color, - border_style, - border_width, - border_radius, - margin, - scroll_margin, - padding, - scroll_padding, - inset, - size, - min_size, - max_size, -}; diff --git a/src/css/media_query.zig b/src/css/media_query.zig deleted file mode 100644 index 171a0d195aad..000000000000 --- a/src/css/media_query.zig +++ /dev/null @@ -1,1568 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const Error = css.Error; - -const Length = css.css_values.length.Length; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const CSSInteger = css.css_values.number.CSSInteger; -const CSSIntegerFns = css.css_values.number.CSSIntegerFns; -const Resolution = css.css_values.resolution.Resolution; -const Ratio = css.css_values.ratio.Ratio; -const Ident = css.css_values.ident.Ident; -const IdentFns = css.css_values.ident.IdentFns; -const EnvironmentVariable = css.css_properties.custom.EnvironmentVariable; -const DashedIdent = css.css_values.ident.DashedIdent; -const DashedIdentFns = css.css_values.ident.DashedIdentFns; - -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Result = css.Result; - -pub fn ValidQueryCondition(comptime T: type) void { - // fn parse_feature<'t>(input: &mut Parser<'i, 't>) -> Result>>; - _ = T.parseFeature; - // fn create_negation(condition: Box) -> Self; - _ = T.createNegation; - // fn create_operation(operator: Operator, conditions: Vec) -> Self; - _ = T.createOperation; - // fn parse_style_query<'t>(input: &mut Parser<'i, 't>) -> Result>> { - _ = T.parseStyleQuery; - // fn needs_parens(&self, parent_operator: Option, targets: &Targets) -> bool; - _ = T.needsParens; -} - -/// A [media query list](https://drafts.csswg.org/mediaqueries/#mq-list). -pub const MediaList = struct { - /// The list of media queries. - media_queries: ArrayList(MediaQuery) = .{}, - - /// Parse a media query list from CSS. - pub fn parse(input: *css.Parser) Result(MediaList) { - var media_queries = ArrayList(MediaQuery){}; - while (true) { - const mq = switch (input.parseUntilBefore(css.Delimiters{ .comma = true }, MediaQuery, {}, css.voidWrap(MediaQuery, MediaQuery.parse))) { - .result => |v| v, - .err => |e| { - if (e.kind == .basic and e.kind.basic == .end_of_input) break; - return .{ .err = e }; - }, - }; - bun.handleOom(media_queries.append(input.allocator(), mq)); - - if (input.next().asValue()) |tok| { - if (tok.* != .comma) { - bun.Output.panic("Unreachable code: expected a comma after parsing a MediaQuery.\n\nThis is a bug in Bun's CSS parser. Please file a bug report at https://github.com/oven-sh/bun/issues/new/choose", .{}); - } - } else break; - } - - return .{ .result = MediaList{ .media_queries = media_queries } }; - } - - pub fn toCss(this: *const MediaList, dest: *css.Printer) PrintErr!void { - if (this.media_queries.items.len == 0) { - return dest.writeStr("not all"); - } - - var first = true; - for (this.media_queries.items) |*query| { - if (!first) { - try dest.delim(',', false); - } - first = false; - try query.toCss(dest); - } - return; - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn eql(lhs: *const MediaList, rhs: *const MediaList) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const MediaList, allocator: std.mem.Allocator) MediaList { - return MediaList{ - .media_queries = css.deepClone(MediaQuery, allocator, &this.media_queries), - }; - } - - pub fn cloneWithImportRecords( - this: *const @This(), - allocator: std.mem.Allocator, - _: *bun.BabyList(bun.ImportRecord), - ) @This() { - return deepClone(this, allocator); - } - - /// Returns whether the media query list always matches. - pub fn alwaysMatches(this: *const MediaList) bool { - // If the media list is empty, it always matches. - return this.media_queries.items.len == 0 or brk: { - for (this.media_queries.items) |*query| { - if (!query.alwaysMatches()) break :brk false; - } - break :brk true; - }; - } - - /// Returns whether the media query list never matches. - pub fn neverMatches(this: *const MediaList) bool { - return this.media_queries.items.len > 0 and brk: { - for (this.media_queries.items) |*query| { - if (!query.neverMatches()) break :brk false; - } - break :brk true; - }; - } -}; - -/// A binary `and` or `or` operator. -pub const Operator = enum { - /// The `and` operator. - @"and", - /// The `or` operator. - @"or", - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -/// A [media query](https://drafts.csswg.org/mediaqueries/#media). -pub const MediaQuery = struct { - /// The qualifier for this query. - qualifier: ?Qualifier, - /// The media type for this query, that can be known, unknown, or "all". - media_type: MediaType, - /// The condition that this media query contains. This cannot have `or` - /// in the first level. - condition: ?MediaCondition, - // ~toCssImpl - const This = @This(); - - pub fn deepClone(this: *const MediaQuery, allocator: std.mem.Allocator) MediaQuery { - return MediaQuery{ - .qualifier = if (this.qualifier) |q| q else null, - .media_type = this.media_type, - .condition = if (this.condition) |*c| c.deepClone(allocator) else null, - }; - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - /// Returns whether the media query is guaranteed to always match. - pub fn alwaysMatches(this: *const MediaQuery) bool { - return this.qualifier == null and this.media_type == .all and this.condition == null; - } - - pub fn parse(input: *css.Parser) Result(MediaQuery) { - const Fn = struct { - pub fn tryParseFn(i: *css.Parser) Result(struct { ?Qualifier, ?MediaType }) { - const qualifier = switch (i.tryParse(Qualifier.parse, .{})) { - .result => |vv| vv, - .err => null, - }; - const media_type = switch (MediaType.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ qualifier, media_type } }; - } - }; - const qualifier, const explicit_media_type = switch (input.tryParse(Fn.tryParseFn, .{})) { - .result => |v| v, - .err => .{ null, null }, - }; - - const condition = if (explicit_media_type == null) - switch (MediaCondition.parseWithFlags(input, .{ .allow_or = true })) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } - else if (input.tryParse(css.Parser.expectIdentMatching, .{"and"}).isOk()) - switch (MediaCondition.parseWithFlags(input, .{})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } - else - null; - - const media_type = explicit_media_type orelse MediaType.all; - - return .{ - .result = MediaQuery{ - .qualifier = qualifier, - .media_type = media_type, - .condition = condition, - }, - }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - if (this.qualifier) |qual| { - try qual.toCss(dest); - try dest.writeChar(' '); - } - - switch (this.media_type) { - .all => { - // We need to print "all" if there's a qualifier, or there's - // just an empty list of expressions. - // - // Otherwise, we'd serialize media queries like "(min-width: - // 40px)" in "all (min-width: 40px)", which is unexpected. - if (this.qualifier != null or this.condition == null) { - try dest.writeStr("all"); - } - }, - .print => { - try dest.writeStr("print"); - }, - .screen => { - try dest.writeStr("screen"); - }, - .custom => |desc| { - try dest.writeStr(desc); - }, - } - - const condition = if (this.condition) |*cond| cond else return; - - const needs_parens = if (this.media_type != .all or this.qualifier != null) needs_parens: { - try dest.writeStr(" and "); - break :needs_parens condition.* == .operation and condition.operation.operator != .@"and"; - } else false; - - return toCssWithParensIfNeeded(condition, dest, needs_parens); - } - - pub fn neverMatches(this: *const MediaQuery) bool { - return this.qualifier == .not and this.media_type == .all and this.condition == null; - } -}; - -/// Flags for `parse_query_condition`. -pub const QueryConditionFlags = packed struct(u8) { - /// Whether to allow top-level "or" boolean logic. - allow_or: bool = false, - /// Whether to allow style container queries. - allow_style: bool = false, - __unused: u6 = 0, -}; - -pub fn toCssWithParensIfNeeded( - v: anytype, - dest: *Printer, - needs_parens: bool, -) PrintErr!void { - if (needs_parens) { - try dest.writeChar('('); - } - try v.toCss(dest); - if (needs_parens) { - try dest.writeChar(')'); - } - return; -} - -/// A [media query qualifier](https://drafts.csswg.org/mediaqueries/#mq-prefix). -pub const Qualifier = enum { - /// Prevents older browsers from matching the media query. - only, - /// Negates a media query. - not, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// A [media type](https://drafts.csswg.org/mediaqueries/#media-types) within a media query. -pub const MediaType = union(enum) { - /// Matches all devices. - all, - /// Matches printers, and devices intended to reproduce a printed - /// display, such as a web browser showing a document in “Print Preview”. - print, - /// Matches all devices that aren’t matched by print. - screen, - /// An unknown media type. - custom: []const u8, - - pub fn parse(input: *css.Parser) Result(MediaType) { - const name = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = MediaType.fromStr(name) }; - } - - pub fn fromStr(name: []const u8) MediaType { - const Enumerations = enum { all, print, screen }; - const Map = comptime bun.ComptimeEnumMap(Enumerations); - if (Map.getASCIIICaseInsensitive(name)) |x| return switch (x) { - .all => .all, - .print => .print, - .screen => .screen, - }; - return .{ .custom = name }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } -}; - -pub fn operationToCss(comptime QueryCondition: type, operator: Operator, conditions: *const ArrayList(QueryCondition), dest: *Printer) PrintErr!void { - ValidQueryCondition(QueryCondition); - const first = &conditions.items[0]; - try toCssWithParensIfNeeded(first, dest, first.needsParens(operator, &dest.targets)); - if (conditions.items.len == 1) return; - for (conditions.items[1..]) |*item| { - try dest.writeChar(' '); - try operator.toCss(dest); - try dest.writeChar(' '); - try toCssWithParensIfNeeded(item, dest, item.needsParens(operator, &dest.targets)); - } - return; -} - -/// Represents a media condition. -/// -/// Implements QueryCondition interface. -pub const MediaCondition = union(enum) { - feature: MediaFeature, - not: *MediaCondition, - operation: struct { - operator: Operator, - conditions: ArrayList(MediaCondition), - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - }, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - switch (this.*) { - .feature => |*f| { - try f.toCss(dest); - }, - .not => |c| { - try dest.writeStr("not "); - try toCssWithParensIfNeeded(c, dest, c.needsParens(null, &dest.targets)); - }, - .operation => |operation| { - try operationToCss(MediaCondition, operation.operator, &operation.conditions, dest); - }, - } - - return; - } - - /// QueryCondition.parseFeature - pub fn parseFeature(input: *css.Parser) Result(MediaCondition) { - const feature = switch (MediaFeature.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = MediaCondition{ .feature = feature } }; - } - - /// QueryCondition.createNegation - pub fn createNegation(condition: *MediaCondition) MediaCondition { - return MediaCondition{ .not = condition }; - } - - /// QueryCondition.createOperation - pub fn createOperation(operator: Operator, conditions: ArrayList(MediaCondition)) MediaCondition { - return MediaCondition{ - .operation = .{ - .operator = operator, - .conditions = conditions, - }, - }; - } - - /// QueryCondition.parseStyleQuery - pub fn parseStyleQuery(input: *css.Parser) Result(MediaCondition) { - return .{ .err = input.newErrorForNextToken() }; - } - - /// QueryCondition.needsParens - pub fn needsParens(this: *const MediaCondition, parent_operator: ?Operator, targets: *const css.targets.Targets) bool { - return switch (this.*) { - .not => true, - .operation => |operation| operation.operator != parent_operator, - .feature => |f| f.needsParens(parent_operator, targets), - }; - } - - pub fn parseWithFlags(input: *css.Parser, flags: QueryConditionFlags) Result(MediaCondition) { - return parseQueryCondition(MediaCondition, input, flags); - } - - pub fn deepClone(this: *const MediaCondition, allocator: std.mem.Allocator) MediaCondition { - return switch (this.*) { - .feature => |*f| MediaCondition{ .feature = f.deepClone(allocator) }, - .not => |c| MediaCondition{ .not = bun.create(allocator, MediaCondition, c.deepClone(allocator)) }, - .operation => |op| MediaCondition{ - .operation = .{ - .operator = op.operator, - .conditions = css.deepClone(MediaCondition, allocator, &op.conditions), - }, - }, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// Parse a single query condition. -pub fn parseQueryCondition( - comptime QueryCondition: type, - input: *css.Parser, - flags: QueryConditionFlags, -) Result(QueryCondition) { - const location = input.currentSourceLocation(); - const is_negation, const is_style = brk: { - const tok = switch (input.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .open_paren => break :brk .{ false, false }, - .ident => |ident| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "not")) break :brk .{ true, false }; - }, - .function => |f| { - if (flags.allow_style and - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "style")) - { - break :brk .{ false, true }; - } - }, - else => {}, - } - return .{ .err = location.newUnexpectedTokenError(tok.*) }; - }; - - const first_condition: QueryCondition = first_condition: { - const val: u8 = @as(u8, @intFromBool(is_negation)) << 1 | @as(u8, @intFromBool(is_style)); - // (is_negation, is_style) - switch (val) { - // (true, false) - 0b10 => { - const inner_condition = switch (parseParensOrFunction(QueryCondition, input, flags)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = QueryCondition.createNegation(bun.create(input.allocator(), QueryCondition, inner_condition)) }; - }, - // (true, true) - 0b11 => { - const inner_condition = switch (QueryCondition.parseStyleQuery(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = QueryCondition.createNegation(bun.create(input.allocator(), QueryCondition, inner_condition)) }; - }, - 0b00 => break :first_condition switch (parseParenBlock(QueryCondition, input, flags)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - 0b01 => break :first_condition switch (QueryCondition.parseStyleQuery(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - else => unreachable, - } - }; - - const operator: Operator = if (input.tryParse(Operator.parse, .{}).asValue()) |op| - op - else - return .{ .result = first_condition }; - - if (!flags.allow_or and operator == .@"or") { - return .{ .err = location.newUnexpectedTokenError(css.Token{ .ident = "or" }) }; - } - - var conditions = ArrayList(QueryCondition){}; - conditions.append( - input.allocator(), - first_condition, - ) catch unreachable; - conditions.append( - input.allocator(), - switch (parseParensOrFunction(QueryCondition, input, flags)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - ) catch unreachable; - - const delim = switch (operator) { - .@"and" => "and", - .@"or" => "or", - }; - - while (true) { - if (input.tryParse(css.Parser.expectIdentMatching, .{delim}).isErr()) { - return .{ .result = QueryCondition.createOperation(operator, conditions) }; - } - - conditions.append( - input.allocator(), - switch (parseParensOrFunction(QueryCondition, input, flags)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - ) catch unreachable; - } -} - -/// Parse a media condition in parentheses, or a style() function. -pub fn parseParensOrFunction( - comptime QueryCondition: type, - input: *css.Parser, - flags: QueryConditionFlags, -) Result(QueryCondition) { - const location = input.currentSourceLocation(); - const t = switch (input.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (t.*) { - .open_paren => return parseParenBlock(QueryCondition, input, flags), - .function => |f| { - if (flags.allow_style and - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "style")) - { - return QueryCondition.parseStyleQuery(input); - } - }, - else => {}, - } - return .{ .err = location.newUnexpectedTokenError(t.*) }; -} - -fn parseParenBlock( - comptime QueryCondition: type, - input: *css.Parser, - flags: QueryConditionFlags, -) Result(QueryCondition) { - const Closure = struct { - flags: QueryConditionFlags, - pub fn parseNestedBlockFn(this: *@This(), i: *css.Parser) Result(QueryCondition) { - if (i.tryParse(@This().tryParseFn, .{this}).asValue()) |inner| { - return .{ .result = inner }; - } - - return QueryCondition.parseFeature(i); - } - - pub fn tryParseFn(i: *css.Parser, this: *@This()) Result(QueryCondition) { - return parseQueryCondition(QueryCondition, i, this.flags); - } - }; - - var closure = Closure{ - .flags = flags, - }; - return input.parseNestedBlock(QueryCondition, &closure, Closure.parseNestedBlockFn); -} - -/// A [media feature](https://drafts.csswg.org/mediaqueries/#typedef-media-feature) -pub const MediaFeature = QueryFeature(MediaFeatureId); - -pub const MediaFeatureId = enum { - /// The [width](https://w3c.github.io/csswg-drafts/mediaqueries-5/#width) media feature. - width, - /// The [height](https://w3c.github.io/csswg-drafts/mediaqueries-5/#height) media feature. - height, - /// The [aspect-ratio](https://w3c.github.io/csswg-drafts/mediaqueries-5/#aspect-ratio) media feature. - @"aspect-ratio", - /// The [orientation](https://w3c.github.io/csswg-drafts/mediaqueries-5/#orientation) media feature. - orientation, - /// The [overflow-block](https://w3c.github.io/csswg-drafts/mediaqueries-5/#overflow-block) media feature. - @"overflow-block", - /// The [overflow-inline](https://w3c.github.io/csswg-drafts/mediaqueries-5/#overflow-inline) media feature. - @"overflow-inline", - /// The [horizontal-viewport-segments](https://w3c.github.io/csswg-drafts/mediaqueries-5/#horizontal-viewport-segments) media feature. - @"horizontal-viewport-segments", - /// The [vertical-viewport-segments](https://w3c.github.io/csswg-drafts/mediaqueries-5/#vertical-viewport-segments) media feature. - @"vertical-viewport-segments", - /// The [display-mode](https://w3c.github.io/csswg-drafts/mediaqueries-5/#display-mode) media feature. - @"display-mode", - /// The [resolution](https://w3c.github.io/csswg-drafts/mediaqueries-5/#resolution) media feature. - resolution, - /// The [scan](https://w3c.github.io/csswg-drafts/mediaqueries-5/#scan) media feature. - scan, - /// The [grid](https://w3c.github.io/csswg-drafts/mediaqueries-5/#grid) media feature. - grid, - /// The [update](https://w3c.github.io/csswg-drafts/mediaqueries-5/#update) media feature. - update, - /// The [environment-blending](https://w3c.github.io/csswg-drafts/mediaqueries-5/#environment-blending) media feature. - @"environment-blending", - /// The [color](https://w3c.github.io/csswg-drafts/mediaqueries-5/#color) media feature. - color, - /// The [color-index](https://w3c.github.io/csswg-drafts/mediaqueries-5/#color-index) media feature. - @"color-index", - /// The [monochrome](https://w3c.github.io/csswg-drafts/mediaqueries-5/#monochrome) media feature. - monochrome, - /// The [color-gamut](https://w3c.github.io/csswg-drafts/mediaqueries-5/#color-gamut) media feature. - @"color-gamut", - /// The [dynamic-range](https://w3c.github.io/csswg-drafts/mediaqueries-5/#dynamic-range) media feature. - @"dynamic-range", - /// The [inverted-colors](https://w3c.github.io/csswg-drafts/mediaqueries-5/#inverted-colors) media feature. - @"inverted-colors", - /// The [pointer](https://w3c.github.io/csswg-drafts/mediaqueries-5/#pointer) media feature. - pointer, - /// The [hover](https://w3c.github.io/csswg-drafts/mediaqueries-5/#hover) media feature. - hover, - /// The [any-pointer](https://w3c.github.io/csswg-drafts/mediaqueries-5/#any-pointer) media feature. - @"any-pointer", - /// The [any-hover](https://w3c.github.io/csswg-drafts/mediaqueries-5/#any-hover) media feature. - @"any-hover", - /// The [nav-controls](https://w3c.github.io/csswg-drafts/mediaqueries-5/#nav-controls) media feature. - @"nav-controls", - /// The [video-color-gamut](https://w3c.github.io/csswg-drafts/mediaqueries-5/#video-color-gamut) media feature. - @"video-color-gamut", - /// The [video-dynamic-range](https://w3c.github.io/csswg-drafts/mediaqueries-5/#video-dynamic-range) media feature. - @"video-dynamic-range", - /// The [scripting](https://w3c.github.io/csswg-drafts/mediaqueries-5/#scripting) media feature. - scripting, - /// The [prefers-reduced-motion](https://w3c.github.io/csswg-drafts/mediaqueries-5/#prefers-reduced-motion) media feature. - @"prefers-reduced-motion", - /// The [prefers-reduced-transparency](https://w3c.github.io/csswg-drafts/mediaqueries-5/#prefers-reduced-transparency) media feature. - @"prefers-reduced-transparency", - /// The [prefers-contrast](https://w3c.github.io/csswg-drafts/mediaqueries-5/#prefers-contrast) media feature. - @"prefers-contrast", - /// The [forced-colors](https://w3c.github.io/csswg-drafts/mediaqueries-5/#forced-colors) media feature. - @"forced-colors", - /// The [prefers-color-scheme](https://w3c.github.io/csswg-drafts/mediaqueries-5/#prefers-color-scheme) media feature. - @"prefers-color-scheme", - /// The [prefers-reduced-data](https://w3c.github.io/csswg-drafts/mediaqueries-5/#prefers-reduced-data) media feature. - @"prefers-reduced-data", - /// The [device-width](https://w3c.github.io/csswg-drafts/mediaqueries-5/#device-width) media feature. - @"device-width", - /// The [device-height](https://w3c.github.io/csswg-drafts/mediaqueries-5/#device-height) media feature. - @"device-height", - /// The [device-aspect-ratio](https://w3c.github.io/csswg-drafts/mediaqueries-5/#device-aspect-ratio) media feature. - @"device-aspect-ratio", - - /// The non-standard -webkit-device-pixel-ratio media feature. - @"-webkit-device-pixel-ratio", - /// The non-standard -moz-device-pixel-ratio media feature. - @"-moz-device-pixel-ratio", - - pub const valueType = css.DeriveValueType(@This(), ValueTypeMap).valueType; - - pub const ValueTypeMap = .{ - .width = MediaFeatureType.length, - .height = MediaFeatureType.length, - .@"aspect-ratio" = MediaFeatureType.ratio, - .orientation = MediaFeatureType.ident, - .@"overflow-block" = MediaFeatureType.ident, - .@"overflow-inline" = MediaFeatureType.ident, - .@"horizontal-viewport-segments" = MediaFeatureType.integer, - .@"vertical-viewport-segments" = MediaFeatureType.integer, - .@"display-mode" = MediaFeatureType.ident, - .resolution = MediaFeatureType.resolution, - .scan = MediaFeatureType.ident, - .grid = MediaFeatureType.boolean, - .update = MediaFeatureType.ident, - .@"environment-blending" = MediaFeatureType.ident, - .color = MediaFeatureType.integer, - .@"color-index" = MediaFeatureType.integer, - .monochrome = MediaFeatureType.integer, - .@"color-gamut" = MediaFeatureType.ident, - .@"dynamic-range" = MediaFeatureType.ident, - .@"inverted-colors" = MediaFeatureType.ident, - .pointer = MediaFeatureType.ident, - .hover = MediaFeatureType.ident, - .@"any-pointer" = MediaFeatureType.ident, - .@"any-hover" = MediaFeatureType.ident, - .@"nav-controls" = MediaFeatureType.ident, - .@"video-color-gamut" = MediaFeatureType.ident, - .@"video-dynamic-range" = MediaFeatureType.ident, - .scripting = MediaFeatureType.ident, - .@"prefers-reduced-motion" = MediaFeatureType.ident, - .@"prefers-reduced-transparency" = MediaFeatureType.ident, - .@"prefers-contrast" = MediaFeatureType.ident, - .@"forced-colors" = MediaFeatureType.ident, - .@"prefers-color-scheme" = MediaFeatureType.ident, - .@"prefers-reduced-data" = MediaFeatureType.ident, - .@"device-width" = MediaFeatureType.length, - .@"device-height" = MediaFeatureType.length, - .@"device-aspect-ratio" = MediaFeatureType.ratio, - .@"-webkit-device-pixel-ratio" = MediaFeatureType.number, - .@"-moz-device-pixel-ratio" = MediaFeatureType.number, - }; - - pub fn toCssWithPrefix( - this: *const MediaFeatureId, - prefix: []const u8, - dest: *Printer, - ) PrintErr!void { - switch (this.*) { - .@"-webkit-device-pixel-ratio" => { - return dest.writeFmt("-webkit-{s}device-pixel-ratio", .{prefix}); - }, - else => { - try dest.writeStr(prefix); - return this.toCss(dest); - }, - } - } - - pub inline fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } -}; - -pub fn QueryFeature(comptime FeatureId: type) type { - return union(enum) { - /// A plain media feature, e.g. `(min-width: 240px)`. - plain: struct { - /// The name of the feature. - name: MediaFeatureName(FeatureId), - /// The feature value. - value: MediaFeatureValue, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn __generateHash() void {} - }, - - /// A boolean feature, e.g. `(hover)`. - boolean: struct { - /// The name of the feature. - name: MediaFeatureName(FeatureId), - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn __generateHash() void {} - }, - - /// A range, e.g. `(width > 240px)`. - range: struct { - /// The name of the feature. - name: MediaFeatureName(FeatureId), - /// A comparator. - operator: MediaFeatureComparison, - /// The feature value. - value: MediaFeatureValue, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn __generateHash() void {} - }, - - /// An interval, e.g. `(120px < width < 240px)`. - interval: struct { - /// The name of the feature. - name: MediaFeatureName(FeatureId), - /// A start value. - start: MediaFeatureValue, - /// A comparator for the start value. - start_operator: MediaFeatureComparison, - /// The end value. - end: MediaFeatureValue, - /// A comparator for the end value. - end_operator: MediaFeatureComparison, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn __generateHash() void {} - }, - - const This = @This(); - - pub fn deepClone(this: *const This, allocator: std.mem.Allocator) This { - return switch (this.*) { - .plain => .{ - .plain = .{ - .name = this.plain.name, - .value = this.plain.value.deepClone(allocator), - }, - }, - .boolean => .{ - .boolean = .{ - .name = this.boolean.name, - }, - }, - .range => .{ - .range = .{ - .name = this.range.name, - .operator = this.range.operator, - .value = this.range.value.deepClone(allocator), - }, - }, - .interval => .{ - .interval = .{ - .name = this.interval.name, - .start = this.interval.start.deepClone(allocator), - .start_operator = this.interval.start_operator, - .end = this.interval.end.deepClone(allocator), - .end_operator = this.interval.end_operator, - }, - }, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn needsParens(this: *const This, parent_operator: ?Operator, targets: *const css.Targets) bool { - return parent_operator != .@"and" and - this.* == .interval and - targets.shouldCompileSame(.media_interval_syntax); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - try dest.writeChar('('); - - switch (this.*) { - .boolean => { - try this.boolean.name.toCss(dest); - }, - .plain => { - try this.plain.name.toCss(dest); - try dest.delim(':', false); - try this.plain.value.toCss(dest); - }, - .range => { - // If range syntax is unsupported, use min/max prefix if possible. - if (dest.targets.shouldCompileSame(.media_range_syntax)) { - return writeMinMax( - &this.range.operator, - FeatureId, - &this.range.name, - &this.range.value, - dest, - ); - } - try this.range.name.toCss(dest); - try this.range.operator.toCss(dest); - try this.range.value.toCss(dest); - }, - .interval => |interval| { - if (dest.targets.shouldCompileSame(.media_interval_syntax)) { - try writeMinMax( - &interval.start_operator.opposite(), - FeatureId, - &interval.name, - &interval.start, - dest, - ); - try dest.writeStr(" and ("); - return writeMinMax( - &interval.end_operator, - FeatureId, - &interval.name, - &interval.end, - dest, - ); - } - - try interval.start.toCss(dest); - try interval.start_operator.toCss(dest); - try interval.name.toCss(dest); - try interval.end_operator.toCss(dest); - try interval.end.toCss(dest); - }, - } - - return dest.writeChar(')'); - } - - pub fn parse(input: *css.Parser) Result(This) { - switch (input.tryParse(parseNameFirst, .{})) { - .result => |res| { - return .{ .result = res }; - }, - .err => |e| { - if (e.kind == .custom and e.kind.custom == .invalid_media_query) { - return .{ .err = e }; - } - return parseValueFirst(input); - }, - } - return .success; - } - - pub fn parseNameFirst(input: *css.Parser) Result(This) { - const name, const legacy_op = switch (MediaFeatureName(FeatureId).parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const operator = if (input.tryParse(consumeOperationOrColon, .{true}).asValue()) |operator| operator else return .{ - .result = .{ - .boolean = .{ .name = name }, - }, - }; - - if (operator != null and legacy_op != null) { - return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }; - } - - const value = switch (MediaFeatureValue.parse(input, name.valueType())) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (!value.checkType(name.valueType())) { - return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }; - } - - if (operator orelse legacy_op) |op| { - if (!name.valueType().allowsRanges()) { - return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }; - } - - return .{ .result = .{ - .range = .{ - .name = name, - .operator = op, - .value = value, - }, - } }; - } else { - return .{ .result = .{ - .plain = .{ - .name = name, - .value = value, - }, - } }; - } - } - - pub fn parseValueFirst(input: *css.Parser) Result(This) { - // We need to find the feature name first so we know the type. - const start = input.state(); - const name = name: { - while (true) { - if (MediaFeatureName(FeatureId).parse(input).asValue()) |result| { - const name: MediaFeatureName(FeatureId) = result[0]; - const legacy_op: ?MediaFeatureComparison = result[1]; - if (legacy_op != null) { - return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }; - } - break :name name; - } - if (input.isExhausted()) { - return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }; - } - } - }; - - input.reset(&start); - - // Now we can parse the first value. - const value = switch (MediaFeatureValue.parse(input, name.valueType())) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const operator = switch (consumeOperationOrColon(input, false)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - // Skip over the feature name again. - { - const feature_name, const blah = switch (MediaFeatureName(FeatureId).parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - _ = blah; - bun.debugAssert(feature_name.eql(&name)); - } - - if (!name.valueType().allowsRanges() or !value.checkType(name.valueType())) { - return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }; - } - - if (input.tryParse(consumeOperationOrColon, .{false}).asValue()) |end_operator_| { - const start_operator = operator.?; - const end_operator = end_operator_.?; - // Start and end operators must be matching. - const GT: u8 = comptime @intFromEnum(MediaFeatureComparison.@"greater-than"); - const GTE: u8 = comptime @intFromEnum(MediaFeatureComparison.@"greater-than-equal"); - const LT: u8 = comptime @intFromEnum(MediaFeatureComparison.@"less-than"); - const LTE: u8 = comptime @intFromEnum(MediaFeatureComparison.@"less-than-equal"); - const check_val: u8 = @intFromEnum(start_operator) | @intFromEnum(end_operator); - switch (check_val) { - GT | GT, - GT | GTE, - GTE | GTE, - LT | LT, - LT | LTE, - LTE | LTE, - => {}, - else => return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }, - } - - const end_value = switch (MediaFeatureValue.parse(input, name.valueType())) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (!end_value.checkType(name.valueType())) { - return .{ .err = input.newCustomError(css.ParserError.invalid_media_query) }; - } - - return .{ .result = .{ - .interval = .{ - .name = name, - .start = value, - .start_operator = start_operator, - .end = end_value, - .end_operator = end_operator, - }, - } }; - } else { - const final_operator = operator.?.opposite(); - return .{ .result = .{ - .range = .{ - .name = name, - .operator = final_operator, - .value = value, - }, - } }; - } - } - }; -} - -/// Consumes an operation or a colon, or returns an error. -fn consumeOperationOrColon(input: *css.Parser, allow_colon: bool) Result(?MediaFeatureComparison) { - const location = input.currentSourceLocation(); - const first_delim = first_delim: { - const loc = input.currentSourceLocation(); - const next_token = switch (input.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (next_token.*) { - .colon => if (allow_colon) return .{ .result = null }, - .delim => |oper| break :first_delim oper, - else => {}, - } - return .{ .err = loc.newUnexpectedTokenError(next_token.*) }; - }; - - switch (first_delim) { - '=' => return .{ .result = .equal }, - '>' => { - if (input.tryParse(css.Parser.expectDelim, .{'='}).isOk()) { - return .{ .result = .@"greater-than-equal" }; - } - return .{ .result = .@"greater-than" }; - }, - '<' => { - if (input.tryParse(css.Parser.expectDelim, .{'='}).isOk()) { - return .{ .result = .@"less-than-equal" }; - } - return .{ .result = .@"less-than" }; - }, - else => return .{ .err = location.newUnexpectedTokenError(.{ .delim = first_delim }) }, - } -} - -pub const MediaFeatureComparison = enum(u8) { - /// `=` - equal = 1, - /// `>` - @"greater-than" = 2, - /// `>=` - @"greater-than-equal" = 4, - /// `<` - @"less-than" = 8, - /// `<=` - @"less-than-equal" = 16, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - switch (this.*) { - .equal => { - try dest.delim('-', true); - }, - .@"greater-than" => { - try dest.delim('>', true); - }, - .@"greater-than-equal" => { - try dest.whitespace(); - try dest.writeStr(">="); - try dest.whitespace(); - }, - .@"less-than" => { - try dest.delim('<', true); - }, - .@"less-than-equal" => { - try dest.whitespace(); - try dest.writeStr("<="); - try dest.whitespace(); - }, - } - } - - pub fn opposite(self: @This()) @This() { - return switch (self) { - .@"greater-than" => .@"less-than", - .@"greater-than-equal" => .@"less-than-equal", - .@"less-than" => .@"greater-than", - .@"less-than-equal" => .@"greater-than-equal", - .equal => .equal, - }; - } -}; - -/// [media feature value](https://drafts.csswg.org/mediaqueries/#typedef-mf-value) within a media query. -/// -/// See [MediaFeature](MediaFeature). -pub const MediaFeatureValue = union(enum) { - /// A length value. - length: Length, - /// A number value. - number: CSSNumber, - /// An integer value. - integer: CSSInteger, - /// A boolean value. - boolean: bool, - /// A resolution. - resolution: Resolution, - /// A ratio. - ratio: Ratio, - /// An identifier. - ident: Ident, - /// An environment variable reference. - env: EnvironmentVariable, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const MediaFeatureValue, allocator: std.mem.Allocator) MediaFeatureValue { - return switch (this.*) { - .length => |*l| .{ .length = l.deepClone(allocator) }, - .number => |n| .{ .number = n }, - .integer => |i| .{ .integer = i }, - .boolean => |b| .{ .boolean = b }, - .resolution => |r| .{ .resolution = r }, - .ratio => |r| .{ .ratio = r }, - .ident => |i| .{ .ident = i }, - .env => |*e| .{ .env = e.deepClone(allocator) }, - }; - } - - pub fn deinit(this: *MediaFeatureValue, allocator: std.mem.Allocator) void { - return switch (this.*) { - .length => |l| l.deinit(allocator), - .number => {}, - .integer => {}, - .boolean => {}, - .resolution => {}, - .ratio => {}, - .ident => {}, - .env => |*env| env.deinit(allocator), - }; - } - - pub fn toCss( - this: *const MediaFeatureValue, - dest: *Printer, - ) PrintErr!void { - switch (this.*) { - .length => |len| return len.toCss(dest), - .number => |num| return CSSNumberFns.toCss(&num, dest), - .integer => |int| return CSSIntegerFns.toCss(&int, dest), - .boolean => |b| { - if (b) { - return dest.writeChar('1'); - } else { - return dest.writeChar('0'); - } - }, - .resolution => |res| return res.toCss(dest), - .ratio => |ratio| return ratio.toCss(dest), - .ident => |id| return IdentFns.toCss(&id, dest), - .env => |*env| return EnvironmentVariable.toCss(env, dest, false), - } - } - - pub fn checkType(this: *const @This(), expected_type: MediaFeatureType) bool { - const vt = this.valueType(); - if (expected_type == .unknown or vt == .unknown) return true; - return expected_type == vt; - } - - /// Parses a single media query feature value, with an expected type. - /// If the type is unknown, pass MediaFeatureType::Unknown instead. - pub fn parse(input: *css.Parser, expected_type: MediaFeatureType) Result(MediaFeatureValue) { - if (input.tryParse(parseKnown, .{expected_type}).asValue()) |value| { - return .{ .result = value }; - } - - return parseUnknown(input); - } - - pub fn parseKnown(input: *css.Parser, expected_type: MediaFeatureType) Result(MediaFeatureValue) { - return .{ - .result = switch (expected_type) { - .boolean => { - const value = switch (CSSIntegerFns.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (value != 0 and value != 1) return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - return .{ .result = .{ .boolean = value == 1 } }; - }, - .number => .{ .number = switch (CSSNumberFns.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } }, - .integer => .{ .integer = switch (CSSIntegerFns.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } }, - .length => .{ .length = switch (Length.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } }, - .resolution => .{ .resolution = switch (Resolution.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } }, - .ratio => .{ .ratio = switch (Ratio.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } }, - .ident => .{ .ident = switch (IdentFns.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } }, - .unknown => return .{ .err = input.newCustomError(.invalid_value) }, - }, - }; - } - - pub fn parseUnknown(input: *css.Parser) Result(MediaFeatureValue) { - // Ratios are ambiguous with numbers because the second param is optional (e.g. 2/1 == 2). - // We require the / delimiter when parsing ratios so that 2/1 ends up as a ratio and 2 is - // parsed as a number. - if (input.tryParse(Ratio.parseRequired, .{}).asValue()) |ratio| return .{ .result = .{ .ratio = ratio } }; - - // Parse number next so that unitless values are not parsed as lengths. - if (input.tryParse(CSSNumberFns.parse, .{}).asValue()) |num| return .{ .result = .{ .number = num } }; - - if (input.tryParse(Length.parse, .{}).asValue()) |res| return .{ .result = .{ .length = res } }; - - if (input.tryParse(Resolution.parse, .{}).asValue()) |res| return .{ .result = .{ .resolution = res } }; - - if (input.tryParse(EnvironmentVariable.parse, .{}).asValue()) |env| return .{ .result = .{ .env = env } }; - - const ident = switch (IdentFns.parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = .{ .ident = ident } }; - } - - pub fn addF32(this: MediaFeatureValue, allocator: Allocator, other: f32) MediaFeatureValue { - return switch (this) { - .length => |len| .{ .length = len.add(allocator, Length.px(other)) }, - // .length => |len| .{ - // .length = .{ - // .value = .{ .px = other }, - // }, - // }, - .number => |num| .{ .number = num + other }, - .integer => |num| .{ .integer = num + if (css.signfns.isSignPositive(other)) @as(i32, 1) else @as(i32, -1) }, - .boolean => |v| .{ .boolean = v }, - .resolution => |res| .{ .resolution = res.addF32(allocator, other) }, - .ratio => |ratio| .{ .ratio = ratio.addF32(allocator, other) }, - .ident => |id| .{ .ident = id }, - .env => |env| .{ .env = env }, // TODO: calc support - }; - } - - pub fn valueType(this: *const MediaFeatureValue) MediaFeatureType { - return switch (this.*) { - .length => .length, - .number => .number, - .integer => .integer, - .boolean => .boolean, - .resolution => .resolution, - .ratio => .ratio, - .ident => .ident, - .env => .unknown, - }; - } -}; - -/// The type of a media feature. -pub const MediaFeatureType = enum { - /// A length value. - length, - /// A number value. - number, - /// An integer value. - integer, - /// A boolean value, either 0 or 1. - boolean, - /// A resolution. - resolution, - /// A ratio. - ratio, - /// An identifier. - ident, - /// An unknown type. - unknown, - - pub fn allowsRanges(this: MediaFeatureType) bool { - return switch (this) { - .length, .number, .integer, .resolution, .ratio, .unknown => true, - .boolean, .ident => false, - }; - } -}; - -pub fn MediaFeatureName(comptime FeatureId: type) type { - return union(enum) { - /// A standard media query feature identifier. - standard: FeatureId, - - /// A custom author-defined environment variable. - custom: DashedIdent, - - /// An unknown environment variable. - unknown: Ident, - - const This = @This(); - - pub fn eql(lhs: *const This, rhs: *const This) bool { - if (@intFromEnum(lhs.*) != @intFromEnum(rhs.*)) return false; - return switch (lhs.*) { - .standard => |fid| fid == rhs.standard, - .custom => |ident| bun.strings.eql(ident.v, rhs.custom.v), - .unknown => |ident| bun.strings.eql(ident.v, rhs.unknown.v), - }; - } - - pub fn valueType(this: *const This) MediaFeatureType { - return switch (this.*) { - .standard => |standard| standard.valueType(), - else => .unknown, - }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - return switch (this.*) { - .standard => |v| v.toCss(dest), - .custom => |d| DashedIdentFns.toCss(&d, dest), - .unknown => |v| IdentFns.toCss(&v, dest), - }; - } - - pub fn toCssWithPrefix(this: *const This, prefix: []const u8, dest: *Printer) PrintErr!void { - return switch (this.*) { - .standard => |v| v.toCssWithPrefix(prefix, dest), - .custom => |d| { - try dest.writeStr(prefix); - return DashedIdentFns.toCss(&d, dest); - }, - .unknown => |v| { - try dest.writeStr(prefix); - return IdentFns.toCss(&v, dest); - }, - }; - } - - /// Parses a media feature name. - pub fn parse(input: *css.Parser) Result(struct { This, ?MediaFeatureComparison }) { - const ident = switch (input.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - if (bun.strings.startsWith(ident, "--")) { - return .{ .result = .{ - .{ - .custom = .{ .v = ident }, - }, - null, - } }; - } - - var name = ident; - - // Webkit places its prefixes before "min" and "max". Remove it first, and - // re-add after removing min/max. - const is_webkit = bun.strings.startsWithCaseInsensitiveAscii(name, "-webkit-"); - if (is_webkit) { - name = name[8..]; - } - - const comparator: ?MediaFeatureComparison = comparator: { - if (bun.strings.startsWithCaseInsensitiveAscii(name, "min-")) { - name = name[4..]; - break :comparator .@"greater-than-equal"; - } else if (bun.strings.startsWithCaseInsensitiveAscii(name, "max-")) { - name = name[4..]; - break :comparator .@"less-than-equal"; - } else break :comparator null; - }; - - var free_str = false; - const final_name = if (is_webkit) name: { - // PERF: stack buffer here? - free_str = true; - break :name bun.handleOom(std.fmt.allocPrint(input.allocator(), "-webkit-{s}", .{name})); - } else name; - - defer if (is_webkit) { - // If we made an allocation let's try to free it, - // this only works if FeatureId doesn't hold any references to the input string. - // i.e. it is an enum - comptime { - std.debug.assert(@typeInfo(FeatureId) == .@"enum"); - } - input.allocator().free(final_name); - }; - - if (css.parse_utility.parseString( - input.allocator(), - FeatureId, - final_name, - FeatureId.parse, - ).asValue()) |standard| { - return .{ .result = .{ - .{ .standard = standard }, - comparator, - } }; - } - - return .{ .result = .{ - .{ - .unknown = .{ .v = ident }, - }, - null, - } }; - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } - }; -} - -fn writeMinMax( - operator: *const MediaFeatureComparison, - comptime FeatureId: type, - name: *const MediaFeatureName(FeatureId), - value: *const MediaFeatureValue, - dest: *Printer, -) PrintErr!void { - const prefix = switch (operator.*) { - .@"greater-than", .@"greater-than-equal" => "min-", - .@"less-than", .@"less-than-equal" => "max-", - .equal => null, - }; - - if (prefix) |p| { - try name.toCssWithPrefix(p, dest); - } else { - try name.toCss(dest); - } - - try dest.delim(':', false); - - var adjusted: ?MediaFeatureValue = switch (operator.*) { - .@"greater-than" => value.deepClone(dest.allocator).addF32(dest.allocator, 0.001), - .@"less-than" => value.deepClone(dest.allocator).addF32(dest.allocator, -0.001), - else => null, - }; - - if (adjusted) |*val| { - defer val.deinit(dest.allocator); - try val.toCss(dest); - } else { - try value.toCss(dest); - } - - return dest.writeChar(')'); -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/prefixes.rs b/src/css/prefixes.rs index 9e9d39324d8f..a3a13e2b186b 100644 --- a/src/css/prefixes.rs +++ b/src/css/prefixes.rs @@ -1,6 +1,4 @@ -// Autogenerated by build-prefixes.js. -// DO NOT EDIT BY HAND — regenerate via `build-prefixes.js --rs` when the -// caniuse tables change. +// Autogenerated by build-prefixes.js. DO NOT EDIT! #![allow(clippy::manual_range_contains)] @@ -2241,9 +2239,3 @@ impl Feature { false } } - -// Module-level re-exports so callers can `use css::prefixes::is_flex_2009`. -#[inline] -pub(crate) fn is_flex_2009(browsers: &Browsers) -> bool { - Feature::is_flex_2009(browsers) -} diff --git a/src/css/prefixes.zig b/src/css/prefixes.zig deleted file mode 100644 index 89f32669134b..000000000000 --- a/src/css/prefixes.zig +++ /dev/null @@ -1,2203 +0,0 @@ -// This file is autogenerated by build-prefixes.js. DO NOT EDIT! - -pub const Feature = enum { - align_content, - align_items, - align_self, - animation, - animation_delay, - animation_direction, - animation_duration, - animation_fill_mode, - animation_iteration_count, - animation_name, - animation_play_state, - animation_timing_function, - any_pseudo, - appearance, - at_keyframes, - at_resolution, - at_viewport, - backdrop_filter, - backface_visibility, - background_clip, - background_origin, - background_size, - border_block_end, - border_block_start, - border_bottom_left_radius, - border_bottom_right_radius, - border_image, - border_inline_end, - border_inline_start, - border_radius, - border_top_left_radius, - border_top_right_radius, - box_decoration_break, - box_shadow, - box_sizing, - break_after, - break_before, - break_inside, - calc, - clip_path, - color_adjust, - column_count, - column_fill, - column_gap, - column_rule, - column_rule_color, - column_rule_style, - column_rule_width, - column_span, - column_width, - columns, - cross_fade, - display_flex, - display_grid, - element, - fill, - fill_available, - filter, - filter_function, - fit_content, - flex, - flex_basis, - flex_direction, - flex_flow, - flex_grow, - flex_shrink, - flex_wrap, - flow_from, - flow_into, - font_feature_settings, - font_kerning, - font_language_override, - font_variant_ligatures, - grab, - grabbing, - grid_area, - grid_column, - grid_column_align, - grid_column_end, - grid_column_start, - grid_row, - grid_row_align, - grid_row_end, - grid_row_start, - grid_template, - grid_template_areas, - grid_template_columns, - grid_template_rows, - hyphens, - image_rendering, - image_set, - inline_flex, - inline_grid, - isolate, - isolate_override, - justify_content, - linear_gradient, - margin_block_end, - margin_block_start, - margin_inline_end, - margin_inline_start, - mask, - mask_border, - mask_border_outset, - mask_border_repeat, - mask_border_slice, - mask_border_source, - mask_border_width, - mask_clip, - mask_composite, - mask_image, - mask_origin, - mask_position, - mask_repeat, - mask_size, - max_content, - min_content, - object_fit, - object_position, - order, - overscroll_behavior, - padding_block_end, - padding_block_start, - padding_inline_end, - padding_inline_start, - perspective, - perspective_origin, - pixelated, - place_self, - plaintext, - print_color_adjust, - pseudo_class_any_link, - pseudo_class_autofill, - pseudo_class_fullscreen, - pseudo_class_placeholder_shown, - pseudo_class_read_only, - pseudo_class_read_write, - pseudo_element_backdrop, - pseudo_element_file_selector_button, - pseudo_element_placeholder, - pseudo_element_selection, - radial_gradient, - region_fragment, - repeating_linear_gradient, - repeating_radial_gradient, - scroll_snap_coordinate, - scroll_snap_destination, - scroll_snap_points_x, - scroll_snap_points_y, - scroll_snap_type, - shape_image_threshold, - shape_margin, - shape_outside, - sticky, - stretch, - tab_size, - text_align_last, - text_decoration, - text_decoration_color, - text_decoration_line, - text_decoration_skip, - text_decoration_skip_ink, - text_decoration_style, - text_emphasis, - text_emphasis_color, - text_emphasis_position, - text_emphasis_style, - text_orientation, - text_overflow, - text_size_adjust, - text_spacing, - touch_action, - transform, - transform_origin, - transform_style, - transition, - transition_delay, - transition_duration, - transition_property, - transition_timing_function, - user_select, - writing_mode, - zoom_in, - zoom_out, - - pub fn prefixesFor(this: *const Feature, browsers: Browsers) VendorPrefix { - var prefixes = VendorPrefix{ .none = true }; - switch (this.*) { - .border_radius, .border_top_left_radius, .border_top_right_radius, .border_bottom_right_radius, .border_bottom_left_radius => { - if (browsers.android) |version| { - if (version <= 131328) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version <= 262144) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 198144) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version <= 197120) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 262144) { - prefixes.webkit = true; - } - } - }, - .box_shadow => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 196608) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 589824) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 197888 and version <= 198144) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 262656) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 327680) { - prefixes.webkit = true; - } - } - }, - .animation, .animation_name, .animation_duration, .animation_delay, .animation_direction, .animation_fill_mode, .animation_iteration_count, .animation_play_state, .animation_timing_function, .at_keyframes => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 2752512) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 327680 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 524544) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version == 786432) { - prefixes.o = true; - } - if (version >= 983040 and version <= 1900544) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 524288) { - prefixes.webkit = true; - } - } - }, - .transition, .transition_property, .transition_duration, .transition_delay, .transition_timing_function => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 262656) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 1638400) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 262144 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 393216) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 655360 and version <= 786432) { - prefixes.o = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 393216) { - prefixes.webkit = true; - } - } - }, - .transform, .transform_origin => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 2293760) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 197888 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ie) |version| { - if (version <= 589824) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 524544) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 656640 and version <= 786432) { - prefixes.o = true; - } - if (version >= 983040 and version <= 1441792) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 524288) { - prefixes.webkit = true; - } - } - }, - .perspective, .perspective_origin, .transform_style => { - if (browsers.android) |version| { - if (version >= 196608 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 786432 and version <= 2293760) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 655360 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 524544) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 1441792) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 524288) { - prefixes.webkit = true; - } - } - }, - .backface_visibility => { - if (browsers.android) |version| { - if (version >= 196608 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 786432 and version <= 2293760) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 655360 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 983552) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 1441792) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 983552) { - prefixes.webkit = true; - } - } - }, - .linear_gradient, .repeating_linear_gradient, .radial_gradient, .repeating_radial_gradient => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 262656) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 1638400) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 198144 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 393216) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 721152 and version <= 786432) { - prefixes.o = true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 393216) { - prefixes.webkit = true; - } - } - }, - .box_sizing => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 196608) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 589824) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 1835008) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 262656) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 327680) { - prefixes.webkit = true; - } - } - }, - .filter => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1179648 and version <= 3407872) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 589824) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2555904) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393216 and version <= 589824) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 393728) { - prefixes.webkit = true; - } - } - }, - .filter_function => { - if (browsers.ios_saf) |version| { - if (version >= 589824 and version <= 590592) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version <= 589824) { - prefixes.webkit = true; - } - } - }, - .backdrop_filter => { - if (browsers.edge) |version| { - if (version >= 1114112 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 589824 and version <= 1115648) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 589824 and version <= 1115648) { - prefixes.webkit = true; - } - } - }, - .element => { - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 8650752) { - prefixes.moz = true; - } - } - }, - .columns, .column_width, .column_gap, .column_rule, .column_rule_color, .column_rule_width, .column_count, .column_rule_style, .column_span, .column_fill => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 3211264) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 3342336) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 524544) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2359296) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 524288) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version <= 262144) { - prefixes.webkit = true; - } - } - }, - .break_before, .break_after, .break_inside => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 3211264) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 524544) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2359296) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 524288) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version <= 262144) { - prefixes.webkit = true; - } - } - }, - .user_select => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 3473408) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 4456448) { - prefixes.moz = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2621440) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 327680) { - prefixes.webkit = true; - } - } - }, - .display_flex, .inline_flex, .flex, .flex_grow, .flex_shrink, .flex_basis, .flex_direction, .flex_wrap, .flex_flow, .justify_content, .order, .align_items, .align_self, .align_content => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 262656) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 1835008) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 1376256) { - prefixes.moz = true; - } - } - if (browsers.ie) |version| { - if (version == 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 524544) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 1048576) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 524288) { - prefixes.webkit = true; - } - } - }, - .calc => { - if (browsers.chrome) |version| { - if (version >= 1245184 and version <= 1638400) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 262144 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version <= 393216) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version <= 393216) { - prefixes.webkit = true; - } - } - }, - .background_origin, .background_size => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 131840) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version <= 198144) { - prefixes.moz = true; - } - } - if (browsers.opera) |version| { - if (version <= 655360) { - prefixes.o = true; - } - } - }, - .background_clip => { - if (browsers.android) |version| { - if (version >= 262144 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 7798784) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 917504) { - prefixes.ms = true; - } - if (version >= 5177344 and version <= 7798784) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 852992) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 6881280) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 852224) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1572864) { - prefixes.webkit = true; - } - } - }, - .font_feature_settings, .font_variant_ligatures, .font_language_override => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1048576 and version <= 3080192) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 262144 and version <= 2162688) { - prefixes.moz = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2228224) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version <= 262144) { - prefixes.webkit = true; - } - } - }, - .font_kerning => { - if (browsers.android) |version| { - if (version <= 263168) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1900544 and version <= 2097152) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 524288 and version <= 721664) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 1048576 and version <= 1245184) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 458752 and version <= 589824) { - prefixes.webkit = true; - } - } - }, - .border_image => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 262656) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 917504) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 197888 and version <= 917504) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 327680) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 720896 and version <= 786688) { - prefixes.o = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 327936) { - prefixes.webkit = true; - } - } - }, - .pseudo_element_selection => { - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 3997696) { - prefixes.moz = true; - } - } - }, - .pseudo_element_placeholder => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 3670016) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.firefox) |version| { - if (version >= 1179648 and version <= 3276800) { - prefixes.moz = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 262656 and version <= 655360) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2818048) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 327680 and version <= 655360) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 393728) { - prefixes.webkit = true; - } - } - }, - .pseudo_class_placeholder_shown => { - if (browsers.firefox) |version| { - if (version >= 262144 and version <= 3276800) { - prefixes.moz = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - }, - .hyphens => { - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.firefox) |version| { - if (version >= 393216 and version <= 2752512) { - prefixes.moz = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 262656 and version <= 1050112) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 327936 and version <= 1050112) { - prefixes.webkit = true; - } - } - }, - .pseudo_class_fullscreen => { - if (browsers.chrome) |version| { - if (version >= 983040 and version <= 4587520) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 655360 and version <= 4128768) { - prefixes.moz = true; - } - } - if (browsers.ie) |version| { - if (version >= 720896) { - prefixes.ms = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 4128768) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 327936 and version <= 1049344) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 590336) { - prefixes.webkit = true; - } - } - }, - .pseudo_element_backdrop => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 2097152 and version <= 2359296) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.ie != null) { - prefixes.ms = true; - } - if (browsers.opera) |version| { - if (version >= 1245184 and version <= 1507328) { - prefixes.webkit = true; - } - } - }, - .pseudo_element_file_selector_button => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 5767168) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - if (version >= 5177344 and version <= 5767168) { - prefixes.webkit = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 917504) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 4849664) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 917504) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 917504) { - prefixes.webkit = true; - } - } - }, - .pseudo_class_autofill => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 7143424) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 7143424) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 918784) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 6225920) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 917760) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1310720) { - prefixes.webkit = true; - } - } - }, - .tab_size => { - if (browsers.firefox) |version| { - if (version >= 262144 and version <= 5898240) { - prefixes.moz = true; - } - } - if (browsers.opera) |version| { - if (version >= 656896 and version <= 786688) { - prefixes.o = true; - } - } - }, - .max_content, .min_content => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1441792 and version <= 2949120) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 196608 and version <= 4259840) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 852992) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2097152) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 655616) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version <= 262144) { - prefixes.webkit = true; - } - } - }, - .fill, .fill_available => { - if (browsers.chrome) |version| { - if (version >= 1441792 and version <= 8519680) { - prefixes.webkit = true; - } - } - if (browsers.android) |version| { - if (version >= 263168 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 196608 and version <= 4259840) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 852992) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 655616) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1638400) { - prefixes.webkit = true; - } - } - }, - .fit_content => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1441792 and version <= 2949120) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 196608 and version <= 6094848) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 852992) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2097152) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 655616) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version <= 262144) { - prefixes.webkit = true; - } - } - }, - .stretch => { - if (browsers.chrome) |version| { - if (version >= 1441792 and version <= 8519680) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 196608 and version <= 8650752) { - prefixes.moz = true; - } - } - if (browsers.android) |version| { - if (version >= 263168 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 458752 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 327680 and version <= 1638400) { - prefixes.webkit = true; - } - } - }, - .zoom_in, .zoom_out => { - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 2359296) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 1507328) { - prefixes.moz = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 1507328) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 524288) { - prefixes.webkit = true; - } - } - }, - .grab, .grabbing => { - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 4390912) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 1703936) { - prefixes.moz = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 3538944) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 655616) { - prefixes.webkit = true; - } - } - }, - .sticky => { - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 786944) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 786688) { - prefixes.webkit = true; - } - } - }, - .touch_action => { - if (browsers.ie) |version| { - if (version == 655360) { - prefixes.ms = true; - } - } - }, - .text_decoration_skip, .text_decoration_skip_ink => { - if (browsers.ios_saf) |version| { - if (version >= 524288 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 459008 and version <= 786432) { - prefixes.webkit = true; - } - } - }, - .text_decoration => { - if (browsers.ios_saf) |version| { - if (version >= 524288 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 524288 and version <= 1179648) { - prefixes.webkit = true; - } - } - }, - .text_decoration_color, .text_decoration_line, .text_decoration_style => { - if (browsers.firefox) |version| { - if (version >= 393216 and version <= 2293760) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 524288 and version <= 786432) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 524288 and version <= 786432) { - prefixes.webkit = true; - } - } - }, - .text_size_adjust => { - if (browsers.firefox) |version| { - if (version <= 8323072) { - prefixes.moz = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 327680 and version <= 1179648) { - prefixes.webkit = true; - } - } - }, - .mask_clip, .mask_composite, .mask_image, .mask_origin, .mask_repeat, .mask_border_repeat, .mask_border_source, .mask, .mask_position, .mask_size, .mask_border, .mask_border_outset, .mask_border_width, .mask_border_slice => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 7798784) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 7798784) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 983552) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 6881280) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 983552) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1572864) { - prefixes.webkit = true; - } - } - }, - .clip_path => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1572864 and version <= 3538944) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 589824) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2686976) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 458752 and version <= 589824) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 327680) { - prefixes.webkit = true; - } - } - }, - .box_decoration_break => { - if (browsers.chrome) |version| { - if (version >= 1441792 and version <= 8519680) { - prefixes.webkit = true; - } - } - if (browsers.android) |version| { - if (version >= 263168 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1638400) { - prefixes.webkit = true; - } - } - }, - .object_fit, .object_position => { - if (browsers.opera) |version| { - if (version >= 656896 and version <= 786688) { - prefixes.o = true; - } - } - }, - .shape_margin, .shape_outside, .shape_image_threshold => { - if (browsers.ios_saf) |version| { - if (version >= 524288 and version <= 655360) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 459008 and version <= 655360) { - prefixes.webkit = true; - } - } - }, - .text_overflow => { - if (browsers.opera) |version| { - if (version >= 589824 and version <= 786432) { - prefixes.o = true; - } - } - }, - .at_viewport => { - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.opera) |version| { - if (version >= 720896 and version <= 786688) { - prefixes.o = true; - } - } - }, - .at_resolution => { - if (browsers.android) |version| { - if (version >= 131840 and version <= 262656) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 1835008) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 197888 and version <= 983040) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 262144 and version <= 984576) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 591104 and version <= 786432) { - prefixes.o = true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 984576) { - prefixes.webkit = true; - } - } - }, - .text_align_last => { - if (browsers.firefox) |version| { - if (version >= 786432 and version <= 3145728) { - prefixes.moz = true; - } - } - }, - .pixelated => { - if (browsers.firefox) |version| { - if (version >= 198144 and version <= 4194304) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 327680 and version <= 393216) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 722432 and version <= 786688) { - prefixes.o = true; - } - } - if (browsers.safari) |version| { - if (version <= 393216) { - prefixes.webkit = true; - } - } - }, - .image_rendering => { - if (browsers.ie) |version| { - if (version >= 458752) { - prefixes.ms = true; - } - } - }, - .border_inline_start, .border_inline_end, .margin_inline_start, .margin_inline_end, .padding_inline_start, .padding_inline_end => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 4456448) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 196608 and version <= 2621440) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 786432) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 3604480) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 786432) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 590336) { - prefixes.webkit = true; - } - } - }, - .border_block_start, .border_block_end, .margin_block_start, .margin_block_end, .padding_block_start, .padding_block_end => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 4456448) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 786432) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 3604480) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 786432) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 590336) { - prefixes.webkit = true; - } - } - }, - .appearance => { - if (browsers.android) |version| { - if (version >= 131328 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 5439488) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - if (version >= 5177344 and version <= 5439488) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 131072 and version <= 5177344) { - prefixes.moz = true; - } - } - if (browsers.ie != null) { - prefixes.ms = true; - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 983552) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 4718592) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 983552) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 851968) { - prefixes.webkit = true; - } - } - }, - .scroll_snap_type, .scroll_snap_coordinate, .scroll_snap_destination, .scroll_snap_points_x, .scroll_snap_points_y => { - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 589824 and version <= 656128) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 589824 and version <= 655616) { - prefixes.webkit = true; - } - } - }, - .flow_into, .flow_from, .region_fragment => { - if (browsers.chrome) |version| { - if (version >= 983040 and version <= 1179648) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 720896) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 720896) { - prefixes.webkit = true; - } - } - }, - .image_set => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1376256 and version <= 7340032) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 7340032) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 590592) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 6422528) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393216 and version <= 590080) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1441792) { - prefixes.webkit = true; - } - } - }, - .writing_mode => { - if (browsers.android) |version| { - if (version >= 196608 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 524288 and version <= 3080192) { - prefixes.webkit = true; - } - } - if (browsers.ie) |version| { - if (version >= 328960) { - prefixes.ms = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 327680 and version <= 656128) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2228224) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 327936 and version <= 655616) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version <= 262144) { - prefixes.webkit = true; - } - } - }, - .cross_fade => { - if (browsers.chrome) |version| { - if (version >= 1114112 and version <= 8519680) { - prefixes.webkit = true; - } - } - if (browsers.android) |version| { - if (version >= 263168 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 327680 and version <= 590592) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 327936 and version <= 590080) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1638400) { - prefixes.webkit = true; - } - } - }, - .pseudo_class_read_only, .pseudo_class_read_write => { - if (browsers.firefox) |version| { - if (version >= 196608 and version <= 5046272) { - prefixes.moz = true; - } - } - }, - .text_emphasis, .text_emphasis_position, .text_emphasis_style, .text_emphasis_color => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 1638400 and version <= 6422528) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 6422528) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 5570560) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 458752) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1114112) { - prefixes.webkit = true; - } - } - }, - .display_grid, .inline_grid, .grid_template_columns, .grid_template_rows, .grid_row_start, .grid_column_start, .grid_row_end, .grid_column_end, .grid_row, .grid_column, .grid_area, .grid_template, .grid_template_areas, .place_self, .grid_column_align, .grid_row_align => { - if (browsers.edge) |version| { - if (version >= 786432 and version <= 983040) { - prefixes.ms = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - }, - .text_spacing => { - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1179648) { - prefixes.ms = true; - } - } - if (browsers.ie) |version| { - if (version >= 524288) { - prefixes.ms = true; - } - } - }, - .pseudo_class_any_link => { - if (browsers.android) |version| { - if (version >= 263168 and version <= 263171) { - prefixes.webkit = true; - } - } - if (browsers.chrome) |version| { - if (version >= 983040 and version <= 4194304) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 196608 and version <= 3211264) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 524544) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 3342336) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393472 and version <= 524288) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 327680 and version <= 524800) { - prefixes.webkit = true; - } - } - }, - .isolate => { - if (browsers.chrome) |version| { - if (version >= 1048576 and version <= 3080192) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 655360 and version <= 3211264) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 656128) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040 and version <= 2228224) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393216 and version <= 655616) { - prefixes.webkit = true; - } - } - }, - .plaintext => { - if (browsers.firefox) |version| { - if (version >= 655360 and version <= 3211264) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 656128) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393216 and version <= 655616) { - prefixes.webkit = true; - } - } - }, - .isolate_override => { - if (browsers.firefox) |version| { - if (version >= 1114112 and version <= 3211264) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 458752 and version <= 656128) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 458752 and version <= 655616) { - prefixes.webkit = true; - } - } - }, - .overscroll_behavior => { - if (browsers.edge) |version| { - if (version >= 786432 and version <= 1114112) { - prefixes.ms = true; - } - } - if (browsers.ie) |version| { - if (version >= 655360) { - prefixes.ms = true; - } - } - }, - .text_orientation => { - if (browsers.safari) |version| { - if (version >= 655616 and version <= 852224) { - prefixes.webkit = true; - } - } - }, - .print_color_adjust, .color_adjust => { - if (browsers.chrome) |version| { - if (version >= 1114112 and version <= 8519680) { - prefixes.webkit = true; - } - } - if (browsers.android) |version| { - if (version >= 263168 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 8323072) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 3145728 and version <= 6291456) { - prefixes.moz = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 393216 and version <= 983552) { - prefixes.webkit = true; - } - } - if (browsers.opera) |version| { - if (version >= 983040) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 393216 and version <= 983552) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 262144 and version <= 1638400) { - prefixes.webkit = true; - } - } - }, - .any_pseudo => { - if (browsers.chrome) |version| { - if (version >= 786432 and version <= 5701632) { - prefixes.webkit = true; - } - } - if (browsers.edge) |version| { - if (version >= 5177344 and version <= 5701632) { - prefixes.webkit = true; - } - } - if (browsers.firefox) |version| { - if (version >= 262144 and version <= 5111808) { - prefixes.moz = true; - } - } - if (browsers.opera) |version| { - if (version >= 917504 and version <= 4784128) { - prefixes.webkit = true; - } - } - if (browsers.safari) |version| { - if (version >= 327680 and version <= 851968) { - prefixes.webkit = true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 327680 and version <= 851968) { - prefixes.webkit = true; - } - } - if (browsers.samsung) |version| { - if (version >= 65536 and version <= 917504) { - prefixes.webkit = true; - } - } - if (browsers.android) |version| { - if (version >= 2424832 and version <= 5701632) { - prefixes.webkit = true; - } - } - }, - } - return prefixes; - } - - pub fn isFlex2009(browsers: Browsers) bool { - if (browsers.android) |version| { - if (version >= 131328 and version <= 262656) { - return true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 1310720) { - return true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 393216) { - return true; - } - } - if (browsers.safari) |version| { - if (version >= 196864 and version <= 393216) { - return true; - } - } - return false; - } - - pub fn isWebkitGradient(browsers: Browsers) bool { - if (browsers.android) |version| { - if (version >= 131328 and version <= 196608) { - return true; - } - } - if (browsers.chrome) |version| { - if (version >= 262144 and version <= 589824) { - return true; - } - } - if (browsers.ios_saf) |version| { - if (version >= 197120 and version <= 393216) { - return true; - } - } - if (browsers.safari) |version| { - if (version >= 262144 and version <= 393216) { - return true; - } - } - return false; - } -}; - -const css = @import("./css_parser.zig"); -const VendorPrefix = css.VendorPrefix; -const Browsers = css.targets.Browsers; diff --git a/src/css/printer.zig b/src/css/printer.zig deleted file mode 100644 index bfafdd2bbbd0..000000000000 --- a/src/css/printer.zig +++ /dev/null @@ -1,581 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const css_values = @import("./values/values.zig"); -const DashedIdent = css_values.ident.DashedIdent; -pub const Error = css.Error; -const Location = css.Location; -const PrintErr = css.PrintErr; - -/// Options that control how CSS is serialized to a string. -pub const PrinterOptions = struct { - /// Whether to minify the CSS, i.e. remove white space. - minify: bool = false, - /// An optional reference to a source map to write mappings into. - /// (Available when the `sourcemap` feature is enabled.) - source_map: ?*sourcemap.SourceMap = null, - /// An optional project root path, used to generate relative paths for sources used in CSS module hashes. - project_root: ?[]const u8 = null, - /// Targets to output the CSS for. - targets: Targets, - /// Whether to analyze dependencies (i.e. `@import` and `url()`). - /// If true, the dependencies are returned as part of the - /// [ToCssResult](super::stylesheet::ToCssResult). - /// - /// When enabled, `@import` and `url()` dependencies - /// are replaced with hashed placeholders that can be replaced with the final - /// urls later (after bundling). - analyze_dependencies: ?css.dependencies.DependencyOptions = null, - /// A mapping of pseudo classes to replace with class names that can be applied - /// from JavaScript. Useful for polyfills, for example. - pseudo_classes: ?PseudoClasses = null, - public_path: []const u8 = "", - - pub fn default() PrinterOptions { - return .{ - .targets = Targets{ - .browsers = null, - }, - }; - } - - pub fn defaultWithMinify(minify: bool) PrinterOptions { - return .{ - .targets = Targets{ - .browsers = null, - }, - .minify = minify, - }; - } -}; - -/// A mapping of user action pseudo classes to replace with class names. -/// -/// See [PrinterOptions](PrinterOptions). -const PseudoClasses = struct { - /// The class name to replace `:hover` with. - hover: ?[]const u8 = null, - /// The class name to replace `:active` with. - active: ?[]const u8 = null, - /// The class name to replace `:focus` with. - focus: ?[]const u8 = null, - /// The class name to replace `:focus-visible` with. - focus_visible: ?[]const u8 = null, - /// The class name to replace `:focus-within` with. - focus_within: ?[]const u8 = null, -}; - -pub const Targets = css.targets.Targets; - -pub const Features = css.targets.Features; - -pub const ImportInfo = struct { - import_records: *const bun.BabyList(bun.ImportRecord), - /// bundle_v2.graph.ast.items(.url_for_css) - ast_urls_for_css: []const []const u8, - /// bundle_v2.graph.input_files.items(.unique_key_for_additional_file) - ast_unique_key_for_additional_file: []const []const u8, - - /// Only safe to use when outside the bundler. As in, the import records - /// were not resolved to source indices. This will out-of-bounds otherwise. - pub fn initOutsideOfBundler(records: *bun.BabyList(bun.ImportRecord)) ImportInfo { - return .{ - .import_records = records, - .ast_urls_for_css = &.{}, - .ast_unique_key_for_additional_file = &.{}, - }; - } -}; - -/// A `Printer` represents a destination to output serialized CSS, as used in -/// the [ToCss](super::traits::ToCss) trait. It can wrap any destination that -/// implements [std::fmt::Write](std::fmt::Write), such as a [String](String). -/// -/// A `Printer` keeps track of the current line and column position, and uses -/// this to generate a source map if provided in the options. -/// -/// `Printer` also includes helper functions that assist with writing output -/// that respects options such as `minify`, and `css_modules`. -pub const Printer = struct { - // #[cfg(feature = "sourcemap")] - sources: ?*const ArrayList([]const u8), - dest: *std.Io.Writer, - loc: Location = Location{ - .source_index = 0, - .line = 0, - .column = 1, - }, - indent_amt: u8 = 0, - line: u32 = 0, - col: u32 = 0, - minify: bool, - targets: Targets, - vendor_prefix: css.VendorPrefix = .{}, - in_calc: bool = false, - css_module: ?css.CssModule = null, - dependencies: ?ArrayList(css.Dependency) = null, - remove_imports: bool, - /// A mapping of pseudo classes to replace with class names that can be applied - /// from JavaScript. Useful for polyfills, for example. - pseudo_classes: ?PseudoClasses = null, - indentation_buf: std.array_list.Managed(u8), - ctx: ?*const css.StyleContext = null, - scratchbuf: std.array_list.Managed(u8), - error_kind: ?css.PrinterError = null, - import_info: ?ImportInfo = null, - public_path: []const u8, - symbols: *const bun.ast.Symbol.Map, - local_names: ?*const css.LocalsResultsMap = null, - /// NOTE This should be the same mimalloc heap arena allocator - allocator: Allocator, - // TODO: finish the fields - - pub threadlocal var in_debug_fmt: if (bun.Environment.isDebug) bool else u0 = if (bun.Environment.isDebug) false else 0; - - const This = @This(); - - pub fn lookupSymbol(this: *This, ref: bun.bundle_v2.Ref) []const u8 { - const symbols = this.symbols; - - const final_ref = symbols.follow(ref); - if (this.local_names) |local_names| { - if (local_names.get(final_ref)) |local_name| return local_name; - } - - const original_name = symbols.get(final_ref).?.original_name; - return original_name; - } - - pub fn lookupIdentOrRef(this: *This, ident: css.css_values.ident.IdentOrRef) []const u8 { - if (comptime bun.Environment.isDebug) { - if (in_debug_fmt) { - return ident.debugIdent(); - } - } - if (ident.isIdent()) { - return ident.asIdent().?.v; - } - return this.lookupSymbol(ident.asRef().?); - } - - inline fn getWrittenAmt(writer: *std.Io.Writer) usize { - if (writer.vtable == std.Io.Writer.Allocating.init(undefined).writer.vtable) { - return @as(*std.Io.Writer.Allocating, @fieldParentPtr("writer", writer)).written().len; - } else { - @panic("css: got bad writer type"); - } - } - - /// Returns the current source filename that is being printed. - pub fn filename(this: *const This) []const u8 { - if (this.sources) |sources| { - if (this.loc.source_index < sources.items.len) return sources.items[this.loc.source_index]; - } - return "unknown.css"; - } - - /// Returns whether the indent level is greater than one. - pub fn isNested(this: *const This) bool { - return this.indent_amt > 2; - } - - /// Add an error related to std lib fmt errors - pub fn addFmtError(this: *This) PrintErr { - this.error_kind = css.PrinterError{ - .kind = .fmt_error, - .loc = null, - }; - return PrintErr.CSSPrintError; - } - - pub fn addNoImportRecordError(this: *This) PrintErr { - this.error_kind = css.PrinterError{ - .kind = .no_import_records, - .loc = null, - }; - return PrintErr.CSSPrintError; - } - - pub fn addInvalidCssModulesPatternInGridError(this: *This) PrintErr { - this.error_kind = css.PrinterError{ - .kind = .invalid_css_modules_pattern_in_grid, - .loc = css.ErrorLocation{ - .filename = this.filename(), - .line = this.loc.line, - .column = this.loc.column, - }, - }; - return PrintErr.CSSPrintError; - } - - /// Returns an error of the given kind at the provided location in the current source file. - pub fn newError( - this: *This, - kind: css.PrinterErrorKind, - maybe_loc: ?css.dependencies.Location, - ) PrintErr!void { - bun.debugAssert(this.error_kind == null); - this.error_kind = css.PrinterError{ - .kind = kind, - .loc = if (maybe_loc) |loc| css.ErrorLocation{ - .filename = this.filename(), - .line = loc.line - 1, - .column = loc.column, - } else null, - }; - return PrintErr.CSSPrintError; - } - - pub fn deinit(this: *This) void { - this.scratchbuf.deinit(); - this.indentation_buf.deinit(); - if (this.dependencies) |*dependencies| { - dependencies.deinit(this.allocator); - } - } - - /// If `import_records` is null, then the printer will error when it encounters code that relies on import records (urls()) - pub fn new( - allocator: Allocator, - scratchbuf: std.array_list.Managed(u8), - dest: *std.Io.Writer, - options: PrinterOptions, - import_info: ?ImportInfo, - local_names: ?*const css.LocalsResultsMap, - symbols: *const bun.ast.Symbol.Map, - ) This { - return .{ - .sources = null, - .dest = dest, - .minify = options.minify, - .targets = options.targets, - .dependencies = if (options.analyze_dependencies != null) .empty else null, - .remove_imports = options.analyze_dependencies != null and options.analyze_dependencies.?.remove_imports, - .pseudo_classes = options.pseudo_classes, - .indentation_buf = .init(allocator), - .import_info = import_info, - .scratchbuf = scratchbuf, - .allocator = allocator, - .public_path = options.public_path, - .local_names = local_names, - .loc = .{ - .source_index = 0, - .line = 0, - .column = 1, - }, - .symbols = symbols, - }; - } - - pub inline fn getImportRecords(this: *This) PrintErr!*const bun.BabyList(bun.ImportRecord) { - if (this.import_info) |info| return info.import_records; - return this.addNoImportRecordError(); - } - - pub fn printImportRecord(this: *This, import_record_idx: u32) PrintErr!void { - if (this.import_info) |info| { - const import_record = info.import_records.at(import_record_idx); - const a, const b = bun.bundle_v2.cheapPrefixNormalizer(this.public_path, import_record.path.text); - try this.writeStr(a); - try this.writeStr(b); - return; - } - return this.addNoImportRecordError(); - } - - pub inline fn importRecord(this: *Printer, import_record_idx: u32) PrintErr!*const bun.ImportRecord { - if (this.import_info) |info| return info.import_records.at(import_record_idx); - return this.addNoImportRecordError(); - } - - pub inline fn getImportRecordUrl(this: *This, import_record_idx: u32) PrintErr![]const u8 { - const import_info = this.import_info orelse return this.addNoImportRecordError(); - const record = import_info.import_records.at(import_record_idx); - if (record.source_index.isValid()) { - // It has an inlined url for CSS - const urls_for_css = import_info.ast_urls_for_css[record.source_index.get()]; - if (urls_for_css.len > 0) { - return urls_for_css; - } - // It is a chunk URL - const unique_key_for_additional_file = import_info.ast_unique_key_for_additional_file[record.source_index.get()]; - if (unique_key_for_additional_file.len > 0) { - return unique_key_for_additional_file; - } - } - // External URL stays as-is - return record.path.text; - } - - pub fn context(this: *const Printer) ?*const css.StyleContext { - return this.ctx; - } - - /// To satisfy io.Writer interface - /// - /// NOTE: Same constraints as `writeStr`, the `str` param is assumted to not - /// contain any newline characters - pub fn writeAll(this: *This, str: []const u8) !void { - return this.writeStr(str) catch std.mem.Allocator.Error.OutOfMemory; - } - - pub fn writeComment(this: *This, comment: []const u8) PrintErr!void { - _ = this.dest.writeAll(comment) catch { - return this.addFmtError(); - }; - const new_lines = std.mem.count(u8, comment, "\n"); - this.line += @intCast(new_lines); - this.col = 0; - const last_line_start = comment.len - (std.mem.lastIndexOfScalar(u8, comment, '\n') orelse comment.len); - this.col += @intCast(last_line_start); - return; - } - - /// Writes a raw string to the underlying destination. - /// - /// NOTE: Is is assumed that the string does not contain any newline characters. - /// If such a string is written, it will break source maps. - pub fn writeStr(this: *This, s: []const u8) PrintErr!void { - if (comptime bun.Environment.isDebug) { - bun.assert(std.mem.indexOfScalar(u8, s, '\n') == null); - } - this.col += @intCast(s.len); - _ = this.dest.writeAll(s) catch { - return this.addFmtError(); - }; - return; - } - - /// Writes a formatted string to the underlying destination. - /// - /// NOTE: Is is assumed that the formatted string does not contain any newline characters. - /// If such a string is written, it will break source maps. - pub fn writeFmt(this: *This, comptime fmt: []const u8, args: anytype) PrintErr!void { - // assuming the writer comes from an ArrayList - const start: usize = getWrittenAmt(this.dest); - this.dest.print(fmt, args) catch return this.addFmtError(); - const written = getWrittenAmt(this.dest) - start; - this.col += @intCast(written); - } - - fn replaceDots(allocator: Allocator, s: []const u8) []const u8 { - var str = bun.handleOom(allocator.dupe(u8, s)); - std.mem.replaceScalar(u8, str[0..], '.', '-'); - return str; - } - - pub fn writeIdentOrRef(this: *This, ident: css.css_values.ident.IdentOrRef, handle_css_module: bool) PrintErr!void { - if (!handle_css_module) { - if (ident.asIdent()) |identifier| { - return css.serializer.serializeIdentifier(identifier.v, this) catch return this.addFmtError(); - } else { - const ref = ident.asRef().?; - const symbol = this.symbols.get(ref) orelse return this.addFmtError(); - return css.serializer.serializeIdentifier(symbol.original_name, this) catch return this.addFmtError(); - } - } - - const str = this.lookupIdentOrRef(ident); - return css.serializer.serializeIdentifier(str, this) catch return this.addFmtError(); - } - - /// Writes a CSS identifier to the underlying destination, escaping it - /// as appropriate. If the `css_modules` option was enabled, then a hash - /// is added, and the mapping is added to the CSS module. - pub fn writeIdent(this: *This, ident: []const u8, handle_css_module: bool) PrintErr!void { - if (handle_css_module) { - if (this.css_module) |*css_module| { - const Closure = struct { first: bool, printer: *This }; - var closure = Closure{ .first = true, .printer = this }; - css_module.config.pattern.write( - css_module.hashes.items[this.loc.source_index], - css_module.sources.items[this.loc.source_index], - ident, - &closure, - struct { - pub fn writeFn(self: *Closure, s1: []const u8, replace_dots: bool) void { - // PERF: stack fallback? - const s = if (!replace_dots) s1 else replaceDots(self.printer.allocator, s1); - defer if (replace_dots) self.printer.allocator.free(s); - self.printer.col += @intCast(s.len); - if (self.first) { - self.first = false; - return css.serializer.serializeIdentifier(s, self.printer) catch |e| css.OOM(e); - } else { - return css.serializer.serializeName(s, self.printer) catch |e| css.OOM(e); - } - } - }.writeFn, - ); - - css_module.addLocal(this.allocator, ident, ident, this.loc.source_index); - return; - } - } - - return css.serializer.serializeIdentifier(ident, this) catch return this.addFmtError(); - } - - pub fn writeDashedIdent(this: *This, ident: *const DashedIdent, is_declaration: bool) !void { - try this.writeStr("--"); - - if (this.css_module) |*css_module| { - if (css_module.config.dashed_idents) { - const Fn = struct { - pub fn writeFn(self: *This, s1: []const u8, replace_dots: bool) void { - const s = if (!replace_dots) s1 else replaceDots(self.allocator, s1); - defer if (replace_dots) self.allocator.free(s); - self.col += @intCast(s.len); - return css.serializer.serializeName(s, self) catch |e| css.OOM(e); - } - }; - css_module.config.pattern.write( - css_module.hashes.items[this.loc.source_index], - css_module.sources.items[this.loc.source_index], - ident.v[2..], - this, - Fn.writeFn, - ); - - if (is_declaration) { - css_module.addDashed(this.allocator, ident.v, this.loc.source_index); - } - } - } - - return css.serializer.serializeName(ident.v[2..], this) catch return this.addFmtError(); - } - - pub fn writeByte(this: *This, char: u8) !void { - return this.writeChar(char) catch return Allocator.Error.OutOfMemory; - } - - /// Write a single character to the underlying destination. - pub fn writeChar(this: *This, char: u8) PrintErr!void { - if (char == '\n') { - this.line += 1; - this.col = 0; - } else { - this.col += 1; - } - _ = this.dest.writeByte(char) catch { - return this.addFmtError(); - }; - } - - /// Writes a newline character followed by indentation. - /// If the `minify` option is enabled, then nothing is printed. - pub fn newline(this: *This) PrintErr!void { - if (this.minify) { - return; - } - - try this.writeChar('\n'); - return this.writeIndent(); - } - - /// Writes a delimiter character, followed by whitespace (depending on the `minify` option). - /// If `ws_before` is true, then whitespace is also written before the delimiter. - pub fn delim(this: *This, delim_: u8, ws_before: bool) PrintErr!void { - if (ws_before) { - try this.whitespace(); - } - try this.writeChar(delim_); - return this.whitespace(); - } - - /// Writes a single whitespace character, unless the `minify` option is enabled. - /// - /// Use `write_char` instead if you wish to force a space character to be written, - /// regardless of the `minify` option. - pub fn whitespace(this: *This) PrintErr!void { - if (this.minify) return; - return this.writeChar(' '); - } - - pub fn withContext( - this: *This, - selectors: *const css.SelectorList, - closure: anytype, - comptime func: anytype, - ) PrintErr!void { - const parent = if (this.ctx) |ctx| parent: { - this.ctx = null; - break :parent ctx; - } else null; - - const ctx = css.StyleContext{ .selectors = selectors, .parent = parent }; - - this.ctx = &ctx; - const res = func(closure, this); - this.ctx = parent; - - return res; - } - - pub fn withClearedContext( - this: *This, - closure: anytype, - comptime func: anytype, - ) PrintErr!void { - const parent = if (this.ctx) |ctx| parent: { - this.ctx = null; - break :parent ctx; - } else null; - const res = func(closure, this); - this.ctx = parent; - return res; - } - - /// Increases the current indent level. - pub fn indent(this: *This) void { - this.indent_amt += 2; - } - - /// Decreases the current indent level. - pub fn dedent(this: *This) void { - this.indent_amt -= 2; - } - - const INDENTS: []const []const u8 = indents: { - const levels = 32; - var indents: [levels][]const u8 = undefined; - for (0..levels) |i| { - const n = i * 2; - var str: [n]u8 = undefined; - for (0..n) |j| { - str[j] = ' '; - } - indents[i] = str; - } - break :indents indents; - }; - - fn getIndent(this: *This, idnt: u8) []const u8 { - // divide by 2 to get index into table - const i = idnt >> 1; - // PERF: may be faster to just do `i < (IDENTS.len - 1) * 2` (e.g. 62 if IDENTS.len == 32) here - if (i < INDENTS.len) { - return INDENTS[i]; - } - if (this.indentation_buf.items.len < idnt) { - this.indentation_buf.appendNTimes(' ', this.indentation_buf.items.len - idnt) catch unreachable; - } else { - this.indentation_buf.items = this.indentation_buf.items[0..idnt]; - } - return this.indentation_buf.items; - } - - fn writeIndent(this: *This) PrintErr!void { - bun.debugAssert(!this.minify); - if (this.indent_amt > 0) { - // try this.writeStr(this.getIndent(this.ident)); - this.dest.splatByteAll(' ', this.indent_amt) catch return this.addFmtError(); - } - } -}; - -const bun = @import("bun"); -const sourcemap = @import("./sourcemap.zig"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/align.zig b/src/css/properties/align.zig deleted file mode 100644 index bd15dd2472f4..000000000000 --- a/src/css/properties/align.zig +++ /dev/null @@ -1,1516 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const LengthPercentage = css.css_values.length.LengthPercentage; - -const VendorPrefix = css.VendorPrefix; -const Property = css.Property; -const Feature = css.prefixes.Feature; - -/// A value for the [align-content](https://www.w3.org/TR/css-align-3/#propdef-align-content) property. -pub const AlignContent = union(enum) { - /// Default alignment. - normal: void, - /// A baseline position. - baseline_position: BaselinePosition, - /// A content distribution keyword. - content_distribution: ContentDistribution, - /// A content position keyword. - content_position: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - /// A content position keyword. - value: ContentPosition, - - pub fn toInner(this: *const @This()) ContentPositionInner { - return .{ - .overflow = this.overflow, - .value = this.value, - }; - } - - pub fn __generateToCss() void {} - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const overflow = input.tryParse(OverflowPosition.parse, .{}).asValue(); - - const value = switch (ContentPosition.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .overflow = overflow, .value = value } }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [``](https://www.w3.org/TR/css-align-3/#typedef-baseline-position) value, -/// as used in the alignment properties. -pub const BaselinePosition = enum { - /// The first baseline. - first, - /// The last baseline. - last, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const BaselinePositionIdent = enum { - baseline, - first, - last, - }; - - const BaselinePositionMap = bun.ComptimeEnumMap(BaselinePositionIdent); - if (BaselinePositionMap.getASCIIICaseInsensitive(ident)) |value| - switch (value) { - .baseline => return .{ .result = BaselinePosition.first }, - .first => { - if (input.expectIdentMatching("baseline").asErr()) |e| return .{ .err = e }; - return .{ .result = BaselinePosition.first }; - }, - .last => { - if (input.expectIdentMatching("baseline").asErr()) |e| return .{ .err = e }; - return .{ .result = BaselinePosition.last }; - }, - } - else - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const BaselinePosition, dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .first => try dest.writeStr("baseline"), - .last => try dest.writeStr("last baseline"), - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [justify-content](https://www.w3.org/TR/css-align-3/#propdef-justify-content) property. -pub const JustifyContent = union(enum) { - /// Default justification. - normal, - /// A content distribution keyword. - content_distribution: ContentDistribution, - /// A content position keyword. - content_position: struct { - /// A content position keyword. - value: ContentPosition, - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn toInner(this: *const @This()) ContentPositionInner { - return .{ - .overflow = this.overflow, - .value = this.value, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// Justify to the left. - left: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// Justify to the right. - right: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"normal"}).isOk()) { - return .{ .result = .normal }; - } - - if (input.tryParse(ContentDistribution.parse, .{}).asValue()) |val| { - return .{ .result = .{ .content_distribution = val } }; - } - - const overflow = input.tryParse(OverflowPosition.parse, .{}).asValue(); - if (input.tryParse(ContentPosition.parse, .{}).asValue()) |content_position| { - return .{ .result = .{ - .content_position = .{ - .overflow = overflow, - .value = content_position, - }, - } }; - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - const JustifyContentIdent = enum { - left, - right, - }; - - const JustifyContentIdentMap = bun.ComptimeEnumMap(JustifyContentIdent); - if (JustifyContentIdentMap.getASCIIICaseInsensitive(ident)) |value| - return switch (value) { - .left => .{ .result = .{ .left = .{ .overflow = overflow } } }, - .right => .{ .result = .{ .right = .{ .overflow = overflow } } }, - } - else - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .normal => dest.writeStr("normal"), - .content_distribution => |value| value.toCss(dest), - .content_position => |*cp| { - if (cp.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - return cp.value.toCss(dest); - }, - .left => |*l| { - if (l.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - return dest.writeStr("left"); - }, - .right => |*r| { - if (r.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - return dest.writeStr("right"); - }, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [align-self](https://www.w3.org/TR/css-align-3/#align-self-property) property. -pub const AlignSelf = union(enum) { - /// Automatic alignment. - auto, - /// Default alignment. - normal, - /// Item is stretched. - stretch, - /// A baseline position keyword. - baseline_position: BaselinePosition, - /// A self position keyword. - self_position: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - /// A self position keyword. - value: SelfPosition, - - pub fn toInner(this: *const @This()) SelfPositionInner { - return .{ - .overflow = this.overflow, - .value = this.value, - }; - } - - pub fn __generateToCss() void {} - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const overflow = input.tryParse(OverflowPosition.parse, .{}).asValue(); - const self_position = switch (SelfPosition.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = .{ - .overflow = overflow, - .value = self_position, - }, - }; - } - }, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [justify-self](https://www.w3.org/TR/css-align-3/#justify-self-property) property. -pub const JustifySelf = union(enum) { - /// Automatic justification. - auto, - /// Default justification. - normal, - /// Item is stretched. - stretch, - /// A baseline position keyword. - baseline_position: BaselinePosition, - /// A self position keyword. - self_position: struct { - /// A self position keyword. - value: SelfPosition, - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn toInner(this: *const @This()) SelfPositionInner { - return .{ - .overflow = this.overflow, - .value = this.value, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// Item is justified to the left. - left: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// Item is justified to the right. - right: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"auto"}).isOk()) { - return .{ .result = .auto }; - } - - if (input.tryParse(css.Parser.expectIdentMatching, .{"normal"}).isOk()) { - return .{ .result = .normal }; - } - - if (input.tryParse(css.Parser.expectIdentMatching, .{"stretch"}).isOk()) { - return .{ .result = .stretch }; - } - - if (input.tryParse(BaselinePosition.parse, .{}).asValue()) |val| { - return .{ .result = .{ .baseline_position = val } }; - } - - const overflow = input.tryParse(OverflowPosition.parse, .{}).asValue(); - if (input.tryParse(SelfPosition.parse, .{}).asValue()) |self_position| { - return .{ .result = .{ .self_position = .{ .overflow = overflow, .value = self_position } } }; - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const Enum = enum { left, right }; - const Map = bun.ComptimeEnumMap(Enum); - if (Map.getASCIIICaseInsensitive(ident)) |val| return .{ .result = switch (val) { - .left => .{ .left = .{ .overflow = overflow } }, - .right => .{ .right = .{ .overflow = overflow } }, - } }; - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const JustifySelf, dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .auto => try dest.writeStr("auto"), - .normal => try dest.writeStr("normal"), - .stretch => try dest.writeStr("stretch"), - .baseline_position => |*baseline_position| baseline_position.toCss(dest), - .self_position => |*self_position| { - if (self_position.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - - try self_position.value.toCss(dest); - }, - .left => |*left| { - if (left.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - try dest.writeStr("left"); - }, - .right => |*right| { - if (right.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - try dest.writeStr("right"); - }, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [align-items](https://www.w3.org/TR/css-align-3/#align-items-property) property. -pub const AlignItems = union(enum) { - /// Default alignment. - normal, - /// Items are stretched. - stretch, - /// A baseline position keyword. - baseline_position: BaselinePosition, - /// A self position keyword. - self_position: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - /// A self position keyword. - value: SelfPosition, - - pub fn toInner(this: *const @This()) SelfPositionInner { - return .{ - .overflow = this.overflow, - .value = this.value, - }; - } - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const overflow = input.tryParse(OverflowPosition.parse, .{}).asValue(); - const self_position = switch (SelfPosition.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = .{ - .overflow = overflow, - .value = self_position, - }, - }; - } - - pub fn __generateToCss() void {} - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [justify-items](https://www.w3.org/TR/css-align-3/#justify-items-property) property. -pub const JustifyItems = union(enum) { - /// Default justification. - normal, - /// Items are stretched. - stretch, - /// A baseline position keyword. - baseline_position: BaselinePosition, - /// A self position keyword, with optional overflow position. - self_position: struct { - /// A self position keyword. - value: SelfPosition, - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn toInner(this: *const @This()) SelfPositionInner { - return .{ - .overflow = this.overflow, - .value = this.value, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// Items are justified to the left, with an optional overflow position. - left: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// Items are justified to the right, with an optional overflow position. - right: struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// A legacy justification keyword. - legacy: LegacyJustify, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"normal"}).isOk()) { - return .{ .result = .normal }; - } - - if (input.tryParse(css.Parser.expectIdentMatching, .{"stretch"}).isOk()) { - return .{ .result = .stretch }; - } - - if (input.tryParse(BaselinePosition.parse, .{}).asValue()) |val| { - return .{ .result = .{ .baseline_position = val } }; - } - - if (input.tryParse(LegacyJustify.parse, .{}).asValue()) |val| { - return .{ .result = .{ .legacy = val } }; - } - - const overflow = input.tryParse(OverflowPosition.parse, .{}).asValue(); - if (input.tryParse(SelfPosition.parse, .{}).asValue()) |self_position| { - return .{ .result = .{ .self_position = .{ .overflow = overflow, .value = self_position } } }; - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - const Enum = enum { left, right }; - const Map = bun.ComptimeEnumMap(Enum); - if (Map.getASCIIICaseInsensitive(ident)) |val| return .{ .result = switch (val) { - .left => .{ .left = .{ .overflow = overflow } }, - .right => .{ .right = .{ .overflow = overflow } }, - } }; - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const JustifyItems, dest: *css.Printer) css.PrintErr!void { - switch (this.*) { - .normal => try dest.writeStr("normal"), - .stretch => try dest.writeStr("stretch"), - .baseline_position => |*val| try val.toCss(dest), - .self_position => |*sp| { - if (sp.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - try sp.value.toCss(dest); - }, - .left => |*l| { - if (l.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - try dest.writeStr("left"); - }, - .right => |*r| { - if (r.overflow) |*overflow| { - try overflow.toCss(dest); - try dest.writeStr(" "); - } - try dest.writeStr("right"); - }, - .legacy => |l| try l.toCss(dest), - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A legacy justification keyword, as used in the `justify-items` property. -pub const LegacyJustify = enum { - /// Left justify. - left, - /// Right justify. - right, - /// Centered. - center, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const LegacyJustifyIdent = enum { - legacy, - left, - right, - center, - }; - - const LegacyJustifyMap = bun.ComptimeEnumMap(LegacyJustifyIdent); - if (LegacyJustifyMap.getASCIIICaseInsensitive(ident)) |value| { - switch (value) { - .legacy => { - const inner_location = input.currentSourceLocation(); - const inner_ident = switch (input.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const InnerEnum = enum { left, right, center }; - const InnerLegacyJustifyMap = bun.ComptimeEnumMap(InnerEnum); - if (InnerLegacyJustifyMap.getASCIIICaseInsensitive(inner_ident)) |inner_value| { - return switch (inner_value) { - .left => .{ .result = .left }, - .right => .{ .result = .right }, - .center => .{ .result = .center }, - }; - } else { - return .{ .err = inner_location.newUnexpectedTokenError(.{ .ident = inner_ident }) }; - } - }, - .left => { - if (input.expectIdentMatching("legacy").asErr()) |e| return .{ .err = e }; - return .{ .result = .left }; - }, - .right => { - if (input.expectIdentMatching("legacy").asErr()) |e| return .{ .err = e }; - return .{ .result = .right }; - }, - .center => { - if (input.expectIdentMatching("legacy").asErr()) |e| return .{ .err = e }; - return .{ .result = .center }; - }, - } - } - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - try dest.writeStr("legacy "); - switch (this.*) { - .left => try dest.writeStr("left"), - .right => try dest.writeStr("right"), - .center => try dest.writeStr("center"), - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [gap](https://www.w3.org/TR/css-align-3/#column-row-gap) value, as used in the -/// `column-gap` and `row-gap` properties. -pub const GapValue = union(enum) { - /// Equal to `1em` for multi-column containers, and zero otherwise. - normal, - /// An explicit length. - length_percentage: LengthPercentage, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [gap](https://www.w3.org/TR/css-align-3/#gap-shorthand) shorthand property. -pub const Gap = struct { - /// The row gap. - row: GapValue, - /// The column gap. - column: GapValue, - - pub const PropertyFieldMap = .{ - .row = "row-gap", - .column = "column-gap", - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const row = switch (@call(.auto, @field(GapValue, "parse"), .{input})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const column = switch (input.tryParse(@field(GapValue, "parse"), .{})) { - .result => |v| v, - .err => row, - }; - return .{ .result = .{ .row = row, .column = column } }; - } - - pub fn toCss(this: *const Gap, dest: *css.Printer) css.PrintErr!void { - try this.row.toCss(dest); - if (!this.column.eql(&this.row)) { - try dest.writeStr(" "); - try this.column.toCss(dest); - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [place-items](https://www.w3.org/TR/css-align-3/#place-items-property) shorthand property. -pub const PlaceItems = struct { - /// The item alignment. - @"align": AlignItems, - /// The item justification. - justify: JustifyItems, - - pub const PropertyFieldMap = .{ - .@"align" = "align-items", - .justify = "justify-items", - }; - - pub const VendorPrefixMap = .{ - .@"align" = true, - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const @"align" = switch (@call(.auto, @field(AlignItems, "parse"), .{input})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const justify = switch (input.tryParse(@field(JustifyItems, "parse"), .{})) { - .result => |v| v, - .err => switch (@"align") { - .normal => JustifyItems.normal, - .stretch => JustifyItems.stretch, - .baseline_position => |p| JustifyItems{ .baseline_position = p }, - .self_position => |sp| JustifyItems{ - .self_position = .{ - .overflow = if (sp.overflow) |o| o else null, - .value = sp.value, - }, - }, - }, - }; - - return .{ .result = .{ .@"align" = @"align", .justify = justify } }; - } - - pub fn toCss(this: *const PlaceItems, dest: *css.Printer) css.PrintErr!void { - try this.@"align".toCss(dest); - const is_equal = switch (this.justify) { - .normal => this.@"align".eql(&AlignItems{ .normal = {} }), - .stretch => this.@"align".eql(&AlignItems{ .stretch = {} }), - .baseline_position => |*p| brk: { - if (this.@"align" == .baseline_position) break :brk p.eql(&this.@"align".baseline_position); - break :brk false; - }, - .self_position => |*p| brk: { - if (this.@"align" == .self_position) break :brk p.toInner().eql(&this.@"align".self_position.toInner()); - break :brk false; - }, - else => false, - }; - - if (!is_equal) { - try dest.writeStr(" "); - try this.justify.toCss(dest); - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [place-self](https://www.w3.org/TR/css-align-3/#place-self-property) shorthand property. -pub const PlaceSelf = struct { - /// The item alignment. - @"align": AlignSelf, - /// The item justification. - justify: JustifySelf, - - pub const PropertyFieldMap = .{ - .@"align" = "align-self", - .justify = "justify-self", - }; - - pub const VendorPrefixMap = .{ - .@"align" = true, - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const @"align" = switch (@call(.auto, @field(AlignSelf, "parse"), .{input})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const justify = switch (input.tryParse(@field(JustifySelf, "parse"), .{})) { - .result => |v| v, - .err => switch (@"align") { - .auto => JustifySelf.auto, - .normal => JustifySelf.normal, - .stretch => JustifySelf.stretch, - .baseline_position => |p| JustifySelf{ .baseline_position = p }, - .self_position => |sp| JustifySelf{ - .self_position = .{ - .overflow = if (sp.overflow) |o| o else null, - .value = sp.value, - }, - }, - }, - }; - - return .{ .result = .{ .@"align" = @"align", .justify = justify } }; - } - - pub fn toCss(this: *const PlaceSelf, dest: *css.Printer) css.PrintErr!void { - try this.@"align".toCss(dest); - const is_equal = switch (this.justify) { - .auto => true, - .normal => this.@"align" == .normal, - .stretch => this.@"align" == .stretch, - .baseline_position => |p| switch (this.@"align") { - .baseline_position => |p2| p.eql(&p2), - else => false, - }, - .self_position => |sp| brk: { - if (this.@"align" == .self_position) break :brk sp.toInner().eql(&this.@"align".self_position.toInner()); - break :brk false; - }, - else => false, - }; - - if (!is_equal) { - try dest.writeStr(" "); - try this.justify.toCss(dest); - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [``](https://www.w3.org/TR/css-align-3/#typedef-self-position) value. -pub const SelfPosition = enum { - /// Item is centered within the container. - center, - /// Item is aligned to the start of the container. - start, - /// Item is aligned to the end of the container. - end, - /// Item is aligned to the edge of the container corresponding to the start side of the item. - @"self-start", - /// Item is aligned to the edge of the container corresponding to the end side of the item. - @"self-end", - /// Item is aligned to the start of the container, within flexbox layouts. - @"flex-start", - /// Item is aligned to the end of the container, within flexbox layouts. - @"flex-end", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [place-content](https://www.w3.org/TR/css-align-3/#place-content) shorthand property. -pub const PlaceContent = struct { - /// The content alignment. - @"align": AlignContent, - /// The content justification. - justify: JustifyContent, - - pub const PropertyFieldMap = .{ - .@"align" = css.PropertyIdTag.@"align-content", - .justify = css.PropertyIdTag.@"justify-content", - }; - - pub const VendorPrefixMap = .{ - .@"align" = true, - .justify = true, - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const @"align" = switch (@call(.auto, @field(AlignContent, "parse"), .{input})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const justify = switch (@call(.auto, @field(JustifyContent, "parse"), .{input})) { - .result => |v| v, - .err => |_| switch (@"align") { - .baseline_position => JustifyContent{ .content_position = .{ - .overflow = null, - .value = .start, - } }, - .normal => JustifyContent.normal, - .content_distribution => |value| JustifyContent{ .content_distribution = value }, - .content_position => |pos| JustifyContent{ .content_position = .{ - .overflow = if (pos.overflow) |*overflow| overflow.deepClone(input.allocator()) else null, - .value = pos.value.deepClone(input.allocator()), - } }, - }, - }; - - return .{ .result = .{ .@"align" = @"align", .justify = justify } }; - } - - pub fn toCss(this: *const PlaceContent, dest: *css.Printer) css.PrintErr!void { - try this.@"align".toCss(dest); - const is_equal = switch (this.justify) { - .normal => brk: { - if (this.@"align" == .normal) break :brk true; - break :brk false; - }, - .content_distribution => |*d| brk: { - if (this.@"align" == .content_distribution) break :brk d.eql(&this.@"align".content_distribution); - break :brk false; - }, - .content_position => |*p| brk: { - if (this.@"align" == .content_position) break :brk p.toInner().eql(&this.@"align".content_position.toInner()); - break :brk false; - }, - else => false, - }; - - if (!is_equal) { - try dest.writeStr(" "); - try this.justify.toCss(dest); - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [``](https://www.w3.org/TR/css-align-3/#typedef-content-distribution) value. -pub const ContentDistribution = enum { - /// Items are spaced evenly, with the first and last items against the edge of the container. - @"space-between", - /// Items are spaced evenly, with half-size spaces at the start and end. - @"space-around", - /// Items are spaced evenly, with full-size spaces at the start and end. - @"space-evenly", - /// Items are stretched evenly to fill free space. - stretch, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// An [``](https://www.w3.org/TR/css-align-3/#typedef-overflow-position) value. -pub const OverflowPosition = enum { - /// If the size of the alignment subject overflows the alignment container, - /// the alignment subject is instead aligned as if the alignment mode were start. - safe, - /// Regardless of the relative sizes of the alignment subject and alignment - /// container, the given alignment value is honored. - unsafe, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A [``](https://www.w3.org/TR/css-align-3/#typedef-content-position) value. -pub const ContentPosition = enum { - /// Content is centered within the container. - center, - /// Content is aligned to the start of the container. - start, - /// Content is aligned to the end of the container. - end, - /// Same as `start` when within a flexbox container. - @"flex-start", - /// Same as `end` when within a flexbox container. - @"flex-end", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -pub const SelfPositionInner = struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - /// A self position keyword. - value: SelfPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -pub const ContentPositionInner = struct { - /// An overflow alignment mode. - overflow: ?OverflowPosition, - /// A content position keyword. - value: ContentPosition, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -const FlexLinePack = css.css_properties.flex.FlexLinePack; -const BoxPack = css.css_properties.flex.BoxPack; -const FlexPack = css.css_properties.flex.FlexPack; -const BoxAlign = css.css_properties.flex.BoxAlign; -const FlexAlign = css.css_properties.flex.FlexAlign; -const FlexItemAlign = css.css_properties.flex.FlexItemAlign; - -pub const AlignHandler = struct { - align_content: ?struct { AlignContent, VendorPrefix } = null, - flex_line_pack: ?struct { FlexLinePack, VendorPrefix } = null, - justify_content: ?struct { JustifyContent, VendorPrefix } = null, - box_pack: ?struct { BoxPack, VendorPrefix } = null, - flex_pack: ?struct { FlexPack, VendorPrefix } = null, - align_self: ?struct { AlignSelf, VendorPrefix } = null, - flex_item_align: ?struct { FlexItemAlign, VendorPrefix } = null, - justify_self: ?JustifySelf = null, - align_items: ?struct { AlignItems, VendorPrefix } = null, - box_align: ?struct { BoxAlign, VendorPrefix } = null, - flex_align: ?struct { FlexAlign, VendorPrefix } = null, - justify_items: ?JustifyItems = null, - row_gap: ?GapValue = null, - column_gap: ?GapValue = null, - has_any: bool = false, - - pub fn handleProperty(this: *AlignHandler, property: *const Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool { - switch (property.*) { - .@"align-content" => |*val| { - this.flex_line_pack = null; - this.handlePropertyHelper(dest, context, "align_content", &val.*[0], val.*[1]); - }, - .@"flex-line-pack" => |*val| this.handlePropertyHelper(dest, context, "flex_line_pack", &val.*[0], val.*[1]), - .@"justify-content" => |*val| { - this.box_pack = null; - this.flex_pack = null; - this.handlePropertyHelper(dest, context, "justify_content", &val.*[0], val.*[1]); - }, - .@"box-pack" => |*val| this.handlePropertyHelper(dest, context, "box_pack", &val.*[0], val.*[1]), - .@"flex-pack" => |*val| this.handlePropertyHelper(dest, context, "flex_pack", &val.*[0], val.*[1]), - .@"place-content" => |*val| { - this.flex_line_pack = null; - this.box_pack = null; - this.flex_pack = null; - this.handlePropertyMaybeFlush(dest, context, "align_content", &val.@"align", VendorPrefix.NONE); - this.handlePropertyMaybeFlush(dest, context, "justify_content", &val.justify, VendorPrefix.NONE); - this.handlePropertyHelper(dest, context, "align_content", &val.@"align", VendorPrefix.NONE); - this.handlePropertyHelper(dest, context, "justify_content", &val.justify, VendorPrefix.NONE); - }, - .@"align-self" => |*val| { - this.flex_item_align = null; - this.handlePropertyHelper(dest, context, "align_self", &val.*[0], val.*[1]); - }, - .@"flex-item-align" => |*val| this.handlePropertyHelper(dest, context, "flex_item_align", &val.*[0], val.*[1]), - .@"justify-self" => |*val| { - this.justify_self = css.generic.deepClone(@TypeOf(val.*), val, context.allocator); - this.has_any = true; - }, - .@"place-self" => |*val| { - this.flex_item_align = null; - this.handlePropertyHelper(dest, context, "align_self", &val.@"align", VendorPrefix.NONE); - this.justify_self = css.generic.deepClone(@TypeOf(val.justify), &val.justify, context.allocator); - }, - .@"align-items" => |*val| { - this.box_align = null; - this.flex_align = null; - this.handlePropertyHelper(dest, context, "align_items", &val.*[0], val.*[1]); - }, - .@"box-align" => |*val| this.handlePropertyHelper(dest, context, "box_align", &val.*[0], val.*[1]), - .@"flex-align" => |*val| this.handlePropertyHelper(dest, context, "flex_align", &val.*[0], val.*[1]), - .@"justify-items" => |*val| { - this.justify_items = css.generic.deepClone(@TypeOf(val.*), val, context.allocator); - this.has_any = true; - }, - .@"place-items" => |*val| { - this.box_align = null; - this.flex_align = null; - this.handlePropertyHelper(dest, context, "align_items", &val.@"align", VendorPrefix.NONE); - this.justify_items = css.generic.deepClone(@TypeOf(val.justify), &val.justify, context.allocator); - }, - .@"row-gap" => |*val| { - this.row_gap = css.generic.deepClone(@TypeOf(val.*), val, context.allocator); - this.has_any = true; - }, - .@"column-gap" => |*val| { - this.column_gap = css.generic.deepClone(@TypeOf(val.*), val, context.allocator); - this.has_any = true; - }, - .gap => |*val| { - this.row_gap = css.generic.deepClone(@TypeOf(val.row), &val.row, context.allocator); - this.column_gap = css.generic.deepClone(@TypeOf(val.column), &val.column, context.allocator); - this.has_any = true; - }, - .unparsed => |*val| { - if (isAlignProperty(val.property_id)) { - this.flush(dest, context); - bun.handleOom(dest.append(context.allocator, property.*)); - } else { - return false; - } - }, - else => return false, - } - - return true; - } - - pub fn finalize(this: *AlignHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - } - - fn flush(this: *AlignHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) { - return; - } - - this.has_any = false; - - var align_content = bun.take(&this.align_content); - var justify_content = bun.take(&this.justify_content); - var align_self = bun.take(&this.align_self); - var justify_self = bun.take(&this.justify_self); - var align_items = bun.take(&this.align_items); - var justify_items = bun.take(&this.justify_items); - const row_gap = bun.take(&this.row_gap); - const column_gap = bun.take(&this.column_gap); - var box_align = bun.take(&this.box_align); - var box_pack = bun.take(&this.box_pack); - var flex_line_pack = bun.take(&this.flex_line_pack); - var flex_pack = bun.take(&this.flex_pack); - var flex_align = bun.take(&this.flex_align); - var flex_item_align = bun.take(&this.flex_item_align); - - // 2009 properties - this.flushPrefixedProperty(dest, context, "box-align", bun.take(&box_align)); - this.flushPrefixedProperty(dest, context, "box-pack", bun.take(&box_pack)); - - // 2012 properties - this.flushPrefixedProperty(dest, context, "flex-pack", bun.take(&flex_pack)); - this.flushPrefixedProperty(dest, context, "flex-align", bun.take(&flex_align)); - this.flushPrefixedProperty(dest, context, "flex-item-align", bun.take(&flex_item_align)); - this.flushPrefixedProperty(dest, context, "flex-line-pack", bun.take(&flex_line_pack)); - - this.flushLegacyProperty(dest, context, Feature.align_content, &align_content, null, .{ FlexLinePack, "flex-line-pack" }); - this.flushLegacyProperty(dest, context, Feature.justify_content, &justify_content, .{ BoxPack, "box-pack" }, .{ FlexPack, "flex-pack" }); - if (context.targets.isCompatible(.place_content)) { - this.flushShorthandHelper( - dest, - context, - .{ .prop = "place-content", .ty = PlaceContent }, - .{ .feature = Feature.align_content, .prop = "align-content" }, - &align_content, - &justify_content, - .{ .feature = Feature.justify_content, .prop = "justify-content" }, - ); - } - this.flushStandardPropertyHelper(dest, context, "align-content", bun.take(&align_content), Feature.align_content); - this.flushStandardPropertyHelper(dest, context, "justify-content", bun.take(&justify_content), Feature.justify_content); - - this.flushLegacyProperty(dest, context, Feature.align_self, &align_self, null, .{ FlexItemAlign, "flex-item-align" }); - if (context.targets.isCompatible(.place_self)) { - this.flushShorthandHelper(dest, context, .{ .prop = "place-self", .ty = PlaceSelf }, .{ .feature = Feature.align_self, .prop = "align-self" }, &align_self, &justify_self, null); - } - this.flushStandardPropertyHelper(dest, context, "align-self", bun.take(&align_self), Feature.align_self); - this.flushUnprefixProperty(dest, context, "justify-self", bun.take(&justify_self)); - - this.flushLegacyProperty(dest, context, Feature.align_items, &align_items, .{ BoxAlign, "box-align" }, .{ FlexAlign, "flex-align" }); - if (context.targets.isCompatible(css.compat.Feature.place_items)) { - this.flushShorthandHelper(dest, context, .{ .prop = "place-items", .ty = PlaceItems }, .{ .feature = Feature.align_items, .prop = "align-items" }, &align_items, &justify_items, null); - } - this.flushStandardPropertyHelper(dest, context, "align-items", bun.take(&align_items), Feature.align_items); - this.flushUnprefixProperty(dest, context, "justify-items", bun.take(&justify_items)); - - if (row_gap != null and column_gap != null) { - dest.append(context.allocator, Property{ .gap = Gap{ - .row = row_gap.?, - .column = column_gap.?, - } }) catch |err| bun.handleOom(err); - } else { - if (row_gap != null) { - bun.handleOom(dest.append(context.allocator, Property{ .@"row-gap" = row_gap.? })); - } - - if (column_gap != null) { - bun.handleOom(dest.append(context.allocator, Property{ .@"column-gap" = column_gap.? })); - } - } - } - - fn handlePropertyMaybeFlush(this: *AlignHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype, vp: VendorPrefix) void { - // If two vendor prefixes for the same property have different - // values, we need to flush what we have immediately to preserve order. - if (@field(this, prop)) |*v| { - if (!val.eql(&v[0]) and !bun.bits.contains(VendorPrefix, v[1], vp)) { - this.flush(dest, context); - } - } - } - - fn handlePropertyHelper(this: *AlignHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype, vp: VendorPrefix) void { - this.handlePropertyMaybeFlush(dest, context, prop, val, vp); - // Otherwise, update the value and add the prefix. - if (@field(this, prop)) |*tuple| { - tuple.*[0] = css.generic.deepClone(@TypeOf(val.*), val, context.allocator); - bun.bits.insert(VendorPrefix, &tuple.*[1], vp); - } else { - @field(this, prop) = .{ css.generic.deepClone(@TypeOf(val.*), val, context.allocator), vp }; - this.has_any = true; - } - } - - // Gets prefixes for standard properties. - fn flushPrefixesHelper(_: *AlignHandler, context: *css.PropertyHandlerContext, comptime feature: Feature) VendorPrefix { - var prefix = context.targets.prefixes(VendorPrefix.NONE, feature); - // Firefox only implemented the 2009 spec prefixed. - // Microsoft only implemented the 2012 spec prefixed. - prefix.moz = false; - prefix.ms = false; - return prefix; - } - - fn flushStandardPropertyHelper(this: *AlignHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, key: anytype, comptime feature: Feature) void { - if (key) |v| { - const val = v[0]; - var prefix = v[1]; - // If we have an unprefixed property, override necessary prefixes. - prefix = if (prefix.none) flushPrefixesHelper(this, context, feature) else prefix; - bun.handleOom(dest.append(context.allocator, @unionInit(Property, prop, .{ val, prefix }))); - } - } - - fn flushLegacyProperty( - this: *AlignHandler, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - comptime feature: Feature, - key: anytype, - comptime prop_2009: ?struct { type, []const u8 }, - comptime prop_2012: ?struct { type, []const u8 }, - ) void { - _ = this; // autofix - if (key.*) |v| { - const val = v[0]; - var prefix = v[1]; - // If we have an unprefixed standard property, generate legacy prefixed versions. - prefix = context.targets.prefixes(prefix, feature); - - if (prefix.none) { - if (comptime prop_2009) |p2009| { - // 2009 spec, implemented by webkit and firefox. - if (context.targets.browsers) |targets| { - var prefixes_2009 = VendorPrefix{}; - if (Feature.isFlex2009(targets)) { - prefixes_2009.webkit = true; - } - if (prefix.moz) { - prefixes_2009.moz = true; - } - if (!prefixes_2009.isEmpty()) { - const s = brk: { - const T = comptime p2009[0]; - if (comptime T == css.css_properties.flex.BoxOrdinalGroup) break :brk @as(?i32, val); - break :brk p2009[0].fromStandard(&val); - }; - if (s) |a| { - dest.append(context.allocator, @unionInit(Property, p2009[1], .{ - a, - prefixes_2009, - })) catch |err| bun.handleOom(err); - } - } - } - } - } - - // 2012 spec, implemented by microsoft. - if (prefix.ms) { - if (comptime prop_2012) |p2012| { - const s = brk: { - const T = comptime p2012[0]; - if (comptime T == css.css_properties.flex.BoxOrdinalGroup) break :brk @as(?i32, val); - break :brk p2012[0].fromStandard(&val); - }; - if (s) |q| { - dest.append(context.allocator, @unionInit(Property, p2012[1], .{ - q, - VendorPrefix.MS, - })) catch |err| bun.handleOom(err); - } - } - } - - // Remove Firefox and IE from standard prefixes. - prefix.moz = false; - prefix.ms = false; - } - } - - fn flushPrefixedProperty(this: *AlignHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, key: anytype) void { - _ = this; // autofix - if (key) |v| { - const val = v[0]; - const prefix = v[1]; - bun.handleOom(dest.append(context.allocator, @unionInit(Property, prop, .{ val, prefix }))); - } - } - - fn flushUnprefixProperty(this: *AlignHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, key: anytype) void { - _ = this; // autofix - if (key) |v| { - const val = v; - bun.handleOom(dest.append(context.allocator, @unionInit(Property, prop, val))); - } - } - - fn flushShorthandHelper( - this: *AlignHandler, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - comptime prop: struct { prop: []const u8, ty: type }, - comptime align_prop: struct { - feature: Feature, - prop: []const u8, - }, - align_val: anytype, - justify_val: anytype, - comptime justify_prop: ?struct { - feature: Feature, - prop: []const u8, - }, - ) void { - // Only use shorthand if both align and justify are present - if (align_val.*) |*__v1| { - const @"align" = &__v1.*[0]; - const align_prefix: *css.VendorPrefix = &__v1.*[1]; - if (justify_val.*) |*__v2| { - const justify = __v2; - - const intersection = align_prefix.bitwiseAnd(if (comptime justify_prop != null) __v2.*[1] else align_prefix.*); - // Only use shorthand if unprefixed. - if (intersection.none) { - // Add prefixed longhands if needed. - align_prefix.* = flushPrefixesHelper(this, context, align_prop.feature); - align_prefix.none = false; - if (!align_prefix.isEmpty()) { - dest.append( - context.allocator, - @unionInit(Property, align_prop.prop, .{ css.generic.deepClone(@TypeOf(@"align".*), @"align", context.allocator), align_prefix.* }), - ) catch |err| bun.handleOom(err); - } - - if (comptime justify_prop != null) { - const justify_actual = &__v2.*[0]; - const justify_prefix = &__v2.*[1]; - justify_prefix.* = this.flushPrefixesHelper(context, justify_prop.?.feature); - justify_prefix.none = false; - - if (!justify_prefix.isEmpty()) { - dest.append( - context.allocator, - @unionInit(Property, justify_prop.?.prop, .{ css.generic.deepClone(@TypeOf(justify_actual.*), justify_actual, context.allocator), justify_prefix.* }), - ) catch |err| bun.handleOom(err); - } - - // Add shorthand. - dest.append( - context.allocator, - @unionInit(Property, prop.prop, prop.ty{ - .@"align" = css.generic.deepClone(@TypeOf(@"align".*), @"align", context.allocator), - .justify = css.generic.deepClone(@TypeOf(justify_actual.*), justify_actual, context.allocator), - }), - ) catch |err| bun.handleOom(err); - } else { - - // Add shorthand. - dest.append( - context.allocator, - @unionInit(Property, prop.prop, prop.ty{ - .@"align" = css.generic.deepClone(@TypeOf(@"align".*), @"align", context.allocator), - .justify = css.generic.deepClone(@TypeOf(justify.*), justify, context.allocator), - }), - ) catch |err| bun.handleOom(err); - } - - align_val.* = null; - justify_val.* = null; - } - } - } - } -}; - -fn isAlignProperty(property_id: css.PropertyId) bool { - return switch (property_id) { - .@"align-content", - .@"flex-line-pack", - .@"justify-content", - .@"box-pack", - .@"flex-pack", - .@"place-content", - .@"align-self", - .@"flex-item-align", - .@"justify-self", - .@"place-self", - .@"align-items", - .@"box-align", - .@"flex-align", - .@"justify-items", - .@"place-items", - .@"row-gap", - .@"column-gap", - .gap, - => true, - else => false, - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/animation.zig b/src/css/properties/animation.zig deleted file mode 100644 index 26809b936950..000000000000 --- a/src/css/properties/animation.zig +++ /dev/null @@ -1,515 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const LengthPercentage = css.css_values.length.LengthPercentage; -const CustomIdent = css.css_values.ident.CustomIdent; -const CSSString = css.css_values.string.CSSString; -const CSSNumber = css.css_values.number.CSSNumber; -const LengthPercentageOrAuto = css.css_values.length.LengthPercentageOrAuto; -const Size2D = css.css_values.size.Size2D; -const DashedIdent = css.css_values.ident.DashedIdent; -const Time = css.css_values.time.Time; -const EasingFunction = css.css_values.easing.EasingFunction; - -/// A list of animations. -pub const AnimationList = SmallList(Animation, 1); - -/// A list of animation names. -pub const AnimationNameList = SmallList(AnimationName, 1); - -/// A value for the [animation](https://drafts.csswg.org/css-animations/#animation) shorthand property. -pub const Animation = struct { - /// The animation name. - name: AnimationName, - /// The animation duration. - duration: Time, - /// The easing function for the animation. - timing_function: EasingFunction, - /// The number of times the animation will run. - iteration_count: AnimationIterationCount, - /// The direction of the animation. - direction: AnimationDirection, - /// The current play state of the animation. - play_state: AnimationPlayState, - /// The animation delay. - delay: Time, - /// The animation fill mode. - fill_mode: AnimationFillMode, - /// The animation timeline. - timeline: AnimationTimeline, - - pub const PropertyFieldMap = .{ - .name = css.PropertyIdTag.@"animation-name", - .duration = css.PropertyIdTag.@"animation-duration", - .timing_function = css.PropertyIdTag.@"animation-timing-function", - .iteration_count = css.PropertyIdTag.@"animation-iteration-count", - .direction = css.PropertyIdTag.@"animation-direction", - .play_state = css.PropertyIdTag.@"animation-play-state", - .delay = css.PropertyIdTag.@"animation-delay", - .fill_mode = css.PropertyIdTag.@"animation-fill-mode", - .timeline = css.PropertyIdTag.@"animation-timeline", - }; - - pub const VendorPrefixMap = .{ - .name = true, - .duration = true, - .timing_function = true, - .iteration_count = true, - .direction = true, - .play_state = true, - .delay = true, - .fill_mode = true, - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var name: ?AnimationName = null; - var duration: ?Time = null; - var timing_function: ?EasingFunction = null; - var iteration_count: ?AnimationIterationCount = null; - var direction: ?AnimationDirection = null; - var play_state: ?AnimationPlayState = null; - var delay: ?Time = null; - var fill_mode: ?AnimationFillMode = null; - var timeline: ?AnimationTimeline = null; - - while (true) { - if (duration == null) { - if (input.tryParse(Time.parse, .{})) |value| { - duration = value; - continue; - } - } - if (timing_function == null) { - if (input.tryParse(EasingFunction.parse, .{})) |value| { - timing_function = value; - continue; - } - } - if (delay == null) { - if (input.tryParse(Time.parse, .{})) |value| { - delay = value; - continue; - } - } - if (iteration_count == null) { - if (input.tryParse(AnimationIterationCount.parse, .{})) |value| { - iteration_count = value; - continue; - } - } - if (direction == null) { - if (input.tryParse(AnimationDirection.parse, .{})) |value| { - direction = value; - continue; - } - } - if (fill_mode == null) { - if (input.tryParse(AnimationFillMode.parse, .{})) |value| { - fill_mode = value; - continue; - } - } - if (play_state == null) { - if (input.tryParse(AnimationPlayState.parse, .{})) |value| { - play_state = value; - continue; - } - } - if (name == null) { - if (input.tryParse(AnimationName.parse, .{})) |value| { - name = value; - continue; - } - } - if (timeline == null) { - if (input.tryParse(AnimationTimeline.parse, .{})) |value| { - timeline = value; - continue; - } - } - break; - } - - return .{ - .result = Animation{ - .name = name orelse AnimationName.none, - .duration = duration orelse Time{ .seconds = 0.0 }, - .timing_function = timing_function orelse EasingFunction.ease, - .iteration_count = iteration_count orelse AnimationIterationCount.number(1), - .direction = direction orelse AnimationDirection.normal, - .play_state = play_state orelse AnimationPlayState.running, - .delay = delay orelse Time{ .seconds = 0.0 }, - .fill_mode = fill_mode orelse AnimationFillMode.none, - .timeline = timeline orelse AnimationTimeline.auto, - }, - }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - switch (this.name) { - .none => {}, - inline .ident, .string => |name| { - const name_str = if (this.name == .ident) name.v else name; - - if (!this.duration.isZero() or !this.delay.isZero()) { - try this.duration.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.timing_function.isEase() or EasingFunction.isIdent(name_str)) { - try this.timing_function.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.delay.isZero()) { - try this.delay.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.iteration_count.eql(&AnimationIterationCount.default()) or bun.strings.eqlCaseInsensitiveASCII(name_str, "infinite")) { - try this.iteration_count.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.direction.eql(&AnimationDirection.default()) or css.parse_utility.parseString( - dest.allocator, - AnimationDirection, - name_str, - AnimationDirection.parse, - ).isOk()) { - try this.direction.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.fill_mode.eql(&AnimationFillMode.default()) or - (!bun.strings.eqlCaseInsensitiveASCII(name_str, "none") and css.parse_utility.parseString(dest.allocator, AnimationFillMode, name_str, AnimationFillMode.parse).isOk())) - { - try this.fill_mode.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.play_state.eql(&AnimationPlayState.default()) or css.parse_utility.parseString( - dest.allocator, - AnimationPlayState, - name_str, - AnimationPlayState.parse, - ).isOk()) { - try this.play_state.toCss(dest); - try dest.writeChar(' '); - } - }, - } - - try this.name.toCss(dest); - - if (!this.name.eql(&AnimationName.none) and !this.timeline.eql(&AnimationTimeline.default())) { - try dest.writeChar(' '); - try this.timeline.toCss(dest); - } - } -}; - -/// A value for the [animation-name](https://drafts.csswg.org/css-animations/#animation-name) property. -pub const AnimationName = union(enum) { - /// The `none` keyword. - none, - /// An identifier of a `@keyframes` rule. - ident: CustomIdent, - /// A `` name of a `@keyframes` rule. - string: CSSString, - - // ~toCssImpl - const This = @This(); - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - const css_module_animation_enabled = if (dest.css_module) |css_module| - css_module.config.animation - else - false; - - switch (this.*) { - .none => return dest.writeStr("none"), - .ident => |s| { - if (css_module_animation_enabled) { - if (dest.css_module) |*css_module| { - css_module.getReference(dest.allocator, s.v, dest.loc.source_index); - } - } - return s.toCssWithOptions(dest, css_module_animation_enabled); - }, - .string => |s| { - if (css_module_animation_enabled) { - if (dest.css_module) |*css_module| { - css_module.getReference(dest.allocator, s, dest.loc.source_index); - } - } - - // CSS-wide keywords and `none` cannot remove quotes - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "none") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "initial") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "inherit") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "unset") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "default") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "revert") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "revert-layer")) - { - css.serializer.serializeString(s, dest) catch return dest.addFmtError(); - return; - } - - return dest.writeIdent(s, css_module_animation_enabled); - }, - } - } -}; - -/// A value for the [animation-iteration-count](https://drafts.csswg.org/css-animations/#animation-iteration-count) property. -pub const AnimationIterationCount = union(enum) { - /// The animation will repeat the specified number of times. - number: CSSNumber, - /// The animation will repeat forever. - infinite, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn default() AnimationIterationCount { - return .{ .number = 1.0 }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [animation-direction](https://drafts.csswg.org/css-animations/#animation-direction) property. -pub const AnimationDirection = enum { - /// The animation is played as specified - normal, - /// The animation is played in reverse. - reverse, - /// The animation iterations alternate between forward and reverse. - alternate, - /// The animation iterations alternate between forward and reverse, with reverse occurring first. - @"alternate-reverse", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() AnimationDirection { - return .normal; - } -}; - -/// A value for the [animation-play-state](https://drafts.csswg.org/css-animations/#animation-play-state) property. -pub const AnimationPlayState = enum { - /// The animation is playing. - running, - /// The animation is paused. - paused, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() AnimationPlayState { - return .running; - } -}; - -/// A value for the [animation-fill-mode](https://drafts.csswg.org/css-animations/#animation-fill-mode) property. -pub const AnimationFillMode = enum { - /// The animation has no effect while not playing. - none, - /// After the animation, the ending values are applied. - forwards, - /// Before the animation, the starting values are applied. - backwards, - /// Both forwards and backwards apply. - both, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() AnimationFillMode { - return .none; - } -}; - -/// A value for the [animation-composition](https://drafts.csswg.org/css-animations-2/#animation-composition) property. -pub const AnimationComposition = enum { - /// The result of compositing the effect value with the underlying value is simply the effect value. - replace, - /// The effect value is added to the underlying value. - add, - /// The effect value is accumulated onto the underlying value. - accumulate, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [animation-timeline](https://drafts.csswg.org/css-animations-2/#animation-timeline) property. -pub const AnimationTimeline = union(enum) { - /// The animation's timeline is a DocumentTimeline, more specifically the default document timeline. - auto, - /// The animation is not associated with a timeline. - none, - /// A timeline referenced by name. - dashed_ident: DashedIdent, - /// The scroll() function. - scroll: ScrollTimeline, - /// The view() function. - view: ViewTimeline, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn default() AnimationTimeline { - return .auto; - } -}; - -/// The [scroll()](https://drafts.csswg.org/scroll-animations-1/#scroll-notation) function. -pub const ScrollTimeline = struct { - /// Specifies which element to use as the scroll container. - scroller: Scroller, - /// Specifies which axis of the scroll container to use as the progress for the timeline. - axis: ScrollAxis, -}; - -/// The [view()](https://drafts.csswg.org/scroll-animations-1/#view-notation) function. -pub const ViewTimeline = struct { - /// Specifies which axis of the scroll container to use as the progress for the timeline. - axis: ScrollAxis, - /// Provides an adjustment of the view progress visibility range. - inset: Size2D(LengthPercentageOrAuto), -}; - -/// A scroller, used in the `scroll()` function. -pub const Scroller = enum { - /// Specifies to use the document viewport as the scroll container. - root, - /// Specifies to use the nearest ancestor scroll container. - nearest, - /// Specifies to use the element's own principal box as the scroll container. - self, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() Scroller { - return .nearest; - } -}; - -/// A scroll axis, used in the `scroll()` function. -pub const ScrollAxis = enum { - /// Specifies to use the measure of progress along the block axis of the scroll container. - block, - /// Specifies to use the measure of progress along the inline axis of the scroll container. - @"inline", - /// Specifies to use the measure of progress along the horizontal axis of the scroll container. - x, - /// Specifies to use the measure of progress along the vertical axis of the scroll container. - y, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() ScrollAxis { - return .block; - } -}; - -/// A value for the animation-range shorthand property. -pub const AnimationRange = struct { - /// The start of the animation's attachment range. - start: AnimationRangeStart, - /// The end of the animation's attachment range. - end: AnimationRangeEnd, -}; - -/// A value for the [animation-range-start](https://drafts.csswg.org/scroll-animations/#animation-range-start) property. -pub const AnimationRangeStart = struct { - v: AnimationAttachmentRange, -}; - -/// A value for the [animation-range-end](https://drafts.csswg.org/scroll-animations/#animation-range-start) property. -pub const AnimationRangeEnd = struct { - v: AnimationAttachmentRange, -}; - -/// A value for the [animation-range-start](https://drafts.csswg.org/scroll-animations/#animation-range-start) -/// or [animation-range-end](https://drafts.csswg.org/scroll-animations/#animation-range-end) property. -pub const AnimationAttachmentRange = union(enum) { - /// The start of the animation's attachment range is the start of its associated timeline. - normal, - /// The animation attachment range starts at the specified point on the timeline measuring from the start of the timeline. - length_percentage: LengthPercentage, - /// The animation attachment range starts at the specified point on the timeline measuring from the start of the specified named timeline range. - timeline_range: struct { - /// The name of the timeline range. - name: TimelineRangeName, - /// The offset from the start of the named timeline range. - offset: LengthPercentage, - }, -}; - -/// A [view progress timeline range](https://drafts.csswg.org/scroll-animations/#view-timelines-ranges) -pub const TimelineRangeName = enum { - /// Represents the full range of the view progress timeline. - cover, - /// Represents the range during which the principal box is either fully contained by, - /// or fully covers, its view progress visibility range within the scrollport. - contain, - /// Represents the range during which the principal box is entering the view progress visibility range. - entry, - /// Represents the range during which the principal box is exiting the view progress visibility range. - exit, - /// Represents the range during which the principal box crosses the end border edge. - entry_crossing, - /// Represents the range during which the principal box crosses the start border edge. - exit_crossing, -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/properties/background.zig b/src/css/properties/background.zig deleted file mode 100644 index 62162dbadd19..000000000000 --- a/src/css/properties/background.zig +++ /dev/null @@ -1,1068 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Property = css.Property; -const VendorPrefix = css.VendorPrefix; -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const LengthPercentageOrAuto = css.css_values.length.LengthPercentageOrAuto; -const Image = css.css_values.image.Image; -const CssColor = css.css_values.color.CssColor; -const Ratio = css.css_values.ratio.Ratio; -const HorizontalPosition = css.css_values.position.HorizontalPosition; -const VerticalPosition = css.css_values.position.VerticalPosition; - -const Position = css.css_values.position.Position; - -/// A value for the [background](https://www.w3.org/TR/css-backgrounds-3/#background) shorthand property. -pub const Background = struct { - /// The background image. - image: Image, - /// The background color. - color: CssColor, - /// The background position. - position: BackgroundPosition, - /// How the background image should repeat. - repeat: BackgroundRepeat, - /// The size of the background image. - size: BackgroundSize, - /// The background attachment. - attachment: BackgroundAttachment, - /// The background origin. - origin: BackgroundOrigin, - /// How the background should be clipped. - clip: BackgroundClip, - - pub fn deinit(_: *@This(), _: Allocator) void { - // TODO: implement this - // not necessary right now because all allocations in CSS parser are in arena - } - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var color: ?CssColor = null; - var position: ?BackgroundPosition = null; - var size: ?BackgroundSize = null; - var image: ?Image = null; - var repeat: ?BackgroundRepeat = null; - var attachment: ?BackgroundAttachment = null; - var origin: ?BackgroundOrigin = null; - var clip: ?BackgroundClip = null; - - while (true) { - // TODO: only allowed on the last background. - if (color == null) { - if (input.tryParse(CssColor.parse, .{}).asValue()) |value| { - color = value; - continue; - } - } - - if (position == null) { - if (input.tryParse(BackgroundPosition.parse, .{}).asValue()) |value| { - position = value; - - size = input.tryParse(struct { - fn parse(i: *css.Parser) css.Result(BackgroundSize) { - if (i.expectDelim('/').asErr()) |e| return .{ .err = e }; - return BackgroundSize.parse(i); - } - }.parse, .{}).asValue(); - - continue; - } - } - - if (image == null) { - if (input.tryParse(Image.parse, .{}).asValue()) |value| { - image = value; - continue; - } - } - - if (repeat == null) { - if (input.tryParse(BackgroundRepeat.parse, .{}).asValue()) |value| { - repeat = value; - continue; - } - } - - if (attachment == null) { - if (input.tryParse(BackgroundAttachment.parse, .{}).asValue()) |value| { - attachment = value; - continue; - } - } - - if (origin == null) { - if (input.tryParse(BackgroundOrigin.parse, .{}).asValue()) |value| { - origin = value; - continue; - } - } - - if (clip == null) { - if (input.tryParse(BackgroundClip.parse, .{}).asValue()) |value| { - clip = value; - continue; - } - } - - break; - } - - if (clip == null) { - if (origin) |o| { - clip = @as(BackgroundClip, @enumFromInt(@intFromEnum(o))); - } - } - - return .{ .result = .{ - .image = image orelse Image.default(), - .color = color orelse CssColor.default(), - .position = position orelse BackgroundPosition.default(), - .repeat = repeat orelse BackgroundRepeat.default(), - .size = size orelse BackgroundSize.default(), - .attachment = attachment orelse BackgroundAttachment.default(), - .origin = origin orelse .@"padding-box", - .clip = clip orelse .@"border-box", - } }; - } - - pub fn toCss(this: *const Background, dest: *Printer) PrintErr!void { - var has_output = false; - - if (!this.color.eql(&CssColor.default())) { - try this.color.toCss(dest); - has_output = true; - } - - if (!this.image.eql(&Image.default())) { - if (has_output) try dest.writeStr(" "); - try this.image.toCss(dest); - has_output = true; - } - - const position: Position = this.position.intoPosition(); - if (!position.isZero() or !this.size.eql(&BackgroundSize.default())) { - if (has_output) { - try dest.writeStr(" "); - } - try position.toCss(dest); - - if (!this.size.eql(&BackgroundSize.default())) { - try dest.delim('/', true); - try this.size.toCss(dest); - } - - has_output = true; - } - - if (!this.repeat.eql(&BackgroundRepeat.default())) { - if (has_output) try dest.writeStr(" "); - try this.repeat.toCss(dest); - has_output = true; - } - - if (!this.attachment.eql(&BackgroundAttachment.default())) { - if (has_output) try dest.writeStr(" "); - try this.attachment.toCss(dest); - has_output = true; - } - - const output_padding_box = !this.origin.eql(&BackgroundOrigin.@"padding-box") or - (!this.clip.eqlOrigin(&BackgroundOrigin.@"border-box") and this.clip.isBackgroundBox()); - - if (output_padding_box) { - if (has_output) try dest.writeStr(" "); - try this.origin.toCss(dest); - has_output = true; - } - - if ((output_padding_box and !this.clip.eqlOrigin(&BackgroundOrigin.@"border-box")) or - !this.clip.eqlOrigin(&BackgroundOrigin.@"border-box")) - { - if (has_output) try dest.writeStr(" "); - - try this.clip.toCss(dest); - has_output = true; - } - - // If nothing was output, then this is the initial value, e.g. background: transparent - if (!has_output) { - if (dest.minify) { - // `0 0` is the shortest valid background value - try this.position.toCss(dest); - } else { - try dest.writeStr("none"); - } - } - } - - pub fn getImage(this: *const @This()) *const Image { - return &this.image; - } - - pub fn withImage(this: *const @This(), allocator: Allocator, image: Image) @This() { - var ret = this.*; - ret.image = .none; - ret = ret.deepClone(allocator); - ret.image = image; - return ret; - } - - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: css.ColorFallbackKind) Background { - var ret: Background = this.*; - // Dummy values for the clone - ret.color = CssColor.default(); - ret.image = Image.default(); - ret = ret.deepClone(allocator); - ret.color = this.color.getFallback(allocator, kind); - ret.image = this.image.getFallback(allocator, kind); - return ret; - } - - pub fn getNecessaryFallbacks(this: *const @This(), targets: css.targets.Targets) css.ColorFallbackKind { - return bun.bits.@"or"( - css.ColorFallbackKind, - this.color.getNecessaryFallbacks(targets), - this.getImage().getNecessaryFallbacks(targets), - ); - } - - pub inline fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [background-size](https://www.w3.org/TR/css-backgrounds-3/#background-size) property. -pub const BackgroundSize = union(enum) { - /// An explicit background size. - explicit: struct { - /// The width of the background. - width: css.css_values.length.LengthPercentageOrAuto, - /// The height of the background. - height: css.css_values.length.LengthPercentageOrAuto, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub inline fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// The `cover` keyword. Scales the background image to cover both the width and height of the element. - cover, - /// The `contain` keyword. Scales the background image so that it fits within the element. - contain, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(LengthPercentageOrAuto.parse, .{}).asValue()) |width| { - const height = input.tryParse(LengthPercentageOrAuto.parse, .{}).unwrapOr(.auto); - return .{ .result = .{ .explicit = .{ .width = width, .height = height } } }; - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "cover")) { - return .{ .result = .cover }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "contain")) { - return .{ .result = .contain }; - } else { - return .{ .err = location.newBasicUnexpectedTokenError(.{ .ident = ident }) }; - } - } - - pub fn toCss(this: *const BackgroundSize, dest: *Printer) PrintErr!void { - return switch (this.*) { - .cover => dest.writeStr("cover"), - .contain => dest.writeStr("contain"), - .explicit => |explicit| { - try explicit.width.toCss(dest); - if (explicit.height != .auto) { - try dest.writeStr(" "); - try explicit.height.toCss(dest); - } - return; - }, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn default() @This() { - return BackgroundSize{ .explicit = .{ - .width = .auto, - .height = .auto, - } }; - } - - pub inline fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [background-position](https://drafts.csswg.org/css-backgrounds/#background-position) shorthand property. -pub const BackgroundPosition = struct { - /// The x-position. - x: HorizontalPosition, - /// The y-position. - y: VerticalPosition, - - const PropertyFieldMap = .{ - .x = css.PropertyIdTag.@"background-position-x", - .y = css.PropertyIdTag.@"background-position-y", - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const pos = switch (css.css_values.position.Position.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = BackgroundPosition.fromPosition(pos) }; - } - - pub fn toCss(this: *const BackgroundPosition, dest: *Printer) PrintErr!void { - const pos = this.intoPosition(); - return pos.toCss(dest); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn default() @This() { - return BackgroundPosition.fromPosition(Position.default()); - } - - pub fn fromPosition(pos: Position) BackgroundPosition { - return BackgroundPosition{ .x = pos.x, .y = pos.y }; - } - - pub fn intoPosition(this: *const BackgroundPosition) Position { - return Position{ .x = this.x, .y = this.y }; - } - - pub inline fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [background-repeat](https://www.w3.org/TR/css-backgrounds-3/#background-repeat) property. -pub const BackgroundRepeat = struct { - /// A repeat style for the x direction. - x: BackgroundRepeatKeyword, - /// A repeat style for the y direction. - y: BackgroundRepeatKeyword, - - pub fn default() @This() { - return BackgroundRepeat{ - .x = .repeat, - .y = .repeat, - }; - } - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const state = input.state(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "repeat-x")) { - return .{ .result = .{ .x = .repeat, .y = .@"no-repeat" } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "repeat-y")) { - return .{ .result = .{ .x = .@"no-repeat", .y = .repeat } }; - } - - input.reset(&state); - - const x = switch (BackgroundRepeatKeyword.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - const y = input.tryParse(BackgroundRepeatKeyword.parse, .{}).unwrapOr(x); - - return .{ .result = .{ .x = x, .y = y } }; - } - - pub fn toCss(this: *const BackgroundRepeat, dest: *Printer) PrintErr!void { - const Repeat = BackgroundRepeatKeyword.repeat; - const NoRepeat = BackgroundRepeatKeyword.@"no-repeat"; - - if (this.x == Repeat and this.y == NoRepeat) { - return dest.writeStr("repeat-x"); - } else if (this.x == NoRepeat and this.y == Repeat) { - return dest.writeStr("repeat-y"); - } else { - try this.x.toCss(dest); - if (this.y != this.x) { - try dest.writeStr(" "); - try this.y.toCss(dest); - } - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [``](https://www.w3.org/TR/css-backgrounds-3/#typedef-repeat-style) value, -/// used within the `background-repeat` property to represent how a background image is repeated -/// in a single direction. -/// -/// See [BackgroundRepeat](BackgroundRepeat). -pub const BackgroundRepeatKeyword = enum { - /// The image is repeated in this direction. - repeat, - /// The image is repeated so that it fits, and then spaced apart evenly. - space, - /// The image is scaled so that it repeats an even number of times. - round, - /// The image is placed once and not repeated in this direction. - @"no-repeat", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [background-attachment](https://www.w3.org/TR/css-backgrounds-3/#background-attachment) property. -pub const BackgroundAttachment = enum { - /// The background scrolls with the container. - scroll, - /// The background is fixed to the viewport. - fixed, - /// The background is fixed with regard to the element's contents. - local, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() @This() { - return .scroll; - } -}; - -/// A value for the [background-origin](https://www.w3.org/TR/css-backgrounds-3/#background-origin) property. -pub const BackgroundOrigin = enum { - /// The position is relative to the border box. - @"border-box", - /// The position is relative to the padding box. - @"padding-box", - /// The position is relative to the content box. - @"content-box", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [background-clip](https://drafts.csswg.org/css-backgrounds-4/#background-clip) property. -pub const BackgroundClip = enum { - /// The background is clipped to the border box. - @"border-box", - /// The background is clipped to the padding box. - @"padding-box", - /// The background is clipped to the content box. - @"content-box", - /// The background is clipped to the area painted by the border. - border, - /// The background is clipped to the text content of the element. - text, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() BackgroundClip { - return .@"border-box"; - } - - pub fn eqlOrigin(this: *const @This(), other: *const BackgroundOrigin) bool { - return switch (this.*) { - .@"border-box" => other.* == .@"border-box", - .@"padding-box" => other.* == .@"padding-box", - .@"content-box" => other.* == .@"content-box", - else => false, - }; - } - - pub fn isBackgroundBox(this: *const @This()) bool { - return switch (this.*) { - .@"border-box", .@"padding-box", .@"content-box" => true, - else => false, - }; - } -}; - -/// A value for the [aspect-ratio](https://drafts.csswg.org/css-sizing-4/#aspect-ratio) property. -pub const AspectRatio = struct { - /// The `auto` keyword. - auto: bool, - /// A preferred aspect ratio for the box, specified as width / height. - ratio: ?Ratio, -}; - -pub const BackgroundProperty = packed struct(u16) { - color: bool = false, - image: bool = false, - @"position-x": bool = false, - @"position-y": bool = false, - repeat: bool = false, - size: bool = false, - attachment: bool = false, - origin: bool = false, - clip: bool = false, - __unused: u7 = 0, - - pub const @"background-color" = BackgroundProperty{ .color = true }; - pub const @"background-image" = BackgroundProperty{ .image = true }; - pub const @"background-position-x" = BackgroundProperty{ .@"position-x" = true }; - pub const @"background-position-y" = BackgroundProperty{ .@"position-y" = true }; - pub const @"background-position" = BackgroundProperty{ .@"position-x" = true, .@"position-y" = true }; - pub const @"background-repeat" = BackgroundProperty{ .repeat = true }; - pub const @"background-size" = BackgroundProperty{ .size = true }; - pub const @"background-attachment" = BackgroundProperty{ .attachment = true }; - pub const @"background-origin" = BackgroundProperty{ .origin = true }; - pub const @"background-clip" = BackgroundProperty{ .clip = true }; - - pub const background = BackgroundProperty{ - .color = true, - .image = true, - .@"position-x" = true, - .@"position-y" = true, - .repeat = true, - .size = true, - .attachment = true, - .origin = true, - .clip = true, - }; - - pub fn isEmpty(this: @This()) bool { - return bun.bits.asInt(@This(), this) == 0; - } - - pub fn tryFromPropertyId(property_id: css.PropertyId) ?BackgroundProperty { - return switch (property_id) { - .@"background-color" => @"background-color", - .@"background-image" => @"background-image", - .@"background-position-x" => @"background-position-x", - .@"background-position-y" => @"background-position-y", - .@"background-position" => @"background-position", - .@"background-repeat" => @"background-repeat", - .@"background-size" => @"background-size", - .@"background-attachment" => @"background-attachment", - .@"background-origin" => @"background-origin", - .background => background, - else => null, - }; - } -}; - -pub const BackgroundHandler = struct { - color: ?CssColor = null, - images: ?css.SmallList(Image, 1) = null, - has_prefix: bool = false, - x_positions: ?css.SmallList(HorizontalPosition, 1) = null, - y_positions: ?css.SmallList(VerticalPosition, 1) = null, - repeats: ?css.SmallList(BackgroundRepeat, 1) = null, - sizes: ?css.SmallList(BackgroundSize, 1) = null, - attachments: ?css.SmallList(BackgroundAttachment, 1) = null, - origins: ?css.SmallList(BackgroundOrigin, 1) = null, - clips: ?struct { css.SmallList(BackgroundClip, 1), VendorPrefix } = null, - decls: ArrayList(Property) = undefined, - flushed_properties: BackgroundProperty = undefined, - has_any: bool = false, - - pub fn handleProperty( - this: *BackgroundHandler, - property: *const Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) bool { - const allocator = context.allocator; - switch (property.*) { - .@"background-color" => |*val| { - this.flushHelper(allocator, "color", CssColor, val, dest, context); - this.color = val.deepClone(allocator); - }, - .@"background-image" => |*val| { - this.backgroundHelper(allocator, SmallList(Image, 1), val, property, dest, context); - this.images = val.deepClone(allocator); - }, - .@"background-position" => |val| { - const x_positions = this.initSmallListHelper(HorizontalPosition, 1, "x_positions", allocator, val.len()); - const y_positions = this.initSmallListHelper(VerticalPosition, 1, "y_positions", allocator, val.len()); - for (val.slice(), x_positions, y_positions) |position, *x, *y| { - x.* = position.x.deepClone(allocator); - y.* = position.y.deepClone(allocator); - } - }, - .@"background-position-x" => |val| { - if (this.x_positions) |*x_positions| x_positions.deinit(allocator); - this.x_positions = val.deepClone(allocator); - }, - .@"background-position-y" => |val| { - if (this.y_positions) |*y_positions| y_positions.deinit(allocator); - this.y_positions = val.deepClone(allocator); - }, - .@"background-repeat" => |val| { - if (this.repeats) |*repeats| repeats.deinit(allocator); - this.repeats = val.deepClone(allocator); - }, - .@"background-size" => |val| { - if (this.sizes) |*sizes| sizes.deinit(allocator); - this.sizes = val.deepClone(allocator); - }, - .@"background-attachment" => |val| { - if (this.attachments) |*attachments| attachments.deinit(allocator); - this.attachments = val.deepClone(allocator); - }, - .@"background-origin" => |val| { - if (this.origins) |*origins| origins.deinit(allocator); - this.origins = val.deepClone(allocator); - }, - .@"background-clip" => |*x| { - const val: *const SmallList(BackgroundClip, 1) = &x.*[0]; - const vendor_prefix: VendorPrefix = x.*[1]; - if (this.clips) |*clips_and_vp| { - var clips: *SmallList(BackgroundClip, 1) = &clips_and_vp.*[0]; - const vp: *VendorPrefix = &clips_and_vp.*[1]; - if (vendor_prefix != vp.* and !val.eql(clips)) { - // `flush()` takes ownership of `this.clips` via `bun.take` and - // frees it, so `clips` (which aliases the payload of `this.clips`) - // is a stale pointer once `flush()` returns. Do not touch it. - this.flush(allocator, dest, context); - this.clips = .{ val.deepClone(allocator), vendor_prefix }; - } else { - if (!val.eql(clips)) { - clips.deinit(allocator); - clips.* = val.deepClone(allocator); - } - bun.bits.insert(VendorPrefix, vp, vendor_prefix); - } - } else { - this.clips = .{ val.deepClone(allocator), vendor_prefix }; - } - }, - .background => |*val| { - var images = SmallList(Image, 1).initCapacity(allocator, val.len()); - for (val.slice()) |*b| { - images.appendAssumeCapacity(b.image.deepClone(allocator)); - } - this.backgroundHelper(allocator, SmallList(Image, 1), &images, property, dest, context); - const color = val.last().?.color.deepClone(allocator); - this.flushHelper(allocator, "color", CssColor, &color, dest, context); - var clips = SmallList(BackgroundClip, 1).initCapacity(allocator, val.len()); - for (val.slice()) |*b| { - clips.appendAssumeCapacity(b.clip.deepClone(allocator)); - } - var clips_vp = VendorPrefix{ .none = true }; - if (this.clips) |*clips_and_vp| { - if (clips_vp != clips_and_vp.*[1] and !clips.eql(&clips_and_vp.*[0])) { - this.flush(allocator, dest, context); - } else { - bun.bits.insert(VendorPrefix, &clips_vp, clips_and_vp.*[1]); - } - } - - if (this.color) |*c| c.deinit(allocator); - this.color = color; - if (this.images) |*i| i.deinit(allocator); - this.images = images; - const x_positions = this.initSmallListHelper(HorizontalPosition, 1, "x_positions", allocator, val.len()); - const y_positions = this.initSmallListHelper(VerticalPosition, 1, "y_positions", allocator, val.len()); - const repeats = this.initSmallListHelper(BackgroundRepeat, 1, "repeats", allocator, val.len()); - const sizes = this.initSmallListHelper(BackgroundSize, 1, "sizes", allocator, val.len()); - const attachments = this.initSmallListHelper(BackgroundAttachment, 1, "attachments", allocator, val.len()); - const origins = this.initSmallListHelper(BackgroundOrigin, 1, "origins", allocator, val.len()); - - for ( - val.slice(), - x_positions, - y_positions, - repeats, - sizes, - attachments, - origins, - ) |*b, *x, *y, *r, *s, *a, *o| { - x.* = b.position.x.deepClone(allocator); - y.* = b.position.y.deepClone(allocator); - r.* = b.repeat.deepClone(allocator); - s.* = b.size.deepClone(allocator); - a.* = b.attachment.deepClone(allocator); - o.* = b.origin.deepClone(allocator); - } - - this.clips = .{ clips, clips_vp }; - }, - .unparsed => |*val| { - if (isBackgroundProperty(val.property_id)) { - this.flush(allocator, dest, context); - var unparsed = val.deepClone(allocator); - context.addUnparsedFallbacks(&unparsed); - if (BackgroundProperty.tryFromPropertyId(val.property_id)) |prop| { - bun.bits.insert(BackgroundProperty, &this.flushed_properties, prop); - } - - bun.handleOom(dest.append(allocator, Property{ .unparsed = unparsed })); - } else return false; - }, - else => return false, - } - - this.has_any = true; - return true; - } - - // Either get the value from the field on `this` or initialize a new one - fn initSmallListHelper( - this: *@This(), - comptime T: type, - comptime N: comptime_int, - comptime field: []const u8, - allocator: Allocator, - length: u32, - ) []T { - if (@field(this, field)) |*list| { - list.clearRetainingCapacity(); - list.ensureTotalCapacity(allocator, length); - list.setLen(length); - return list.slice_mut(); - } else { - @field(this, field) = SmallList(T, N).initCapacity(allocator, length); - @field(this, field).?.setLen(length); - return @field(this, field).?.slice_mut(); - } - } - - fn backgroundHelper( - this: *@This(), - allocator: Allocator, - comptime T: type, - val: *const T, - property: *const Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - this.flushHelper(allocator, "images", T, val, dest, context); - - // Store prefixed properties. Clear if we hit an unprefixed property and we have - // targets. In this case, the necessary prefixes will be generated. - this.has_prefix = val.any(struct { - pub fn predicate(item: *const Image) bool { - return item.hasVendorPrefix(); - } - }.predicate); - if (this.has_prefix) { - bun.handleOom(this.decls.append(allocator, property.deepClone(allocator))); - } else if (context.targets.browsers != null) { - this.decls.clearRetainingCapacity(); - } - } - - fn flushHelper( - this: *@This(), - allocator: Allocator, - comptime field: []const u8, - comptime T: type, - val: *const T, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - if (@field(this, field) != null and - !@field(this, field).?.eql(val) and - context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) - { - this.flush(allocator, dest, context); - } - } - - fn flush(this: *@This(), allocator: Allocator, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - this.has_any = false; - const push = struct { - fn push(self: *BackgroundHandler, alloc: Allocator, d: *css.DeclarationList, comptime property_field_name: []const u8, val: anytype) void { - bun.handleOom(d.append(alloc, @unionInit(Property, property_field_name, val))); - const prop = @field(BackgroundProperty, property_field_name); - bun.bits.insert(BackgroundProperty, &self.flushed_properties, prop); - } - }.push; - - var maybe_color: ?CssColor = bun.take(&this.color); - var maybe_images: ?css.SmallList(Image, 1) = bun.take(&this.images); - var maybe_x_positions: ?css.SmallList(HorizontalPosition, 1) = bun.take(&this.x_positions); - var maybe_y_positions: ?css.SmallList(VerticalPosition, 1) = bun.take(&this.y_positions); - var maybe_repeats: ?css.SmallList(BackgroundRepeat, 1) = bun.take(&this.repeats); - var maybe_sizes: ?css.SmallList(BackgroundSize, 1) = bun.take(&this.sizes); - var maybe_attachments: ?css.SmallList(BackgroundAttachment, 1) = bun.take(&this.attachments); - var maybe_origins: ?css.SmallList(BackgroundOrigin, 1) = bun.take(&this.origins); - var maybe_clips: ?struct { css.SmallList(BackgroundClip, 1), css.VendorPrefix } = bun.take(&this.clips); - defer { - if (maybe_color) |*c| c.deinit(allocator); - if (maybe_images) |*i| i.deinit(allocator); - if (maybe_x_positions) |*x| x.deinit(allocator); - if (maybe_y_positions) |*y| y.deinit(allocator); - if (maybe_repeats) |*r| r.deinit(allocator); - if (maybe_sizes) |*s| s.deinit(allocator); - if (maybe_attachments) |*a| a.deinit(allocator); - if (maybe_origins) |*o| o.deinit(allocator); - if (maybe_clips) |*c| c.*[0].deinit(allocator); - } - - if (maybe_color != null and - maybe_images != null and - maybe_x_positions != null and - maybe_y_positions != null and - maybe_repeats != null and - maybe_sizes != null and - maybe_attachments != null and - maybe_origins != null and - maybe_clips != null) - { - const color = &maybe_color.?; - var images = &maybe_images.?; - var x_positions = &maybe_x_positions.?; - var y_positions = &maybe_y_positions.?; - var repeats = &maybe_repeats.?; - var sizes = &maybe_sizes.?; - var attachments = &maybe_attachments.?; - var origins = &maybe_origins.?; - var clips = &maybe_clips.?; - - // Only use shorthand syntax if the number of layers matches on all properties. - const len = images.len(); - if (x_positions.len() == len and - y_positions.len() == len and - repeats.len() == len and - sizes.len() == len and attachments.len() == len and origins.len() == len and clips[0].len() == len) - { - const clip_prefixes = if (clips.*[0].any(struct { - fn predicate(clip: *const BackgroundClip) bool { - return clip.* == BackgroundClip.text; - } - }.predicate)) context.targets.prefixes(clips.*[1], .background_clip) else clips.*[1]; - const clip_property = if (clip_prefixes != css.VendorPrefix{ .none = true }) - css.Property{ .@"background-clip" = .{ clips.*[0].deepClone(allocator), clip_prefixes } } - else - null; - - var backgrounds = SmallList(Background, 1).initCapacity(allocator, len); - for ( - images.slice(), - x_positions.slice(), - y_positions.slice(), - repeats.slice(), - sizes.slice(), - attachments.slice(), - origins.slice(), - clips.*[0].slice(), - 0.., - ) |image, x_position, y_position, repeat, size, attachment, origin, clip, i| { - backgrounds.appendAssumeCapacity(Background{ - .color = if (i == len - 1) color.deepClone(allocator) else CssColor.default(), - .image = image, - .position = BackgroundPosition{ .x = x_position, .y = y_position }, - .repeat = repeat, - .size = size, - .attachment = attachment, - .origin = origin, - .clip = if (clip_prefixes == css.VendorPrefix{ .none = true }) clip else BackgroundClip.default(), - }); - } - defer { - images.clearRetainingCapacity(); - x_positions.clearRetainingCapacity(); - y_positions.clearRetainingCapacity(); - repeats.clearRetainingCapacity(); - sizes.clearRetainingCapacity(); - attachments.clearRetainingCapacity(); - origins.clearRetainingCapacity(); - clips.*[0].clearRetainingCapacity(); - } - - if (this.flushed_properties.isEmpty()) { - for (backgrounds.getFallbacks(allocator, context.targets).slice()) |fallback| { - push(this, allocator, dest, "background", fallback); - } - } - - push(this, allocator, dest, "background", backgrounds); - - if (clip_property) |clip| { - bun.handleOom(dest.append(allocator, clip)); - this.flushed_properties.clip = true; - } - - this.reset(allocator); - return; - } - } - - if (bun.take(&maybe_color)) |color_const| { - var color: CssColor = color_const; - if (!this.flushed_properties.color) { - for (color.getFallbacks(allocator, context.targets).slice()) |fallback| { - push(this, allocator, dest, "background-color", fallback); - } - } - push(this, allocator, dest, "background-color", color); - } - - if (bun.take(&maybe_images)) |images_| { - var images: css.SmallList(Image, 1) = images_; - if (!this.flushed_properties.image) { - var fallbacks = images.getFallbacks(allocator, context.targets); - for (fallbacks.slice()) |fallback| { - push(this, allocator, dest, "background-image", fallback); - } - } - push(this, allocator, dest, "background-image", images); - } - - if (maybe_x_positions != null and maybe_y_positions != null and maybe_x_positions.?.len() == maybe_y_positions.?.len()) { - var positions = SmallList(BackgroundPosition, 1).initCapacity(allocator, maybe_x_positions.?.len()); - for (maybe_x_positions.?.slice(), maybe_y_positions.?.slice()) |x, y| { - positions.appendAssumeCapacity(BackgroundPosition{ .x = x, .y = y }); - } - maybe_x_positions.?.clearRetainingCapacity(); - maybe_y_positions.?.clearRetainingCapacity(); - push(this, allocator, dest, "background-position", positions); - } else { - if (bun.take(&maybe_x_positions)) |x| { - push(this, allocator, dest, "background-position-x", x); - } - if (bun.take(&maybe_y_positions)) |y| { - push(this, allocator, dest, "background-position-y", y); - } - } - - if (bun.take(&maybe_repeats)) |rep| { - push(this, allocator, dest, "background-repeat", rep); - } - - if (bun.take(&maybe_sizes)) |rep| { - push(this, allocator, dest, "background-size", rep); - } - - if (bun.take(&maybe_attachments)) |rep| { - push(this, allocator, dest, "background-attachment", rep); - } - - if (bun.take(&maybe_origins)) |rep| { - push(this, allocator, dest, "background-origin", rep); - } - - if (bun.take(&maybe_clips)) |c| { - const clips: css.SmallList(BackgroundClip, 1), const vp: css.VendorPrefix = c; - const prefixes = if (clips.any(struct { - pub fn predicate(clip: *const BackgroundClip) bool { - return clip.* == BackgroundClip.text; - } - }.predicate)) context.targets.prefixes(vp, css.prefixes.Feature.background_clip) else vp; - dest.append( - allocator, - Property{ - .@"background-clip" = .{ clips.deepClone(allocator), prefixes }, - }, - ) catch |err| bun.handleOom(err); - this.flushed_properties.clip = true; - } - - this.reset(allocator); - } - - fn reset(this: *@This(), allocator: Allocator) void { - if (this.color) |c| c.deinit(allocator); - this.color = null; - if (this.images) |*i| i.deinit(allocator); - this.images = null; - if (this.x_positions) |*x| x.deinit(allocator); - this.x_positions = null; - if (this.y_positions) |*y| y.deinit(allocator); - this.y_positions = null; - if (this.repeats) |*r| r.deinit(allocator); - this.repeats = null; - if (this.sizes) |*s| s.deinit(allocator); - this.sizes = null; - if (this.attachments) |*a| a.deinit(allocator); - this.attachments = null; - if (this.origins) |*o| o.deinit(allocator); - this.origins = null; - if (this.clips) |*c| c.*[0].deinit(allocator); - this.clips = null; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - const allocator = context.allocator; - // If the last declaration is prefixed, pop the last value - // so it isn't duplicated when we flush. - if (this.has_prefix) { - var maybe_prop = this.decls.pop(); - if (maybe_prop) |*prop| { - prop.deinit(allocator); - } - } - - bun.handleOom(dest.appendSlice(allocator, this.decls.items)); - this.decls.clearRetainingCapacity(); - - this.flush(allocator, dest, context); - this.flushed_properties = BackgroundProperty{}; - } -}; - -fn isBackgroundProperty(property_id: css.PropertyId) bool { - return switch (property_id) { - .@"background-color", - .@"background-image", - .@"background-position", - .@"background-position-x", - .@"background-position-y", - .@"background-repeat", - .@"background-size", - .@"background-attachment", - .@"background-origin", - .@"background-clip", - .background, - => true, - else => false, - }; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/border.zig b/src/css/properties/border.zig deleted file mode 100644 index 885c35779795..000000000000 --- a/src/css/properties/border.zig +++ /dev/null @@ -1,1486 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const CssColor = css.css_values.color.CssColor; -const Length = css.css_values.length.Length; - -const PropertyCategory = css.PropertyCategory; -const UnparsedProperty = css.css_properties.custom.UnparsedProperty; - -/// A value for the [border-top](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-top) shorthand property. -pub const BorderTop = GenericBorder(LineStyle, 0); -/// A value for the [border-right](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-right) shorthand property. -pub const BorderRight = GenericBorder(LineStyle, 1); -/// A value for the [border-bottom](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-bottom) shorthand property. -pub const BorderBottom = GenericBorder(LineStyle, 2); -/// A value for the [border-left](https://www.w3.org/TR/css-backgrounds-3/#propdef-border-left) shorthand property. -pub const BorderLeft = GenericBorder(LineStyle, 3); -/// A value for the [border-block-start](https://drafts.csswg.org/css-logical/#propdef-border-block-start) shorthand property. -pub const BorderBlockStart = GenericBorder(LineStyle, 4); -/// A value for the [border-block-end](https://drafts.csswg.org/css-logical/#propdef-border-block-end) shorthand property. -pub const BorderBlockEnd = GenericBorder(LineStyle, 5); -/// A value for the [border-inline-start](https://drafts.csswg.org/css-logical/#propdef-border-inline-start) shorthand property. -pub const BorderInlineStart = GenericBorder(LineStyle, 6); -/// A value for the [border-inline-end](https://drafts.csswg.org/css-logical/#propdef-border-inline-end) shorthand property. -pub const BorderInlineEnd = GenericBorder(LineStyle, 7); -/// A value for the [border-block](https://drafts.csswg.org/css-logical/#propdef-border-block) shorthand property. -pub const BorderBlock = GenericBorder(LineStyle, 8); -/// A value for the [border-inline](https://drafts.csswg.org/css-logical/#propdef-border-inline) shorthand property. -pub const BorderInline = GenericBorder(LineStyle, 9); -/// A value for the [border](https://www.w3.org/TR/css-backgrounds-3/#propdef-border) shorthand property. -pub const Border = GenericBorder(LineStyle, 10); - -/// A generic type that represents the `border` and `outline` shorthand properties. -pub fn GenericBorder(comptime S: type, comptime P: u8) type { - _ = P; // autofix - return struct { - /// The width of the border. - width: BorderSideWidth, - /// The border style. - style: S, - /// The border color. - color: CssColor, - - const This = @This(); - - pub fn parse(input: *css.Parser) css.Result(@This()) { - // Order doesn't matter - var color: ?CssColor = null; - var style: ?S = null; - var width: ?BorderSideWidth = null; - var any = false; - - while (true) { - if (width == null) { - if (input.tryParse(BorderSideWidth.parse, .{}).asValue()) |value| { - width = value; - any = true; - } - } - - if (style == null) { - if (input.tryParse(S.parse, .{}).asValue()) |value| { - style = value; - any = true; - continue; - } - } - - if (color == null) { - if (input.tryParse(CssColor.parse, .{}).asValue()) |value| { - color = value; - any = true; - continue; - } - } - break; - } - - if (any) { - return .{ - .result = This{ - .width = width orelse BorderSideWidth.medium, - .style = style orelse S.default(), - .color = color orelse CssColor.current_color, - }, - }; - } - - return .{ .err = input.newCustomError(css.ParserError.invalid_declaration) }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - if (this.eql(&This.default())) { - try this.style.toCss(dest); - return; - } - - var needs_space = false; - if (!this.width.eql(&BorderSideWidth.default())) { - try this.width.toCss(dest); - needs_space = true; - } - if (!this.style.eql(&S.default())) { - if (needs_space) { - try dest.writeStr(" "); - } - try this.style.toCss(dest); - needs_space = true; - } - if (!this.color.eql(&CssColor{ .current_color = {} })) { - if (needs_space) { - try dest.writeStr(" "); - } - try this.color.toCss(dest); - needs_space = true; - } - return; - } - - fn getFallbacks(this: *@This(), allocator: Allocator, targets: css.targets.Targets) css.SmallList(@This(), 2) { - var fallbacks = this.color.getFallbacks(allocator, targets); - defer fallbacks.deinit(allocator); - var out = css.SmallList(@This(), 2).initCapacity(allocator, fallbacks.len()); - out.setLen(fallbacks.len()); - - for (fallbacks.slice(), out.slice_mut()) |color, *o| { - o.* = .{ - .color = color, - .width = this.width.deepClone(allocator), - .style = this.style.deepClone(allocator), - }; - } - - return out; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const This, other: *const This) bool { - return css.implementEql(@This(), this, other); - } - - pub inline fn default() This { - return This{ - .width = .medium, - .style = S.default(), - .color = CssColor.current_color, - }; - } - }; -} -/// A [``](https://drafts.csswg.org/css-backgrounds/#typedef-line-style) value, used in the `border-style` property. -/// A [``](https://drafts.csswg.org/css-backgrounds/#typedef-line-style) value, used in the `border-style` property. -pub const LineStyle = enum { - /// No border. - none, - /// Similar to `none` but with different rules for tables. - hidden, - /// Looks as if the content on the inside of the border is sunken into the canvas. - inset, - /// Looks as if it were carved in the canvas. - groove, - /// Looks as if the content on the inside of the border is coming out of the canvas. - outset, - /// Looks as if it were coming out of the canvas. - ridge, - /// A series of round dots. - dotted, - /// A series of square-ended dashes. - dashed, - /// A single line segment. - solid, - /// Two parallel solid lines with some space between them. - double, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn isCompatible(_: *const @This(), _: bun.css.targets.Browsers) bool { - return true; - } - - pub fn default() LineStyle { - return .none; - } -}; - -/// A value for the [border-width](https://www.w3.org/TR/css-backgrounds-3/#border-width) property. -pub const BorderSideWidth = union(enum) { - /// A UA defined `thin` value. - thin, - /// A UA defined `medium` value. - medium, - /// A UA defined `thick` value. - thick, - /// An explicit width. - length: Length, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn isCompatible(this: *const @This(), browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .length => |len| len.isCompatible(browsers), - else => true, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn default() BorderSideWidth { - return .medium; - } - - pub fn deinit(_: *@This(), _: std.mem.Allocator) void {} - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } -}; - -// TODO: fallbacks -/// A value for the [border-color](https://drafts.csswg.org/css-backgrounds/#propdef-border-color) shorthand property. -pub const BorderColor = struct { - top: CssColor, - right: CssColor, - bottom: CssColor, - left: CssColor, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-color"); - const css_impl = css.DefineRectShorthand(@This(), CssColor); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - pub const getFallbacks = ImplFallbacks(@This()).getFallbacks; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.@"border-top-color", - .right = css.PropertyIdTag.@"border-right-color", - .bottom = css.PropertyIdTag.@"border-bottom-color", - .left = css.PropertyIdTag.@"border-left-color", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [border-style](https://drafts.csswg.org/css-backgrounds/#propdef-border-style) shorthand property. -pub const BorderStyle = struct { - top: LineStyle, - right: LineStyle, - bottom: LineStyle, - left: LineStyle, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-style"); - const css_impl = css.DefineRectShorthand(@This(), LineStyle); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.@"border-top-style", - .right = css.PropertyIdTag.@"border-right-style", - .bottom = css.PropertyIdTag.@"border-bottom-style", - .left = css.PropertyIdTag.@"border-left-style", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [border-width](https://drafts.csswg.org/css-backgrounds/#propdef-border-width) shorthand property. -pub const BorderWidth = struct { - top: BorderSideWidth, - right: BorderSideWidth, - bottom: BorderSideWidth, - left: BorderSideWidth, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-width"); - const css_impl = css.DefineRectShorthand(@This(), BorderSideWidth); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.@"border-top-width", - .right = css.PropertyIdTag.@"border-right-width", - .bottom = css.PropertyIdTag.@"border-bottom-width", - .left = css.PropertyIdTag.@"border-left-width", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -// TODO: fallbacks -/// A value for the [border-block-color](https://drafts.csswg.org/css-logical/#propdef-border-block-color) shorthand property. -pub const BorderBlockColor = struct { - /// The block start value. - start: CssColor, - /// The block end value. - end: CssColor, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-block-color"); - const css_impl = css.DefineSizeShorthand(@This(), CssColor); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - pub const getFallbacks = ImplFallbacks(@This()).getFallbacks; - - pub const PropertyFieldMap = .{ - .start = css.PropertyIdTag.@"border-block-start-color", - .end = css.PropertyIdTag.@"border-block-end-color", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [border-block-style](https://drafts.csswg.org/css-logical/#propdef-border-block-style) shorthand property. -pub const BorderBlockStyle = struct { - /// The block start value. - start: LineStyle, - /// The block end value. - end: LineStyle, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-block-style"); - const css_impl = css.DefineSizeShorthand(@This(), LineStyle); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .start = css.PropertyIdTag.@"border-block-start-style", - .end = css.PropertyIdTag.@"border-block-end-style", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [border-block-width](https://drafts.csswg.org/css-logical/#propdef-border-block-width) shorthand property. -pub const BorderBlockWidth = struct { - /// The block start value. - start: BorderSideWidth, - /// The block end value. - end: BorderSideWidth, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-block-width"); - const css_impl = css.DefineSizeShorthand(@This(), BorderSideWidth); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .start = css.PropertyIdTag.@"border-block-start-width", - .end = css.PropertyIdTag.@"border-block-end-width", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -// TODO: fallbacks -/// A value for the [border-inline-color](https://drafts.csswg.org/css-logical/#propdef-border-inline-color) shorthand property. -pub const BorderInlineColor = struct { - /// The inline start value. - start: CssColor, - /// The inline end value. - end: CssColor, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-inline-color"); - const css_impl = css.DefineSizeShorthand(@This(), CssColor); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - pub const getFallbacks = ImplFallbacks(@This()).getFallbacks; - - pub const PropertyFieldMap = .{ - .start = css.PropertyIdTag.@"border-inline-start-color", - .end = css.PropertyIdTag.@"border-inline-end-color", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [border-inline-style](https://drafts.csswg.org/css-logical/#propdef-border-inline-style) shorthand property. -pub const BorderInlineStyle = struct { - /// The inline start value. - start: LineStyle, - /// The inline end value. - end: LineStyle, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-inline-style"); - const css_impl = css.DefineSizeShorthand(@This(), LineStyle); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .start = css.PropertyIdTag.@"border-inline-start-style", - .end = css.PropertyIdTag.@"border-inline-end-style", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [border-inline-width](https://drafts.csswg.org/css-logical/#propdef-border-inline-width) shorthand property. -pub const BorderInlineWidth = struct { - /// The inline start value. - start: BorderSideWidth, - /// The inline end value. - end: BorderSideWidth, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-inline-width"); - const css_impl = css.DefineSizeShorthand(@This(), BorderSideWidth); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .start = css.PropertyIdTag.@"border-inline-start-width", - .end = css.PropertyIdTag.@"border-inline-end-width", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -pub fn ImplFallbacks(comptime T: type) type { - return struct { - const fields = std.meta.fields(T); - - pub fn getFallbacks(this: *T, allocator: std.mem.Allocator, targets: css.Targets) css.SmallList(T, 2) { - const ColorFallbackKind = css.css_values.color.ColorFallbackKind; - var fallbacks = ColorFallbackKind{}; - inline for (fields) |field| { - bun.bits.insert(ColorFallbackKind, &fallbacks, @field(this, field.name).getNecessaryFallbacks(targets)); - } - - var res = css.SmallList(T, 2){}; - if (fallbacks.rgb) { - var out: T = undefined; - inline for (fields) |field| { - @field(out, field.name) = @field(this, field.name).getFallback(allocator, ColorFallbackKind{ .rgb = true }); - } - res.append(allocator, out); - } - - if (fallbacks.p3) { - var out: T = undefined; - inline for (fields) |field| { - @field(out, field.name) = @field(this, field.name).getFallback(allocator, ColorFallbackKind{ .p3 = true }); - } - res.append(allocator, out); - } - - if (fallbacks.lab) { - inline for (fields) |field| { - @field(this, field.name) = @field(this, field.name).getFallback(allocator, ColorFallbackKind{ .lab = true }); - } - } - - return res; - } - }; -} - -const BorderShorthand = struct { - width: ?BorderSideWidth = null, - style: ?LineStyle = null, - color: ?CssColor = null, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn setBorder(this: *@This(), allocator: std.mem.Allocator, border: anytype) void { - this.width = border.width.deepClone(allocator); - this.style = border.style.deepClone(allocator); - this.color = border.color.deepClone(allocator); - } - - fn reset(this: *@This(), allocator: std.mem.Allocator) void { - bun.clear(&this.width, allocator); - bun.clear(&this.style, allocator); - bun.clear(&this.color, allocator); - } - - fn isValid(this: *const @This()) bool { - return this.width != null and this.style != null and this.color != null; - } - - fn toBorder(this: *const @This(), allocator: std.mem.Allocator) Border { - return .{ - .width = css.generic.deepClone(@TypeOf(this.width), &this.width, allocator).?, - .style = css.generic.deepClone(@TypeOf(this.style), &this.style, allocator).?, - .color = css.generic.deepClone(@TypeOf(this.color), &this.color, allocator).?, - }; - } -}; - -const BorderProperty = packed struct(u32) { - @"top-color": bool = false, - @"bottom-color": bool = false, - @"left-color": bool = false, - @"right-color": bool = false, - @"block-start-color": bool = false, - @"block-end-color": bool = false, - @"inline-start-color": bool = false, - @"inline-end-color": bool = false, - @"top-width": bool = false, - @"bottom-width": bool = false, - @"left-width": bool = false, - @"right-width": bool = false, - @"block-start-width": bool = false, - @"block-end-width": bool = false, - @"inline-start-width": bool = false, - @"inline-end-width": bool = false, - @"top-style": bool = false, - @"bottom-style": bool = false, - @"left-style": bool = false, - @"right-style": bool = false, - @"block-start-style": bool = false, - @"block-end-style": bool = false, - @"inline-start-style": bool = false, - @"inline-end-style": bool = false, - __unused: u8 = 0, - - const @"border-top-color" = BorderProperty{ .@"top-color" = true }; - const @"border-bottom-color" = BorderProperty{ .@"bottom-color" = true }; - const @"border-left-color" = BorderProperty{ .@"left-color" = true }; - const @"border-right-color" = BorderProperty{ .@"right-color" = true }; - const @"border-block-start-color" = BorderProperty{ .@"block-start-color" = true }; - const @"border-block-end-color" = BorderProperty{ .@"block-end-color" = true }; - const @"border-inline-start-color" = BorderProperty{ .@"inline-start-color" = true }; - const @"border-inline-end-color" = BorderProperty{ .@"inline-end-color" = true }; - const @"border-top-width" = BorderProperty{ .@"top-width" = true }; - const @"border-bottom-width" = BorderProperty{ .@"bottom-width" = true }; - const @"border-left-width" = BorderProperty{ .@"left-width" = true }; - const @"border-right-width" = BorderProperty{ .@"right-width" = true }; - const @"border-block-start-width" = BorderProperty{ .@"block-start-width" = true }; - const @"border-block-end-width" = BorderProperty{ .@"block-end-width" = true }; - const @"border-inline-start-width" = BorderProperty{ .@"inline-start-width" = true }; - const @"border-inline-end-width" = BorderProperty{ .@"inline-end-width" = true }; - const @"border-top-style" = BorderProperty{ .@"top-style" = true }; - const @"border-bottom-style" = BorderProperty{ .@"bottom-style" = true }; - const @"border-left-style" = BorderProperty{ .@"left-style" = true }; - const @"border-right-style" = BorderProperty{ .@"right-style" = true }; - const @"border-block-start-style" = BorderProperty{ .@"block-start-style" = true }; - const @"border-block-end-style" = BorderProperty{ .@"block-end-style" = true }; - const @"border-inline-start-style" = BorderProperty{ .@"inline-start-style" = true }; - const @"border-inline-end-style" = BorderProperty{ .@"inline-end-style" = true }; - - const @"border-block-color" = BorderProperty{ .@"block-start-color" = true, .@"block-end-color" = true }; - const @"border-inline-color" = BorderProperty{ .@"inline-start-color" = true, .@"inline-end-color" = true }; - const @"border-block-width" = BorderProperty{ .@"block-start-width" = true, .@"block-end-width" = true }; - const @"border-inline-width" = BorderProperty{ .@"inline-start-width" = true, .@"inline-end-width" = true }; - const @"border-block-style" = BorderProperty{ .@"block-start-style" = true, .@"block-end-style" = true }; - const @"border-inline-style" = BorderProperty{ .@"inline-start-style" = true, .@"inline-end-style" = true }; - const @"border-top" = BorderProperty{ .@"top-color" = true, .@"top-width" = true, .@"top-style" = true }; - const @"border-bottom" = BorderProperty{ .@"bottom-color" = true, .@"bottom-width" = true, .@"bottom-style" = true }; - const @"border-left" = BorderProperty{ .@"left-color" = true, .@"left-width" = true, .@"left-style" = true }; - const @"border-right" = BorderProperty{ .@"right-color" = true, .@"right-width" = true, .@"right-style" = true }; - const @"border-block-start" = BorderProperty{ .@"block-start-color" = true, .@"block-start-width" = true, .@"block-start-style" = true }; - const @"border-block-end" = BorderProperty{ .@"block-end-color" = true, .@"block-end-width" = true, .@"block-end-style" = true }; - const @"border-inline-start" = BorderProperty{ .@"inline-start-color" = true, .@"inline-start-width" = true, .@"inline-start-style" = true }; - const @"border-inline-end" = BorderProperty{ .@"inline-end-color" = true, .@"inline-end-width" = true, .@"inline-end-style" = true }; - const @"border-block" = BorderProperty{ .@"block-start-color" = true, .@"block-end-color" = true, .@"block-start-width" = true, .@"block-end-width" = true, .@"block-start-style" = true, .@"block-end-style" = true }; - const @"border-inline" = BorderProperty{ .@"inline-start-color" = true, .@"inline-end-color" = true, .@"inline-start-width" = true, .@"inline-end-width" = true, .@"inline-start-style" = true, .@"inline-end-style" = true }; - const @"border-width" = BorderProperty{ .@"left-width" = true, .@"right-width" = true, .@"top-width" = true, .@"bottom-width" = true }; - const @"border-style" = BorderProperty{ .@"left-style" = true, .@"right-style" = true, .@"top-style" = true, .@"bottom-style" = true }; - const @"border-color" = BorderProperty{ .@"left-color" = true, .@"right-color" = true, .@"top-color" = true, .@"bottom-color" = true }; - const border = BorderProperty{ .@"left-width" = true, .@"right-width" = true, .@"top-width" = true, .@"bottom-width" = true, .@"left-style" = true, .@"right-style" = true, .@"top-style" = true, .@"bottom-style" = true, .@"left-color" = true, .@"right-color" = true, .@"top-color" = true, .@"bottom-color" = true }; - - pub fn tryFromPropertyId(property_id: css.PropertyIdTag) ?@This() { - @setEvalBranchQuota(10000); - const fields = bun.meta.EnumFields(css.PropertyIdTag); - inline for (fields) |field| { - if (field.value == @intFromEnum(property_id)) { - if (comptime std.mem.startsWith(u8, field.name, "border") and @hasDecl(@This(), field.name)) { - return @field(@This(), field.name); - } - } - } - - return null; - } -}; - -pub const BorderHandler = struct { - border_top: BorderShorthand = .{}, - border_bottom: BorderShorthand = .{}, - border_left: BorderShorthand = .{}, - border_right: BorderShorthand = .{}, - border_block_start: BorderShorthand = .{}, - border_block_end: BorderShorthand = .{}, - border_inline_start: BorderShorthand = .{}, - border_inline_end: BorderShorthand = .{}, - category: PropertyCategory = PropertyCategory.default(), - border_image_handler: BorderImageHandler = .{}, - border_radius_handler: BorderRadiusHandler = .{}, - flushed_properties: BorderProperty = .{}, - has_any: bool = false, - - pub fn handleProperty( - this: *@This(), - property: *const css.Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) bool { - const allocator = context.allocator; - - const flushHelper = struct { - inline fn flushHelper(self: *BorderHandler, d: *css.DeclarationList, c: *css.PropertyHandlerContext, comptime key: []const u8, comptime prop: []const u8, val: anytype, category: PropertyCategory) void { - if (category != self.category) { - self.flush(d, c); - } - - if (@field(@field(self, key), prop) != null and !@field(@field(self, key), prop).?.eql(val) and c.targets.browsers != null and !css.generic.isCompatible(@TypeOf(val.*), val, c.targets.browsers.?)) { - self.flush(d, c); - } - } - }.flushHelper; - - const propertyHelper = struct { - inline fn propertyHelper(self: *BorderHandler, d: *css.DeclarationList, c: *css.PropertyHandlerContext, comptime key: []const u8, comptime prop: []const u8, val: anytype, category: PropertyCategory) void { - flushHelper(self, d, c, key, prop, val, category); - @field(@field(self, key), prop) = val.deepClone(c.allocator); - self.category = category; - self.has_any = true; - } - }.propertyHelper; - - const setBorderHelper = struct { - inline fn setBorderHelper(self: *BorderHandler, d: *css.DeclarationList, c: *css.PropertyHandlerContext, comptime key: []const u8, val: anytype, category: PropertyCategory) void { - if (category != self.category) { - self.flush(d, c); - } - - @field(self, key).setBorder(c.allocator, val); - self.category = category; - self.has_any = true; - } - }.setBorderHelper; - - switch (property.*) { - .@"border-top-color" => |*val| propertyHelper(this, dest, context, "border_top", "color", val, .physical), - .@"border-bottom-color" => |*val| propertyHelper(this, dest, context, "border_bottom", "color", val, .physical), - .@"border-left-color" => |*val| propertyHelper(this, dest, context, "border_left", "color", val, .physical), - .@"border-right-color" => |*val| propertyHelper(this, dest, context, "border_right", "color", val, .physical), - .@"border-block-start-color" => |*val| propertyHelper(this, dest, context, "border_block_start", "color", val, .logical), - .@"border-block-end-color" => |*val| propertyHelper(this, dest, context, "border_block_end", "color", val, .logical), - .@"border-block-color" => |val| { - propertyHelper(this, dest, context, "border_block_start", "color", &val.start, .logical); - propertyHelper(this, dest, context, "border_block_end", "color", &val.end, .logical); - }, - .@"border-inline-start-color" => |*val| propertyHelper(this, dest, context, "border_inline_start", "color", val, .logical), - .@"border-inline-end-color" => |*val| propertyHelper(this, dest, context, "border_inline_end", "color", val, .logical), - .@"border-inline-color" => |val| { - propertyHelper(this, dest, context, "border_inline_start", "color", &val.start, .logical); - propertyHelper(this, dest, context, "border_inline_end", "color", &val.end, .logical); - }, - .@"border-top-width" => |*val| propertyHelper(this, dest, context, "border_top", "width", val, .physical), - .@"border-bottom-width" => |*val| propertyHelper(this, dest, context, "border_bottom", "width", val, .physical), - .@"border-left-width" => |*val| propertyHelper(this, dest, context, "border_left", "width", val, .physical), - .@"border-right-width" => |*val| propertyHelper(this, dest, context, "border_right", "width", val, .physical), - .@"border-block-start-width" => |*val| propertyHelper(this, dest, context, "border_block_start", "width", val, .logical), - .@"border-block-end-width" => |*val| propertyHelper(this, dest, context, "border_block_end", "width", val, .logical), - .@"border-block-width" => |val| { - propertyHelper(this, dest, context, "border_block_start", "width", &val.start, .logical); - propertyHelper(this, dest, context, "border_block_end", "width", &val.end, .logical); - }, - .@"border-inline-start-width" => |*val| propertyHelper(this, dest, context, "border_inline_start", "width", val, .logical), - .@"border-inline-end-width" => |*val| propertyHelper(this, dest, context, "border_inline_end", "width", val, .logical), - .@"border-inline-width" => |val| { - propertyHelper(this, dest, context, "border_inline_start", "width", &val.start, .logical); - propertyHelper(this, dest, context, "border_inline_end", "width", &val.end, .logical); - }, - .@"border-top-style" => |*val| propertyHelper(this, dest, context, "border_top", "style", val, .physical), - .@"border-bottom-style" => |*val| propertyHelper(this, dest, context, "border_bottom", "style", val, .physical), - .@"border-left-style" => |*val| propertyHelper(this, dest, context, "border_left", "style", val, .physical), - .@"border-right-style" => |*val| propertyHelper(this, dest, context, "border_right", "style", val, .physical), - .@"border-block-start-style" => |*val| propertyHelper(this, dest, context, "border_block_start", "style", val, .logical), - .@"border-block-end-style" => |*val| propertyHelper(this, dest, context, "border_block_end", "style", val, .logical), - .@"border-block-style" => |val| { - propertyHelper(this, dest, context, "border_block_start", "style", &val.start, .logical); - propertyHelper(this, dest, context, "border_block_end", "style", &val.end, .logical); - }, - .@"border-inline-start-style" => |*val| propertyHelper(this, dest, context, "border_inline_start", "style", val, .logical), - .@"border-inline-end-style" => |*val| propertyHelper(this, dest, context, "border_inline_end", "style", val, .logical), - .@"border-inline-style" => |val| { - propertyHelper(this, dest, context, "border_inline_start", "style", &val.start, .logical); - propertyHelper(this, dest, context, "border_inline_end", "style", &val.end, .logical); - }, - .@"border-top" => |*val| setBorderHelper(this, dest, context, "border_top", val, .physical), - .@"border-bottom" => |*val| setBorderHelper(this, dest, context, "border_bottom", val, .physical), - .@"border-left" => |*val| setBorderHelper(this, dest, context, "border_left", val, .physical), - .@"border-right" => |*val| setBorderHelper(this, dest, context, "border_right", val, .physical), - .@"border-block-start" => |*val| setBorderHelper(this, dest, context, "border_block_start", val, .logical), - .@"border-block-end" => |*val| setBorderHelper(this, dest, context, "border_block_end", val, .logical), - .@"border-inline-start" => |*val| setBorderHelper(this, dest, context, "border_inline_start", val, .logical), - .@"border-inline-end" => |*val| setBorderHelper(this, dest, context, "border_inline_end", val, .logical), - .@"border-block" => |*val| { - setBorderHelper(this, dest, context, "border_block_start", val, .logical); - setBorderHelper(this, dest, context, "border_block_end", val, .logical); - }, - .@"border-inline" => |*val| { - setBorderHelper(this, dest, context, "border_inline_start", val, .logical); - setBorderHelper(this, dest, context, "border_inline_end", val, .logical); - }, - .@"border-width" => |*val| { - propertyHelper(this, dest, context, "border_top", "width", &val.top, .physical); - propertyHelper(this, dest, context, "border_right", "width", &val.right, .physical); - propertyHelper(this, dest, context, "border_bottom", "width", &val.bottom, .physical); - propertyHelper(this, dest, context, "border_left", "width", &val.left, .physical); - - bun.clear(&this.border_block_start.width, context.allocator); - bun.clear(&this.border_block_end.width, context.allocator); - bun.clear(&this.border_inline_start.width, context.allocator); - bun.clear(&this.border_inline_end.width, context.allocator); - this.has_any = true; - }, - .@"border-style" => |*val| { - propertyHelper(this, dest, context, "border_top", "style", &val.top, .physical); - propertyHelper(this, dest, context, "border_right", "style", &val.right, .physical); - propertyHelper(this, dest, context, "border_bottom", "style", &val.bottom, .physical); - propertyHelper(this, dest, context, "border_left", "style", &val.left, .physical); - - bun.clear(&this.border_block_start.style, context.allocator); - bun.clear(&this.border_block_end.style, context.allocator); - bun.clear(&this.border_inline_start.style, context.allocator); - bun.clear(&this.border_inline_end.style, context.allocator); - this.has_any = true; - }, - .@"border-color" => |*val| { - propertyHelper(this, dest, context, "border_top", "color", &val.top, .physical); - propertyHelper(this, dest, context, "border_right", "color", &val.right, .physical); - propertyHelper(this, dest, context, "border_bottom", "color", &val.bottom, .physical); - propertyHelper(this, dest, context, "border_left", "color", &val.left, .physical); - - bun.clear(&this.border_block_start.color, context.allocator); - bun.clear(&this.border_block_end.color, context.allocator); - bun.clear(&this.border_inline_start.color, context.allocator); - bun.clear(&this.border_inline_end.color, context.allocator); - this.has_any = true; - }, - .border => |*val| { - this.border_top.setBorder(context.allocator, val); - this.border_bottom.setBorder(context.allocator, val); - this.border_left.setBorder(context.allocator, val); - this.border_right.setBorder(context.allocator, val); - - this.border_block_start.reset(allocator); - this.border_block_end.reset(allocator); - this.border_inline_start.reset(allocator); - this.border_inline_end.reset(allocator); - - // Setting the `border` property resets `border-image` - this.border_image_handler.reset(allocator); - this.has_any = true; - }, - .unparsed => |*val| { - if (isBorderProperty(val.property_id)) { - this.flush(dest, context); - this.flushUnparsed(val, dest, context); - } else { - if (this.border_image_handler.willFlush(property)) { - this.flush(dest, context); - } - return this.border_image_handler.handleProperty(property, dest, context) or this.border_radius_handler.handleProperty(property, dest, context); - } - }, - else => { - if (this.border_image_handler.willFlush(property)) { - this.flush(dest, context); - } - return this.border_image_handler.handleProperty(property, dest, context) or this.border_radius_handler.handleProperty(property, dest, context); - }, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - this.flushed_properties = .{}; - this.border_image_handler.finalize(dest, context); - this.border_radius_handler.finalize(dest, context); - } - - const FlushContext = struct { - self: *BorderHandler, - dest: *css.DeclarationList, - ctx: *css.PropertyHandlerContext, - logical_supported: bool, - logical_shorthand_supported: bool, - - inline fn logicalProp(f: *FlushContext, comptime ltr: []const u8, comptime ltr_key: []const u8, comptime rtl: []const u8, comptime rtl_key: []const u8, val: anytype) void { - _ = ltr_key; // autofix - _ = rtl_key; // autofix - f.ctx.addLogicalRule(f.ctx.allocator, @unionInit(css.Property, ltr, val.deepClone(f.ctx.allocator)), @unionInit(css.Property, rtl, val.deepClone(f.ctx.allocator))); - } - - inline fn push(f: *FlushContext, comptime p: []const u8, val: anytype) void { - bun.bits.insert(BorderProperty, &f.self.flushed_properties, @field(BorderProperty, p)); - bun.handleOom(f.dest.append(f.ctx.allocator, @unionInit(css.Property, p, val.deepClone(f.ctx.allocator)))); - } - - inline fn fallbacks(f: *FlushContext, comptime p: []const u8, _val: anytype) void { - var val = _val; - if (!bun.bits.contains(BorderProperty, f.self.flushed_properties, @field(BorderProperty, p))) { - const fbs = val.getFallbacks(f.ctx.allocator, f.ctx.targets); - for (css.generic.slice(@TypeOf(fbs), &fbs)) |fallback| { - bun.handleOom(f.dest.append(f.ctx.allocator, @unionInit(css.Property, p, fallback))); - } - } - push(f, p, val); - } - - inline fn prop(f: *FlushContext, comptime prop_name: []const u8, val: anytype) void { - @setEvalBranchQuota(10000); - if (comptime std.mem.eql(u8, prop_name, "border-inline-start")) { - if (f.logical_supported) { - fallbacks(f, "border-inline-start", val); - } else { - logicalProp(f, "border-left", "border_left", "border-right", "border_right", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-inline-start-width")) { - if (f.logical_supported) { - push(f, "border-inline-start-width", val); - } else { - logicalProp(f, "border-left-width", "border_left_width", "border-right-width", "border_right_width", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-inline-start-color")) { - if (f.logical_supported) { - fallbacks(f, "border-inline-start-color", val); - } else { - logicalProp(f, "border-left-color", "border_left_color", "border-right-color", "border_right_color", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-inline-start-style")) { - if (f.logical_supported) { - push(f, "border-inline-start-style", val); - } else { - logicalProp(f, "border-left-style", "border_left_style", "border-right-style", "border_right_style", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-inline-end")) { - if (f.logical_supported) { - fallbacks(f, "border-inline-end", val); - } else { - logicalProp(f, "border-right", "border_right", "border-left", "border_left", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-inline-end-width")) { - if (f.logical_supported) { - push(f, "border-inline-end-width", val); - } else { - logicalProp(f, "border-right-width", "border_right_width", "border-left-width", "border_left_width", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-inline-end-color")) { - if (f.logical_supported) { - fallbacks(f, "border-inline-end-color", val); - } else { - logicalProp(f, "border-right-color", "border_right_color", "border-left-color", "border_left_color", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-inline-end-style")) { - if (f.logical_supported) { - push(f, "border-inline-end-style", val); - } else { - logicalProp(f, "border-right-style", "border_right_style", "border-left-style", "border_left_style", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-start")) { - if (f.logical_supported) { - fallbacks(f, "border-block-start", val); - } else { - fallbacks(f, "border-top", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-start-width")) { - if (f.logical_supported) { - push(f, "border-block-start-width", val); - } else { - push(f, "border-top-width", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-start-color")) { - if (f.logical_supported) { - fallbacks(f, "border-block-start-color", val); - } else { - fallbacks(f, "border-top-color", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-start-style")) { - if (f.logical_supported) { - push(f, "border-block-start-style", val); - } else { - push(f, "border-top-style", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-end")) { - if (f.logical_supported) { - fallbacks(f, "border-block-end", val); - } else { - fallbacks(f, "border-bottom", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-end-width")) { - if (f.logical_supported) { - push(f, "border-block-end-width", val); - } else { - push(f, "border-bottom-width", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-end-color")) { - if (f.logical_supported) { - fallbacks(f, "border-block-end-color", val); - } else { - fallbacks(f, "border-bottom-color", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-block-end-style")) { - if (f.logical_supported) { - push(f, "border-block-end-style", val); - } else { - push(f, "border-bottom-style", val); - } - } else if (comptime std.mem.eql(u8, prop_name, "border-left-color") or - std.mem.eql(u8, prop_name, "border-right-color") or - std.mem.eql(u8, prop_name, "border-top-color") or - std.mem.eql(u8, prop_name, "border-bottom-color") or - std.mem.eql(u8, prop_name, "border-color") or - std.mem.eql(u8, prop_name, "border-block-color") or - std.mem.eql(u8, prop_name, "border-inline-color") or - std.mem.eql(u8, prop_name, "border-left") or - std.mem.eql(u8, prop_name, "border-right") or - std.mem.eql(u8, prop_name, "border-top") or - std.mem.eql(u8, prop_name, "border-bottom") or - std.mem.eql(u8, prop_name, "border-block-start") or - std.mem.eql(u8, prop_name, "border-block-end") or - std.mem.eql(u8, prop_name, "border-inline-start") or - std.mem.eql(u8, prop_name, "border-inline-end") or - std.mem.eql(u8, prop_name, "border-inline") or - std.mem.eql(u8, prop_name, "border-block") or - std.mem.eql(u8, prop_name, "border")) - { - fallbacks(f, prop_name, val); - } else { - push(f, prop_name, val); - } - } - - fn flushCategory( - f: *FlushContext, - comptime block_start_prop: []const u8, - comptime block_start_width: []const u8, - comptime block_start_style: []const u8, - comptime block_start_color: []const u8, - block_start: *BorderShorthand, - comptime block_end_prop: []const u8, - comptime block_end_width: []const u8, - comptime block_end_style: []const u8, - comptime block_end_color: []const u8, - block_end: *BorderShorthand, - comptime inline_start_prop: []const u8, - comptime inline_start_width: []const u8, - comptime inline_start_style: []const u8, - comptime inline_start_color: []const u8, - inline_start: *BorderShorthand, - comptime inline_end_prop: []const u8, - comptime inline_end_width: []const u8, - comptime inline_end_style: []const u8, - comptime inline_end_color: []const u8, - inline_end: *BorderShorthand, - comptime is_logical: bool, - ) void { - const State = struct { - f: *FlushContext, - block_start: *BorderShorthand, - block_end: *BorderShorthand, - inline_start: *BorderShorthand, - inline_end: *BorderShorthand, - - inline fn shorthand(s: *@This(), comptime p: type, comptime prop_name: []const u8, comptime key: []const u8) void { - const has_prop = @field(s.block_start, key) != null and @field(s.block_end, key) != null and @field(s.inline_start, key) != null and @field(s.inline_end, key) != null; - if (has_prop) { - if (!is_logical or css.generic.eql(@TypeOf(@field(s.block_start, key)), &@field(s.block_start, key), &@field(s.block_end, key)) and - css.generic.eql(@TypeOf(@field(s.block_end, key)), &@field(s.block_end, key), &@field(s.inline_start, key)) and - css.generic.eql(@TypeOf(@field(s.inline_start, key)), &@field(s.inline_start, key), &@field(s.inline_end, key))) - { - const rect = p{ - .top = bun.take(&@field(s.block_start, key)).?, - .right = bun.take(&@field(s.inline_end, key)).?, - .bottom = bun.take(&@field(s.block_end, key)).?, - .left = bun.take(&@field(s.inline_start, key)).?, - }; - prop(s.f, prop_name, rect); - } - } - } - - inline fn logicalShorthand( - s: *@This(), - comptime P: type, - comptime prop_name: []const u8, - comptime key: []const u8, - start: anytype, - end: anytype, - ) void { - const has_prop = @field(start, key) != null and @field(end, key) != null; - if (has_prop) { - prop(s.f, prop_name, P{ - .start = bun.take(&@field(start, key)).?, - .end = bun.take(&@field(end, key)).?, - }); - bun.clear(&@field(end, key), s.f.ctx.allocator); - } - } - - inline fn is_eq(s: *@This(), comptime key: []const u8) bool { - return css.generic.eql(@TypeOf(@field(s.block_start, key)), &@field(s.block_start, key), &@field(s.block_end, key)) and - css.generic.eql(@TypeOf(@field(s.inline_start, key)), &@field(s.inline_start, key), &@field(s.inline_end, key)) and - css.generic.eql(@TypeOf(@field(s.inline_start, key)), &@field(s.inline_start, key), &@field(s.block_start, key)); - } - - inline fn prop_diff(s: *@This(), border: anytype, fallback: anytype, border_fallback: anytype) void { - if (!is_logical and - s.is_eq("color") and - s.is_eq("style")) - { - prop(s.f, "border", border.toBorder(s.f.ctx.allocator)); - shorthand(s, BorderWidth, "border-width", "width"); - } else if (!is_logical and - s.is_eq("width") and - s.is_eq("style")) - { - prop(s.f, "border", border.toBorder(s.f.ctx.allocator)); - shorthand(s, BorderColor, "border-color", "color"); - } else if (!is_logical and - s.is_eq("width") and - s.is_eq("color")) - { - prop(s.f, "border", border.toBorder(s.f.ctx.allocator)); - shorthand(s, BorderStyle, "border-style", "style"); - } else { - if (border_fallback) { - prop(s.f, "border", border.toBorder(s.f.ctx.allocator)); - } - fallback(s); - } - } - - inline fn side_diff(s: *@This(), border: anytype, other: anytype, comptime prop_name: []const u8, width: anytype, style: anytype, comptime color: []const u8) void { - const eq_width = css.generic.eql(@TypeOf(border.width), &border.width, &other.width); - const eq_style = css.generic.eql(@TypeOf(border.style), &border.style, &other.style); - const eq_color = css.generic.eql(@TypeOf(border.color), &border.color, &other.color); - - // If only one of the sub-properties is different, only emit that. - // Otherwise, emit the full border value. - if (eq_width and eq_style) { - s.f.prop(color, css.generic.deepClone(@TypeOf(other.color), &other.color, s.f.ctx.allocator).?); - } else if (eq_width and eq_color) { - s.f.prop(style, css.generic.deepClone(@TypeOf(other.style), &other.style, s.f.ctx.allocator).?); - } else if (eq_style and eq_color) { - s.f.prop(width, css.generic.deepClone(@TypeOf(other.width), &other.width, s.f.ctx.allocator).?); - } else { - s.f.prop(prop_name, other.toBorder(s.f.ctx.allocator)); - } - } - - inline fn side(s: *@This(), val: anytype, comptime short: []const u8, comptime width: []const u8, comptime style: []const u8, comptime color: []const u8) void { - if (val.isValid()) { - s.f.prop(short, val.toBorder(s.f.ctx.allocator)); - } else { - if (val.style) |*sty| { - s.f.prop(style, sty.deepClone(s.f.ctx.allocator)); - } - - if (val.width) |*w| { - s.f.prop(width, w.deepClone(s.f.ctx.allocator)); - } - - if (val.color) |*c| { - s.f.prop(color, c.deepClone(s.f.ctx.allocator)); - } - } - } - - // If both values of an inline logical property are equal, then we can just convert them to physical properties. - inline fn inlineProp(s: *@This(), comptime key: []const u8, comptime left: []const u8, comptime right: []const u8) void { - if (@field(s.inline_start, key) != null and css.generic.eql(@TypeOf(@field(s.inline_start, key)), &@field(s.inline_start, key), &@field(s.inline_end, key))) { - s.f.prop(left, bun.take(&@field(s.inline_start, key)).?); - s.f.prop(right, bun.take(&@field(s.inline_end, key)).?); - } - } - }; - - var state = State{ - .f = f, - .block_start = block_start, - .block_end = block_end, - .inline_start = inline_start, - .inline_end = inline_end, - }; - - if (block_start.isValid() and block_end.isValid() and inline_start.isValid() and inline_end.isValid()) { - const top_eq_bottom = block_start.eql(block_end); - const left_eq_right = inline_start.eql(inline_end); - const top_eq_left = block_start.eql(inline_start); - const top_eq_right = block_start.eql(inline_end); - const bottom_eq_left = block_end.eql(inline_start); - const bottom_eq_right = block_end.eql(inline_end); - - if (top_eq_bottom and top_eq_left and top_eq_right) { - state.f.prop("border", block_start.toBorder(f.ctx.allocator)); - } else if (top_eq_bottom and top_eq_left) { - state.f.prop("border", block_start.toBorder(f.ctx.allocator)); - state.side_diff(block_start, inline_end, inline_end_prop, inline_end_width, inline_end_style, inline_end_color); - } else if (top_eq_bottom and top_eq_right) { - state.f.prop("border", block_start.toBorder(f.ctx.allocator)); - state.side_diff(block_start, inline_start, inline_start_prop, inline_start_width, inline_start_style, inline_start_color); - } else if (left_eq_right and bottom_eq_left) { - state.f.prop("border", inline_start.toBorder(f.ctx.allocator)); - state.side_diff(inline_start, block_start, block_start_prop, block_start_width, block_start_style, block_start_color); - } else if (left_eq_right and top_eq_left) { - state.f.prop("border", inline_start.toBorder(f.ctx.allocator)); - state.side_diff(inline_start, block_end, block_end_prop, block_end_width, block_end_style, block_end_color); - } else if (top_eq_bottom) { - state.prop_diff(block_start, struct { - fn fallback(s: *State) void { - // Try to use border-inline shorthands for the opposite direction if possible - var handled = false; - if (is_logical) { - var diff: u32 = 0; - if (!css.generic.eql(@TypeOf(s.inline_start.width), &s.inline_start.width, &s.block_start.width) or - !css.generic.eql(@TypeOf(s.inline_end.width), &s.inline_end.width, &s.block_start.width)) - { - diff += 1; - } - if (!css.generic.eql(@TypeOf(s.inline_start.style), &s.inline_start.style, &s.block_start.style) or - !css.generic.eql(@TypeOf(s.inline_end.style), &s.inline_end.style, &s.block_start.style)) - { - diff += 1; - } - if (!css.generic.eql(@TypeOf(s.inline_start.color), &s.inline_start.color, &s.block_start.color) or - !css.generic.eql(@TypeOf(s.inline_end.color), &s.inline_end.color, &s.block_start.color)) - { - diff += 1; - } - - if (diff == 1) { - if (!css.generic.eql(@TypeOf(s.inline_start.width), &s.inline_start.width, &s.block_start.width)) { - s.f.prop("border-inline-width", BorderInlineWidth{ - .start = s.inline_start.width.?.deepClone(s.f.ctx.allocator), - .end = s.inline_end.width.?.deepClone(s.f.ctx.allocator), - }); - handled = true; - } else if (!css.generic.eql(@TypeOf(s.inline_start.style), &s.inline_start.style, &s.block_start.style)) { - s.f.prop("border-inline-style", BorderInlineStyle{ - .start = s.inline_start.style.?.deepClone(s.f.ctx.allocator), - .end = s.inline_end.style.?.deepClone(s.f.ctx.allocator), - }); - handled = true; - } else if (!css.generic.eql(@TypeOf(s.inline_start.color), &s.inline_start.color, &s.block_start.color)) { - s.f.prop("border-inline-color", BorderInlineColor{ - .start = s.inline_start.color.?.deepClone(s.f.ctx.allocator), - .end = s.inline_end.color.?.deepClone(s.f.ctx.allocator), - }); - handled = true; - } - } else if (diff > 1 and - css.generic.eql(@TypeOf(s.inline_start.width), &s.inline_start.width, &s.inline_end.width) and - css.generic.eql(@TypeOf(s.inline_start.style), &s.inline_start.style, &s.inline_end.style) and - css.generic.eql(@TypeOf(s.inline_start.color), &s.inline_start.color, &s.inline_end.color)) - { - s.f.prop("border-inline", s.inline_start.toBorder(s.f.ctx.allocator)); - handled = true; - } - } - - if (!handled) { - s.side_diff(s.block_start, s.inline_start, inline_start_prop, inline_start_width, inline_start_style, inline_start_color); - s.side_diff(s.block_start, s.inline_end, inline_end_prop, inline_end_width, inline_end_style, inline_end_color); - } - } - }.fallback, true); - } else if (left_eq_right) { - state.prop_diff(inline_start, struct { - fn fallback(s: *State) void { - // We know already that top != bottom, so no need to try to use border-block. - s.side_diff(s.inline_start, s.block_start, block_start_prop, block_start_width, block_start_style, block_start_color); - s.side_diff(s.inline_start, s.block_end, block_end_prop, block_end_width, block_end_style, block_end_color); - } - }.fallback, true); - } else if (bottom_eq_right) { - state.prop_diff(block_end, struct { - fn fallback(s: *State) void { - s.side_diff(s.block_end, s.block_start, block_start_prop, block_start_width, block_start_style, block_start_color); - s.side_diff(s.block_end, s.inline_start, inline_start_prop, inline_start_width, inline_start_style, inline_start_color); - } - }.fallback, true); - } else { - state.prop_diff(block_start, struct { - fn fallback(s: *State) void { - s.f.prop(block_start_prop, s.block_start.toBorder(s.f.ctx.allocator)); - s.f.prop(block_end_prop, s.block_end.toBorder(s.f.ctx.allocator)); - s.f.prop(inline_start_prop, s.inline_start.toBorder(s.f.ctx.allocator)); - s.f.prop(inline_end_prop, s.inline_end.toBorder(s.f.ctx.allocator)); - } - }.fallback, false); - } - } else { - state.shorthand(BorderStyle, "border-style", "style"); - state.shorthand(BorderWidth, "border-width", "width"); - state.shorthand(BorderColor, "border-color", "color"); - - if (is_logical and block_start.eql(block_end) and block_start.isValid()) { - if (f.logical_supported) { - if (f.logical_shorthand_supported) { - state.f.prop("border-block", block_start.toBorder(f.ctx.allocator)); - } else { - state.f.prop("border-block-start", block_start.toBorder(f.ctx.allocator)); - state.f.prop("border-block-end", block_start.toBorder(f.ctx.allocator)); - } - } else { - state.f.prop("border-top", block_start.toBorder(f.ctx.allocator)); - state.f.prop("border-bottom", block_start.toBorder(f.ctx.allocator)); - } - } else { - if (is_logical and f.logical_shorthand_supported and !block_start.isValid() and !block_end.isValid()) { - state.logicalShorthand(BorderBlockStyle, "border-block-style", "style", block_start, block_end); - state.logicalShorthand(BorderBlockWidth, "border-block-width", "width", block_start, block_end); - state.logicalShorthand(BorderBlockColor, "border-block-color", "color", block_start, block_end); - } - - state.side(block_start, block_start_prop, block_start_width, block_start_style, block_start_color); - state.side(block_end, block_end_prop, block_end_width, block_end_style, block_end_color); - } - - if (is_logical and inline_start.eql(inline_end) and inline_start.isValid()) { - if (f.logical_supported) { - if (f.logical_shorthand_supported) { - state.f.prop("border-inline", inline_start.toBorder(f.ctx.allocator)); - } else { - state.f.prop("border-inline-start", inline_start.toBorder(f.ctx.allocator)); - state.f.prop("border-inline-end", inline_start.toBorder(f.ctx.allocator)); - } - } else { - state.f.prop("border-left", inline_start.toBorder(f.ctx.allocator)); - state.f.prop("border-right", inline_start.toBorder(f.ctx.allocator)); - } - } else { - if (is_logical and !inline_start.isValid() and !inline_end.isValid()) { - if (f.logical_shorthand_supported) { - state.logicalShorthand(BorderInlineStyle, "border-inline-style", "style", inline_start, inline_end); - state.logicalShorthand(BorderInlineWidth, "border-inline-width", "width", inline_start, inline_end); - state.logicalShorthand(BorderInlineColor, "border-inline-color", "color", inline_start, inline_end); - } else { - // If both values of an inline logical property are equal, then we can just convert them to physical properties. - state.inlineProp("style", "border-left-style", "border-right-style"); - state.inlineProp("width", "border-left-width", "border-right-width"); - state.inlineProp("color", "border-left-color", "border-right-color"); - } - } - - state.side(inline_start, inline_start_prop, inline_start_width, inline_start_style, inline_start_color); - state.side(inline_end, inline_end_prop, inline_end_width, inline_end_style, inline_end_color); - } - } - } - }; - - fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - - this.has_any = false; - - const logical_supported = !context.shouldCompileLogical(css.Feature.logical_borders); - const logical_shorthand_supported = !context.shouldCompileLogical(css.Feature.logical_border_shorthand); - - var flctx = FlushContext{ - .self = this, - .dest = dest, - .ctx = context, - .logical_supported = logical_supported, - .logical_shorthand_supported = logical_shorthand_supported, - }; - - flctx.flushCategory( - "border-top", - "border-top-width", - "border-top-style", - "border-top-color", - &this.border_top, - - "border-bottom", - "border-bottom-width", - "border-bottom-style", - "border-bottom-color", - &this.border_bottom, - - "border-left", - "border-left-width", - "border-left-style", - "border-left-color", - &this.border_left, - - "border-right", - "border-right-width", - "border-right-style", - "border-right-color", - &this.border_right, - - false, - ); - - flctx.flushCategory( - "border-block-start", - "border-block-start-width", - "border-block-start-style", - "border-block-start-color", - &this.border_block_start, - - "border-block-end", - "border-block-end-width", - "border-block-end-style", - "border-block-end-color", - &this.border_block_end, - - "border-inline-start", - "border-inline-start-width", - "border-inline-start-style", - "border-inline-start-color", - &this.border_inline_start, - - "border-inline-end", - "border-inline-end-width", - "border-inline-end-style", - "border-inline-end-color", - &this.border_inline_end, - - true, - ); - - this.border_top.reset(context.allocator); - this.border_bottom.reset(context.allocator); - this.border_left.reset(context.allocator); - this.border_right.reset(context.allocator); - this.border_block_start.reset(context.allocator); - this.border_block_end.reset(context.allocator); - this.border_inline_start.reset(context.allocator); - this.border_inline_end.reset(context.allocator); - } - - fn flushUnparsed(this: *@This(), unparsed: *const UnparsedProperty, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - const logical_supported = !context.shouldCompileLogical(css.Feature.logical_borders); - if (logical_supported) { - var up = unparsed.deepClone(context.allocator); - context.addUnparsedFallbacks(&up); - bun.bits.insert(BorderProperty, &this.flushed_properties, BorderProperty.tryFromPropertyId(up.property_id).?); - bun.handleOom(dest.append(context.allocator, .{ .unparsed = up })); - return; - } - - const prop = struct { - inline fn prop(self: *BorderHandler, d: *css.DeclarationList, c: *css.PropertyHandlerContext, up: *const UnparsedProperty, comptime id: []const u8) void { - _ = d; // autofix - var upppppppppp = up.withPropertyId(c.allocator, @unionInit(css.PropertyId, id, {})); - c.addUnparsedFallbacks(&upppppppppp); - bun.bits.insert(BorderProperty, &self.flushed_properties, @field(BorderProperty, id)); - } - }.prop; - - const logical_prop = struct { - inline fn logical_prop( - c: *css.PropertyHandlerContext, - up: *const UnparsedProperty, - comptime ltr: []const u8, - comptime rtl: []const u8, - ) void { - c.addLogicalRule( - c.allocator, - css.Property{ - .unparsed = up.withPropertyId( - c.allocator, - @unionInit(css.PropertyId, ltr, {}), - ), - }, - css.Property{ - .unparsed = up.withPropertyId( - c.allocator, - @unionInit(css.PropertyId, rtl, {}), - ), - }, - ); - } - }.logical_prop; - - switch (unparsed.property_id) { - .@"border-inline-start" => logical_prop(context, unparsed, "border-left", "border-right"), - .@"border-inline-start-width" => logical_prop(context, unparsed, "border-left-width", "border-right-width"), - .@"border-inline-start-color" => logical_prop(context, unparsed, "border-left-color", "border-right-color"), - .@"border-inline-start-style" => logical_prop(context, unparsed, "border-left-style", "border-right-style"), - .@"border-inline-end" => logical_prop(context, unparsed, "border-right", "border-left"), - .@"border-inline-end-width" => logical_prop(context, unparsed, "border-right-width", "border-left-width"), - .@"border-inline-end-color" => logical_prop(context, unparsed, "border-right-color", "border-left-color"), - .@"border-inline-end-style" => logical_prop(context, unparsed, "border-right-style", "border-left-style"), - .@"border-block-start" => prop(this, dest, context, unparsed, "border-top"), - .@"border-block-start-width" => prop(this, dest, context, unparsed, "border-top-width"), - .@"border-block-start-color" => prop(this, dest, context, unparsed, "border-top-color"), - .@"border-block-start-style" => prop(this, dest, context, unparsed, "border-top-style"), - .@"border-block-end" => prop(this, dest, context, unparsed, "border-bottom"), - .@"border-block-end-width" => prop(this, dest, context, unparsed, "border-bottom-width"), - .@"border-block-end-color" => prop(this, dest, context, unparsed, "border-bottom-color"), - .@"border-block-end-style" => prop(this, dest, context, unparsed, "border-bottom-style"), - else => { - var up = unparsed.deepClone(context.allocator); - context.addUnparsedFallbacks(&up); - bun.bits.insert(BorderProperty, &this.flushed_properties, BorderProperty.tryFromPropertyId(up.property_id).?); - bun.handleOom(dest.append(context.allocator, .{ .unparsed = up })); - }, - } - } -}; - -fn isBorderProperty(property_id: css.PropertyIdTag) bool { - return switch (property_id) { - .@"border-top-color", .@"border-bottom-color", .@"border-left-color", .@"border-right-color", .@"border-block-start-color", .@"border-block-end-color", .@"border-block-color", .@"border-inline-start-color", .@"border-inline-end-color", .@"border-inline-color", .@"border-top-width", .@"border-bottom-width", .@"border-left-width", .@"border-right-width", .@"border-block-start-width", .@"border-block-end-width", .@"border-block-width", .@"border-inline-start-width", .@"border-inline-end-width", .@"border-inline-width", .@"border-top-style", .@"border-bottom-style", .@"border-left-style", .@"border-right-style", .@"border-block-start-style", .@"border-block-end-style", .@"border-block-style", .@"border-inline-start-style", .@"border-inline-end-style", .@"border-inline-style", .@"border-top", .@"border-bottom", .@"border-left", .@"border-right", .@"border-block-start", .@"border-block-end", .@"border-inline-start", .@"border-inline-end", .@"border-block", .@"border-inline", .@"border-width", .@"border-style", .@"border-color", .border => true, - else => false, - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const BorderImageHandler = @import("./border_image.zig").BorderImageHandler; -const BorderRadiusHandler = @import("./border_radius.zig").BorderRadiusHandler; -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/border_image.zig b/src/css/properties/border_image.zig deleted file mode 100644 index ea0c53d39057..000000000000 --- a/src/css/properties/border_image.zig +++ /dev/null @@ -1,637 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const LengthPercentage = css.css_values.length.LengthPercentage; -const CSSNumber = css.css_values.number.CSSNumber; -const LengthOrNumber = css.css_values.length.LengthOrNumber; -const Image = css.css_values.image.Image; -const Rect = css.css_values.rect.Rect; -const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage; -const Percentage = css.css_values.percentage.Percentage; -const Property = css.Property; -const VendorPrefix = css.VendorPrefix; - -/// A value for the [border-image](https://www.w3.org/TR/css-backgrounds-3/#border-image) shorthand property. -pub const BorderImage = struct { - /// The border image. - source: Image, - /// The offsets that define where the image is sliced. - slice: BorderImageSlice, - /// The width of the border image. - width: Rect(BorderImageSideWidth), - /// The amount that the image extends beyond the border box. - outset: Rect(css.css_values.length.LengthOrNumber), - /// How the border image is scaled and tiled. - repeat: BorderImageRepeat, - - pub const PropertyFieldMap = .{ - .source = css.PropertyIdTag.@"border-image-source", - .slice = css.PropertyIdTag.@"border-image-slice", - .width = css.PropertyIdTag.@"border-image-width", - .outset = css.PropertyIdTag.@"border-image-outset", - .repeat = css.PropertyIdTag.@"border-image-repeat", - }; - - pub const VendorPrefixMap = .{ - .source = true, - .slice = true, - .width = true, - .outset = true, - .repeat = true, - }; - - pub fn parse(input: *css.Parser) css.Result(BorderImage) { - return parseWithCallback(input, {}, struct { - pub fn cb(_: void, _: *css.Parser) bool { - return false; - } - }.cb); - } - - pub fn parseWithCallback(input: *css.Parser, ctx: anytype, comptime callback: anytype) css.Result(BorderImage) { - var source: ?Image = null; - var slice: ?BorderImageSlice = null; - var width: ?Rect(BorderImageSideWidth) = null; - var outset: ?Rect(LengthOrNumber) = null; - var repeat: ?BorderImageRepeat = null; - - while (true) { - if (slice == null) { - if (input.tryParse(BorderImageSlice.parse, .{}).asValue()) |value| { - slice = value; - // Parse border image width and outset, if applicable. - const maybe_width_outset = input.tryParse(struct { - pub fn parse(i: *css.Parser) css.Result(struct { ?Rect(BorderImageSideWidth), ?Rect(LengthOrNumber) }) { - if (i.expectDelim('/').asErr()) |e| return .{ .err = e }; - - const w = i.tryParse(Rect(BorderImageSideWidth).parse, .{}).asValue(); - - const o = i.tryParse(struct { - pub fn parseFn(in: *css.Parser) css.Result(Rect(LengthOrNumber)) { - if (in.expectDelim('/').asErr()) |e| return .{ .err = e }; - return Rect(LengthOrNumber).parse(in); - } - }.parseFn, .{}).asValue(); - - if (w == null and o == null) return .{ .err = i.newCustomError(css.ParserError.invalid_declaration) }; - return .{ .result = .{ w, o } }; - } - }.parse, .{}); - - if (maybe_width_outset.asValue()) |val| { - width = val[0]; - outset = val[1]; - } - continue; - } - } - - if (source == null) { - if (input.tryParse(Image.parse, .{}).asValue()) |value| { - source = value; - continue; - } - } - - if (repeat == null) { - if (input.tryParse(BorderImageRepeat.parse, .{}).asValue()) |value| { - repeat = value; - continue; - } - } - - if (@call(.auto, callback, .{ ctx, input })) { - continue; - } - - break; - } - - if (source != null or slice != null or width != null or outset != null or repeat != null) { - return .{ - .result = BorderImage{ - .source = source orelse Image.default(), - .slice = slice orelse BorderImageSlice.default(), - .width = width orelse Rect(BorderImageSideWidth).all(BorderImageSideWidth.default()), - .outset = outset orelse Rect(LengthOrNumber).all(LengthOrNumber.default()), - .repeat = repeat orelse BorderImageRepeat.default(), - }, - }; - } - return .{ .err = input.newCustomError(css.ParserError.invalid_declaration) }; - } - - pub fn toCss(this: *const BorderImage, dest: *css.Printer) PrintErr!void { - return toCssInternal(&this.source, &this.slice, &this.width, &this.outset, &this.repeat, dest); - } - - pub fn toCssInternal( - source: *const Image, - slice: *const BorderImageSlice, - width: *const Rect(BorderImageSideWidth), - outset: *const Rect(LengthOrNumber), - repeat: *const BorderImageRepeat, - dest: *css.Printer, - ) PrintErr!void { - if (!css.generic.eql(Image, source, &Image.default())) { - try source.toCss(dest); - } - const has_slice = !css.generic.eql(BorderImageSlice, slice, &BorderImageSlice.default()); - const has_width = !css.generic.eql(Rect(BorderImageSideWidth), width, &Rect(BorderImageSideWidth).all(BorderImageSideWidth.default())); - const has_outset = !css.generic.eql(Rect(LengthOrNumber), outset, &Rect(LengthOrNumber).all(LengthOrNumber{ .number = 0.0 })); - if (has_slice or has_width or has_outset) { - try dest.writeStr(" "); - try slice.toCss(dest); - if (has_width or has_outset) { - try dest.delim('/', true); - } - if (has_width) { - try width.toCss(dest); - } - - if (has_outset) { - try dest.delim('/', true); - try outset.toCss(dest); - } - } - - if (!css.generic.eql(BorderImageRepeat, repeat, &BorderImageRepeat.default())) { - try dest.writeStr(" "); - return repeat.toCss(dest); - } - - return; - } - - pub fn getFallbacks(this: *@This(), allocator: Allocator, targets: css.targets.Targets) css.SmallList(BorderImage, 6) { - var fallbacks = this.source.getFallbacks(allocator, targets); - defer fallbacks.deinit(allocator); - var res = css.SmallList(BorderImage, 6).initCapacity(allocator, fallbacks.len()); - res.setLen(fallbacks.len()); - for (fallbacks.slice(), res.slice_mut()) |fallback, *out| { - out.* = this.deepClone(allocator); - out.source = fallback; - } - - return res; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const BorderImage, other: *const BorderImage) bool { - return this.source.eql(&other.source) and - this.slice.eql(&other.slice) and - this.width.eql(&other.width) and - this.outset.eql(&other.outset) and - this.repeat.eql(&other.repeat); - } - - pub fn default() BorderImage { - return BorderImage{ - .source = Image.default(), - .slice = BorderImageSlice.default(), - .width = Rect(BorderImageSideWidth).all(BorderImageSideWidth.default()), - .outset = Rect(LengthOrNumber).all(LengthOrNumber.default()), - .repeat = BorderImageRepeat.default(), - }; - } -}; - -/// A value for the [border-image-repeat](https://www.w3.org/TR/css-backgrounds-3/#border-image-repeat) property. -pub const BorderImageRepeat = struct { - /// The horizontal repeat value. - horizontal: BorderImageRepeatKeyword, - /// The vertical repeat value. - vertical: BorderImageRepeatKeyword, - - pub fn parse(input: *css.Parser) css.Result(BorderImageRepeat) { - const horizontal = switch (BorderImageRepeatKeyword.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const vertical = input.tryParse(BorderImageRepeatKeyword.parse, .{}).asValue(); - return .{ .result = BorderImageRepeat{ - .horizontal = horizontal, - .vertical = vertical orelse horizontal, - } }; - } - - pub fn toCss(this: *const BorderImageRepeat, dest: *Printer) PrintErr!void { - try this.horizontal.toCss(dest); - if (this.horizontal != this.vertical) { - try dest.writeStr(" "); - try this.vertical.toCss(dest); - } - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return this.horizontal.isCompatible(browsers) and this.vertical.isCompatible(browsers); - } - - pub fn default() BorderImageRepeat { - return BorderImageRepeat{ - .horizontal = BorderImageRepeatKeyword.stretch, - .vertical = BorderImageRepeatKeyword.stretch, - }; - } - - pub fn eql(this: *const BorderImageRepeat, other: *const BorderImageRepeat) bool { - return this.horizontal.eql(&other.horizontal) and this.vertical.eql(&other.vertical); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [border-image-width](https://www.w3.org/TR/css-backgrounds-3/#border-image-width) property. -pub const BorderImageSideWidth = union(enum) { - /// A number representing a multiple of the border width. - number: CSSNumber, - /// An explicit length or percentage. - length_percentage: LengthPercentage, - /// The `auto` keyword, representing the natural width of the image slice. - auto: void, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn deinit(this: *const BorderImageSideWidth, allocator: std.mem.Allocator) void { - switch (this.*) { - .length_percentage => |*l| l.deinit(allocator), - .number => {}, - .auto => {}, - } - } - - pub fn default() BorderImageSideWidth { - return .{ .number = 1.0 }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const BorderImageSideWidth, other: *const BorderImageSideWidth) bool { - return switch (this.*) { - .number => |*a| switch (other.*) { - .number => |*b| a.* == b.*, - else => false, - }, - .length_percentage => |*a| switch (other.*) { - .length_percentage => css.generic.eql(LengthPercentage, a, &other.length_percentage), - else => false, - }, - .auto => switch (other.*) { - .auto => true, - else => false, - }, - }; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .length_percentage => |*l| l.isCompatible(browsers), - else => true, - }; - } -}; - -/// A single [border-image-repeat](https://www.w3.org/TR/css-backgrounds-3/#border-image-repeat) keyword. -pub const BorderImageRepeatKeyword = enum { - /// The image is stretched to fill the area. - stretch, - /// The image is tiled (repeated) to fill the area. - repeat, - /// The image is scaled so that it repeats an even number of times. - round, - /// The image is repeated so that it fits, and then spaced apart evenly. - space, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .round => css.compat.Feature.border_image_repeat_round.isCompatible(browsers), - .space => css.compat.Feature.border_image_repeat_space.isCompatible(browsers), - .stretch, .repeat => true, - }; - } -}; - -/// A value for the [border-image-slice](https://www.w3.org/TR/css-backgrounds-3/#border-image-slice) property. -pub const BorderImageSlice = struct { - /// The offsets from the edges of the image. - offsets: Rect(NumberOrPercentage), - /// Whether the middle of the border image should be preserved. - fill: bool, - - pub fn parse(input: *css.Parser) css.Result(BorderImageSlice) { - var fill = switch (input.expectIdentMatching("fill")) { - .err => false, - .result => true, - }; - const offsets = switch (Rect(NumberOrPercentage).parse(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (!fill) { - fill = switch (input.expectIdentMatching("fill")) { - .err => false, - .result => true, - }; - } - return .{ .result = BorderImageSlice{ .offsets = offsets, .fill = fill } }; - } - - pub fn toCss(this: *const BorderImageSlice, dest: *Printer) PrintErr!void { - try this.offsets.toCss(dest); - if (this.fill) { - try dest.writeStr(" fill"); - } - } - - pub fn isCompatible(_: *const BorderImageSlice, _: css.targets.Browsers) bool { - return true; - } - - pub fn eql(this: *const BorderImageSlice, other: *const BorderImageSlice) bool { - return this.offsets.eql(&other.offsets) and this.fill == other.fill; - } - - pub fn default() BorderImageSlice { - return BorderImageSlice{ - .offsets = Rect(NumberOrPercentage).all(NumberOrPercentage{ .percentage = Percentage{ .v = 1.0 } }), - .fill = false, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const BorderImageProperty = packed struct(u8) { - source: bool = false, - slice: bool = false, - width: bool = false, - outset: bool = false, - repeat: bool = false, - __unused: u3 = 0, - - pub const @"border-image-source" = BorderImageProperty{ .source = true }; - pub const @"border-image-slice" = BorderImageProperty{ .slice = true }; - pub const @"border-image-width" = BorderImageProperty{ .width = true }; - pub const @"border-image-outset" = BorderImageProperty{ .outset = true }; - pub const @"border-image-repeat" = BorderImageProperty{ .repeat = true }; - - pub const @"border-image" = BorderImageProperty{ - .source = true, - .slice = true, - .width = true, - .outset = true, - .repeat = true, - }; - - pub fn isEmpty(this: BorderImageProperty) bool { - return @as(u8, @bitCast(this)) == 0; - } - - pub fn tryFromPropertyId(property_id: css.PropertyIdTag) ?BorderImageProperty { - inline for (std.meta.fields(BorderImageProperty)) |field| { - if (comptime std.mem.eql(u8, field.name, "__unused")) continue; - const desired = comptime @field(css.PropertyIdTag, "border-image-" ++ field.name); - if (desired == property_id) { - var result: BorderImageProperty = .{}; - @field(result, field.name) = true; - return result; - } - } - if (property_id == .@"border-image") { - return BorderImageProperty.@"border-image"; - } - return null; - } -}; - -pub const BorderImageHandler = struct { - source: ?Image = null, - slice: ?BorderImageSlice = null, - width: ?Rect(BorderImageSideWidth) = null, - outset: ?Rect(LengthOrNumber) = null, - repeat: ?BorderImageRepeat = null, - vendor_prefix: css.VendorPrefix = .{}, - flushed_properties: BorderImageProperty = .{}, - has_any: bool = false, - - pub fn handleProperty(this: *@This(), property: *const css.Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool { - const allocator = context.allocator; - - const flushHelper = struct { - inline fn flushHelper( - self: *BorderImageHandler, - d: *css.DeclarationList, - ctx: *css.PropertyHandlerContext, - comptime name: []const u8, - val: anytype, - ) void { - if (@field(self, name) != null and !@field(self, name).?.eql(val) and ctx.targets.browsers != null and css.generic.isCompatible(@TypeOf(@field(self, name).?), val, ctx.targets.browsers.?)) { - self.flush(d, ctx); - } - } - }.flushHelper; - - const propertyHelper = struct { - inline fn propertyHelper(self: *BorderImageHandler, comptime field: []const u8, comptime T: type, val: *const T, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext) void { - if (self.vendor_prefix != VendorPrefix{ .none = true }) { - self.flush(d, ctx); - } - - flushHelper(self, d, ctx, field, val); - - self.vendor_prefix = VendorPrefix{ .none = true }; - @field(self, field) = val.deepClone(ctx.allocator); - self.has_any = true; - } - }.propertyHelper; - - switch (property.*) { - .@"border-image-source" => |*val| propertyHelper(this, "source", Image, val, dest, context), - .@"border-image-slice" => |*val| propertyHelper(this, "slice", BorderImageSlice, val, dest, context), - .@"border-image-width" => |*val| propertyHelper(this, "width", Rect(BorderImageSideWidth), val, dest, context), - .@"border-image-outset" => |*val| propertyHelper(this, "outset", Rect(LengthOrNumber), val, dest, context), - .@"border-image-repeat" => |*val| propertyHelper(this, "repeat", BorderImageRepeat, val, dest, context), - .@"border-image" => |_val| { - const val = &_val[0]; - const vp = _val[1]; - - flushHelper(this, dest, context, "source", &val.source); - flushHelper(this, dest, context, "slice", &val.slice); - flushHelper(this, dest, context, "width", &val.width); - flushHelper(this, dest, context, "outset", &val.outset); - flushHelper(this, dest, context, "repeat", &val.repeat); - - this.source = val.source.deepClone(allocator); - this.slice = val.slice.deepClone(allocator); - this.width = val.width.deepClone(allocator); - this.outset = val.outset.deepClone(allocator); - this.repeat = val.repeat.deepClone(allocator); - this.vendor_prefix = bun.bits.@"or"(VendorPrefix, this.vendor_prefix, vp); - this.has_any = true; - }, - .unparsed => |unparsed| { - if (isBorderImageProperty(unparsed.property_id)) { - this.flush(dest, context); - - // Even if we weren't able to parse the value (e.g. due to var() references), - // we can still add vendor prefixes to the property itself. - var unparsed_clone = if (unparsed.property_id == .@"border-image") - unparsed.getPrefixed(allocator, context.targets, css.prefixes.Feature.border_image) - else - unparsed.deepClone(allocator); - - context.addUnparsedFallbacks(&unparsed_clone); - bun.bits.insert(BorderImageProperty, &this.flushed_properties, BorderImageProperty.tryFromPropertyId(unparsed_clone.property_id).?); - bun.handleOom(dest.append(allocator, Property{ .unparsed = unparsed_clone })); - } else return false; - }, - else => return false, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - this.flushed_properties = BorderImageProperty{}; - } - - pub fn reset(this: *@This(), allocator: std.mem.Allocator) void { - if (this.source) |*s| s.deinit(allocator); - // if (this.slice) |*s| s.deinit(allocator); - if (this.width) |*w| w.deinit(allocator); - if (this.outset) |*o| o.deinit(allocator); - // if (this.repeat) |*r| r.deinit(allocator); - this.source = null; - this.slice = null; - this.width = null; - this.outset = null; - this.repeat = null; - } - - pub fn willFlush(this: *const @This(), property: *const Property) bool { - return switch (property.*) { - .@"border-image-source", - .@"border-image-slice", - .@"border-image-width", - .@"border-image-outset", - .@"border-image-repeat", - => this.vendor_prefix != VendorPrefix{ .none = true }, - .unparsed => |val| isBorderImageProperty(val.property_id), - else => false, - }; - } - - fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - const allocator = context.allocator; - - this.has_any = false; - - var source = bun.take(&this.source); - const slice = bun.take(&this.slice); - const width = bun.take(&this.width); - const outset = bun.take(&this.outset); - const repeat = bun.take(&this.repeat); - - if (source != null and slice != null and width != null and outset != null and repeat != null) { - var border_image = BorderImage{ - .source = source.?, - .slice = slice.?, - .width = width.?, - .outset = outset.?, - .repeat = repeat.?, - }; - - var prefix = this.vendor_prefix; - if (prefix.none and !border_image.slice.fill) { - prefix = context.targets.prefixes(this.vendor_prefix, css.prefixes.Feature.border_image); - if (this.flushed_properties.isEmpty()) { - const fallbacks = border_image.getFallbacks(allocator, context.targets).slice(); - for (fallbacks) |fallback| { - // Match prefix of fallback. e.g. -webkit-linear-gradient - // can only be used in -webkit-border-image, not -moz-border-image. - // However, if border-image is unprefixed, gradients can still be. - var p = bun.bits.@"and"(VendorPrefix, fallback.source.getVendorPrefix(), prefix); - if (p.isEmpty()) { - p = prefix; - } - bun.handleOom(dest.append(allocator, css.Property{ .@"border-image" = .{ fallback, p } })); - } - } - } - - const p = bun.bits.@"and"(css.VendorPrefix, border_image.source.getVendorPrefix(), prefix); - if (!p.isEmpty()) { - prefix = p; - } - - bun.handleOom(dest.append(allocator, Property{ .@"border-image" = .{ border_image, prefix } })); - bun.bits.insert(BorderImageProperty, &this.flushed_properties, BorderImageProperty.@"border-image"); - } else { - if (source) |*mut_source| { - if (!bun.bits.contains(BorderImageProperty, this.flushed_properties, BorderImageProperty.@"border-image-source")) { - for (mut_source.getFallbacks(allocator, context.targets).slice()) |fallback| { - bun.handleOom(dest.append(allocator, Property{ .@"border-image-source" = fallback })); - } - } - - bun.handleOom(dest.append(allocator, Property{ .@"border-image-source" = mut_source.* })); - bun.bits.insert(BorderImageProperty, &this.flushed_properties, BorderImageProperty.@"border-image-source"); - } - - if (slice) |s| { - bun.handleOom(dest.append(allocator, Property{ .@"border-image-slice" = s })); - bun.bits.insert(BorderImageProperty, &this.flushed_properties, BorderImageProperty.@"border-image-slice"); - } - - if (width) |w| { - bun.handleOom(dest.append(allocator, Property{ .@"border-image-width" = w })); - bun.bits.insert(BorderImageProperty, &this.flushed_properties, BorderImageProperty.@"border-image-width"); - } - - if (outset) |o| { - bun.handleOom(dest.append(allocator, Property{ .@"border-image-outset" = o })); - bun.bits.insert(BorderImageProperty, &this.flushed_properties, BorderImageProperty.@"border-image-outset"); - } - - if (repeat) |r| { - bun.handleOom(dest.append(allocator, Property{ .@"border-image-repeat" = r })); - bun.bits.insert(BorderImageProperty, &this.flushed_properties, BorderImageProperty.@"border-image-repeat"); - } - } - - this.vendor_prefix = VendorPrefix{}; - } -}; - -pub fn isBorderImageProperty(property_id: css.PropertyId) bool { - return switch (property_id) { - .@"border-image-source", .@"border-image-slice", .@"border-image-width", .@"border-image-outset", .@"border-image-repeat", .@"border-image" => true, - else => false, - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/border_radius.zig b/src/css/properties/border_radius.zig deleted file mode 100644 index 7454c1c4d211..000000000000 --- a/src/css/properties/border_radius.zig +++ /dev/null @@ -1,321 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const LengthPercentage = css.css_values.length.LengthPercentage; -const Size2D = css.css_values.size.Size2D; -const Rect = css.css_values.rect.Rect; -const Property = css.Property; -const VendorPrefix = css.VendorPrefix; -const PropertyIdTag = css.PropertyIdTag; - -/// A value for the [border-radius](https://www.w3.org/TR/css-backgrounds-3/#border-radius) property. -pub const BorderRadius = struct { - /// The x and y radius values for the top left corner. - top_left: Size2D(LengthPercentage), - /// The x and y radius values for the top right corner. - top_right: Size2D(LengthPercentage), - /// The x and y radius values for the bottom right corner. - bottom_right: Size2D(LengthPercentage), - /// The x and y radius values for the bottom left corner. - bottom_left: Size2D(LengthPercentage), - - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"border-radius", PropertyFieldMap); - - pub const PropertyFieldMap = .{ - .top_left = "border-top-left-radius", - .top_right = "border-top-right-radius", - .bottom_right = "border-bottom-right-radius", - .bottom_left = "border-bottom-left-radius", - }; - - pub const VendorPrefixMap = .{ - .top_left = true, - .top_right = true, - .bottom_right = true, - .bottom_left = true, - }; - - pub fn parse(input: *css.Parser) css.Result(BorderRadius) { - const widths = switch (Rect(LengthPercentage).parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const heights = if (input.tryParse(css.Parser.expectDelim, .{'/'}).isOk()) - switch (Rect(LengthPercentage).parse(input)) { - .result => |v| v, - .err => |e| { - widths.deinit(input.allocator()); - return .{ .err = e }; - }, - } - else - widths.deepClone(input.allocator()); - - return .{ - .result = BorderRadius{ - .top_left = Size2D(LengthPercentage){ .a = widths.top, .b = heights.top }, - .top_right = Size2D(LengthPercentage){ .a = widths.right, .b = heights.right }, - .bottom_right = Size2D(LengthPercentage){ .a = widths.bottom, .b = heights.bottom }, - .bottom_left = Size2D(LengthPercentage){ .a = widths.left, .b = heights.left }, - }, - }; - } - - pub fn toCss(this: *const BorderRadius, dest: *Printer) PrintErr!void { - const widths = Rect(*const LengthPercentage){ - .top = &this.top_left.a, - .right = &this.top_right.a, - .bottom = &this.bottom_right.a, - .left = &this.bottom_left.a, - }; - - const heights = Rect(*const LengthPercentage){ - .top = &this.top_left.b, - .right = &this.top_right.b, - .bottom = &this.bottom_right.b, - .left = &this.bottom_left.b, - }; - - try widths.toCss(dest); - - if (!widths.eql(&heights)) { - try dest.delim('/', true); - try heights.toCss(dest); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -pub const BorderRadiusHandler = struct { - top_left: ?struct { Size2D(LengthPercentage), css.VendorPrefix } = null, - top_right: ?struct { Size2D(LengthPercentage), css.VendorPrefix } = null, - bottom_right: ?struct { Size2D(LengthPercentage), css.VendorPrefix } = null, - bottom_left: ?struct { Size2D(LengthPercentage), css.VendorPrefix } = null, - start_start: ?css.Property = null, - start_end: ?css.Property = null, - end_end: ?css.Property = null, - end_start: ?css.Property = null, - category: css.PropertyCategory = .physical, - has_any: bool = false, - - pub fn handleProperty(this: *@This(), property: *const css.Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool { - switch (property.*) { - .@"border-top-left-radius" => |val| propertyHelper(this, dest, context, "top_left", &val[0], val[1]), - .@"border-top-right-radius" => |val| propertyHelper(this, dest, context, "top_right", &val[0], val[1]), - .@"border-bottom-right-radius" => |val| propertyHelper(this, dest, context, "bottom_right", &val[0], val[1]), - .@"border-bottom-left-radius" => |val| propertyHelper(this, dest, context, "bottom_left", &val[0], val[1]), - .@"border-start-start-radius" => logicalPropertyHelper(this, dest, context, "start_start", property), - .@"border-start-end-radius" => logicalPropertyHelper(this, dest, context, "start_end", property), - .@"border-end-end-radius" => logicalPropertyHelper(this, dest, context, "end_end", property), - .@"border-end-start-radius" => logicalPropertyHelper(this, dest, context, "end_start", property), - .@"border-radius" => |val| { - this.start_start = null; - this.start_end = null; - this.end_end = null; - this.end_start = null; - - maybeFlush(this, dest, context, "top_left", &val[0].top_left, val[1]); - maybeFlush(this, dest, context, "top_right", &val[0].top_right, val[1]); - maybeFlush(this, dest, context, "bottom_right", &val[0].bottom_right, val[1]); - maybeFlush(this, dest, context, "bottom_left", &val[0].bottom_left, val[1]); - - propertyHelper(this, dest, context, "top_left", &val[0].top_left, val[1]); - propertyHelper(this, dest, context, "top_right", &val[0].top_right, val[1]); - propertyHelper(this, dest, context, "bottom_right", &val[0].bottom_right, val[1]); - propertyHelper(this, dest, context, "bottom_left", &val[0].bottom_left, val[1]); - }, - .unparsed => |unparsed| { - if (isBorderRadiusProperty(unparsed.property_id)) { - // Even if we weren't able to parse the value (e.g. due to var() references), - // we can still add vendor prefixes to the property itself. - switch (unparsed.property_id) { - .@"border-start-start-radius" => logicalPropertyHelper(this, dest, context, "start_start", property), - .@"border-start-end-radius" => logicalPropertyHelper(this, dest, context, "start_end", property), - .@"border-end-end-radius" => logicalPropertyHelper(this, dest, context, "end_end", property), - .@"border-end-start-radius" => logicalPropertyHelper(this, dest, context, "end_start", property), - else => { - this.flush(dest, context); - bun.handleOom(dest.append(context.allocator, Property{ .unparsed = unparsed.getPrefixed(context.allocator, context.targets, css.prefixes.Feature.border_radius) })); - }, - } - } else return false; - }, - else => return false, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - } - - fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - - this.has_any = false; - - var top_left = bun.take(&this.top_left); - var top_right = bun.take(&this.top_right); - var bottom_right = bun.take(&this.bottom_right); - var bottom_left = bun.take(&this.bottom_left); - const start_start = bun.take(&this.start_start); - const start_end = bun.take(&this.start_end); - const end_end = bun.take(&this.end_end); - const end_start = bun.take(&this.end_start); - - if (top_left != null and top_right != null and bottom_right != null and bottom_left != null) { - const intersection = top_left.?[1].bitwiseAnd(top_right.?[1]).bitwiseAnd(bottom_right.?[1]).bitwiseAnd(bottom_left.?[1]); - if (!intersection.isEmpty()) { - const prefix = context.targets.prefixes(intersection, css.prefixes.Feature.border_radius); - dest.append(context.allocator, Property{ .@"border-radius" = .{ - BorderRadius{ - .top_left = top_left.?[0].deepClone(context.allocator), - .top_right = top_right.?[0].deepClone(context.allocator), - .bottom_right = bottom_right.?[0].deepClone(context.allocator), - .bottom_left = bottom_left.?[0].deepClone(context.allocator), - }, - prefix, - } }) catch |err| bun.handleOom(err); - bun.bits.remove(VendorPrefix, &top_left.?[1], intersection); - bun.bits.remove(VendorPrefix, &top_right.?[1], intersection); - bun.bits.remove(VendorPrefix, &bottom_right.?[1], intersection); - bun.bits.remove(VendorPrefix, &bottom_left.?[1], intersection); - } - } - - const logical_supported = !context.shouldCompileLogical(.logical_border_radius); - - singleProperty(dest, context, "border-top-left-radius", top_left); - singleProperty(dest, context, "border-top-right-radius", top_right); - singleProperty(dest, context, "border-bottom-right-radius", bottom_right); - singleProperty(dest, context, "border-bottom-left-radius", bottom_left); - - logicalProperty(dest, context, start_start, "border-top-left-radius", "border-top-right-radius", logical_supported); - logicalProperty(dest, context, start_end, "border-top-right-radius", "border-top-left-radius", logical_supported); - logicalProperty(dest, context, end_end, "border-bottom-right-radius", "border-bottom-left-radius", logical_supported); - logicalProperty(dest, context, end_start, "border-bottom-left-radius", "border-bottom-right-radius", logical_supported); - } - - fn singleProperty(d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, comptime prop: []const u8, val: ?struct { Size2D(LengthPercentage), css.VendorPrefix }) void { - if (val) |v| { - if (!v[1].isEmpty()) { - const prefix = ctx.targets.prefixes(v[1], css.prefixes.Feature.border_radius); - bun.handleOom(d.append(ctx.allocator, @unionInit(css.Property, prop, .{ v[0], prefix }))); - } - } - } - - fn logicalProperty(d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, val: ?css.Property, comptime ltr: []const u8, comptime rtl: []const u8, logical_supported: bool) void { - if (val) |v| { - if (logical_supported) { - bun.handleOom(d.append(ctx.allocator, v)); - } else { - const prefix = ctx.targets.prefixes(css.VendorPrefix{ .none = true }, css.prefixes.Feature.border_radius); - switch (v) { - .@"border-start-start-radius", - .@"border-start-end-radius", - .@"border-end-end-radius", - .@"border-end-start-radius", - => |radius| { - ctx.addLogicalRule( - ctx.allocator, - @unionInit(css.Property, ltr, .{ radius, prefix }), - @unionInit(css.Property, rtl, .{ radius, prefix }), - ); - }, - .unparsed => |unparsed| { - ctx.addLogicalRule( - ctx.allocator, - Property{ .unparsed = unparsed.withPropertyId(ctx.allocator, @unionInit(css.PropertyId, ltr, prefix)) }, - Property{ .unparsed = unparsed.withPropertyId(ctx.allocator, @unionInit(css.PropertyId, rtl, prefix)) }, - ); - }, - else => {}, - } - } - } - } - - fn maybeFlush(self: *BorderRadiusHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype, vp: css.VendorPrefix) void { - // If two vendor prefixes for the same property have different - // values, we need to flush what we have immediately to preserve order. - if (@field(self, prop)) |*existing| { - if (!existing.*[0].eql(val) and !bun.bits.contains(VendorPrefix, existing.*[1], vp)) { - self.flush(d, ctx); - } - } - - if (@field(self, prop) != null and ctx.targets.browsers != null and !css.generic.isCompatible(Size2D(LengthPercentage), val, ctx.targets.browsers.?)) { - self.flush(d, ctx); - } - } - - fn propertyHelper(self: *BorderRadiusHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, comptime prop: []const u8, val: *const Size2D(LengthPercentage), vp: css.VendorPrefix) void { - if (self.category != .physical) { - self.flush(d, ctx); - } - - maybeFlush(self, d, ctx, prop, val, vp); - - // Otherwise, update the value and add the prefix. - if (@field(self, prop)) |*existing| { - existing.* = .{ val.deepClone(ctx.allocator), vp }; - } else { - @field(self, prop) = .{ val.deepClone(ctx.allocator), vp }; - self.has_any = true; - } - - self.category = .physical; - } - - fn logicalPropertyHelper(self: *BorderRadiusHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, comptime prop: []const u8, val: *const css.Property) void { - if (self.category != .logical) { - self.flush(d, ctx); - } - - @field(self, prop) = val.deepClone(ctx.allocator); - self.category = .logical; - self.has_any = true; - } -}; - -pub fn isBorderRadiusProperty(property_id: PropertyIdTag) bool { - if (isLogicalBorderRadiusProperty(property_id)) { - return true; - } - - return switch (property_id) { - .@"border-top-left-radius", - .@"border-top-right-radius", - .@"border-bottom-right-radius", - .@"border-bottom-left-radius", - .@"border-radius", - => true, - else => false, - }; -} - -pub fn isLogicalBorderRadiusProperty(property_id: PropertyIdTag) bool { - return switch (property_id) { - .@"border-start-start-radius", - .@"border-start-end-radius", - .@"border-end-end-radius", - .@"border-end-start-radius", - => true, - else => false, - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/box_shadow.zig b/src/css/properties/box_shadow.zig deleted file mode 100644 index d970a31738a3..000000000000 --- a/src/css/properties/box_shadow.zig +++ /dev/null @@ -1,259 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const CssColor = css.css_values.color.CssColor; -const Length = css.css_values.length.Length; - -const VendorPrefix = css.VendorPrefix; -const Property = css.Property; -const Feature = css.prefixes.Feature; - -/// A value for the [box-shadow](https://drafts.csswg.org/css-backgrounds/#box-shadow) property. -pub const BoxShadow = struct { - /// The color of the box shadow. - color: CssColor, - /// The x offset of the shadow. - x_offset: Length, - /// The y offset of the shadow. - y_offset: Length, - /// The blur radius of the shadow. - blur: Length, - /// The spread distance of the shadow. - spread: Length, - /// Whether the shadow is inset within the box. - inset: bool, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var color: ?CssColor = null; - const Lengths = struct { x: Length, y: Length, blur: Length, spread: Length }; - var lengths: ?Lengths = null; - var inset = false; - - while (true) { - if (!inset) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"inset"}).isOk()) { - inset = true; - continue; - } - } - - if (lengths == null) { - const value = input.tryParse(struct { - fn parse(p: *css.Parser) css.Result(Lengths) { - const horizontal = switch (Length.parse(p)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const vertical = switch (Length.parse(p)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const blur = p.tryParse(Length.parse, .{}).asValue() orelse Length.zero(); - const spread = p.tryParse(Length.parse, .{}).asValue() orelse Length.zero(); - return .{ .result = .{ .x = horizontal, .y = vertical, .blur = blur, .spread = spread } }; - } - }.parse, .{}); - - if (value.isOk()) { - lengths = value.result; - continue; - } - } - - if (color == null) { - if (input.tryParse(CssColor.parse, .{}).asValue()) |c| { - color = c; - continue; - } - } - - break; - } - - const final_lengths = lengths orelse return .{ .err = input.newError(.qualified_rule_invalid) }; - return .{ .result = BoxShadow{ - .color = color orelse CssColor{ .current_color = {} }, - .x_offset = final_lengths.x, - .y_offset = final_lengths.y, - .blur = final_lengths.blur, - .spread = final_lengths.spread, - .inset = inset, - } }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - if (this.inset) { - try dest.writeStr("inset "); - } - - try this.x_offset.toCss(dest); - try dest.writeChar(' '); - try this.y_offset.toCss(dest); - - if (!this.blur.eql(&Length.zero()) or !this.spread.eql(&Length.zero())) { - try dest.writeChar(' '); - try this.blur.toCss(dest); - - if (!this.spread.eql(&Length.zero())) { - try dest.writeChar(' '); - try this.spread.toCss(dest); - } - } - - if (!this.color.eql(&CssColor{ .current_color = {} })) { - try dest.writeChar(' '); - try this.color.toCss(dest); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return this.color.isCompatible(browsers) and - this.x_offset.isCompatible(browsers) and - this.y_offset.isCompatible(browsers) and - this.blur.isCompatible(browsers) and - this.spread.isCompatible(browsers); - } -}; - -pub const BoxShadowHandler = struct { - box_shadows: ?struct { SmallList(BoxShadow, 1), VendorPrefix } = null, - flushed: bool = false, - - pub fn handleProperty(this: *@This(), property: *const Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool { - switch (property.*) { - .@"box-shadow" => |*b| { - const box_shadows: *const SmallList(BoxShadow, 1) = &b.*[0]; - const prefix: VendorPrefix = b.*[1]; - if (this.box_shadows != null and context.targets.browsers != null and !box_shadows.isCompatible(context.targets.browsers.?)) { - this.flush(dest, context); - } - - if (this.box_shadows) |*bxs| { - const val: *SmallList(BoxShadow, 1) = &bxs.*[0]; - const prefixes: *VendorPrefix = &bxs.*[1]; - if (!val.eql(box_shadows) and !bun.bits.contains(VendorPrefix, prefixes.*, prefix)) { - this.flush(dest, context); - this.box_shadows = .{ - box_shadows.deepClone(context.allocator), - prefix, - }; - } else { - val.* = box_shadows.deepClone(context.allocator); - bun.bits.insert(VendorPrefix, prefixes, prefix); - } - } else { - this.box_shadows = .{ - box_shadows.deepClone(context.allocator), - prefix, - }; - } - }, - .unparsed => |unp| { - if (unp.property_id == .@"box-shadow") { - this.flush(dest, context); - - var unparsed = unp.deepClone(context.allocator); - context.addUnparsedFallbacks(&unparsed); - bun.handleOom(dest.append(context.allocator, .{ .unparsed = unparsed })); - this.flushed = true; - } else return false; - }, - else => return false, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - this.flushed = false; - } - - pub fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (this.box_shadows == null) return; - - const box_shadows: SmallList(BoxShadow, 1), const prefixes2: VendorPrefix = bun.take(&this.box_shadows) orelse { - this.flushed = true; - return; - }; - - if (!this.flushed) { - const ColorFallbackKind = css.ColorFallbackKind; - var prefixes = context.targets.prefixes(prefixes2, Feature.box_shadow); - var fallbacks = ColorFallbackKind{}; - for (box_shadows.slice()) |*shadow| { - bun.bits.insert(ColorFallbackKind, &fallbacks, shadow.color.getNecessaryFallbacks(context.targets)); - } - - if (fallbacks.rgb) { - var rgb = SmallList(BoxShadow, 1).initCapacity(context.allocator, box_shadows.len()); - rgb.setLen(box_shadows.len()); - for (box_shadows.slice(), rgb.slice_mut()) |*input, *output| { - output.color = input.color.toRGB(context.allocator) orelse input.color.deepClone(context.allocator); - const fields = std.meta.fields(BoxShadow); - inline for (fields) |field| { - if (comptime std.mem.eql(u8, field.name, "color")) continue; - @field(output, field.name) = css.generic.deepClone(field.type, &@field(input, field.name), context.allocator); - } - } - - bun.handleOom(dest.append(context.allocator, .{ .@"box-shadow" = .{ rgb, prefixes } })); - if (prefixes.none) { - prefixes = VendorPrefix.NONE; - } else { - // Only output RGB for prefixed property (e.g. -webkit-box-shadow) - return; - } - } - - if (fallbacks.p3) { - var p3 = SmallList(BoxShadow, 1).initCapacity(context.allocator, box_shadows.len()); - p3.setLen(box_shadows.len()); - for (box_shadows.slice(), p3.slice_mut()) |*input, *output| { - output.color = input.color.toP3(context.allocator) orelse input.color.deepClone(context.allocator); - const fields = std.meta.fields(BoxShadow); - inline for (fields) |field| { - if (comptime std.mem.eql(u8, field.name, "color")) continue; - @field(output, field.name) = css.generic.deepClone(field.type, &@field(input, field.name), context.allocator); - } - } - bun.handleOom(dest.append(context.allocator, .{ .@"box-shadow" = .{ p3, VendorPrefix.NONE } })); - } - - if (fallbacks.lab) { - var lab = SmallList(BoxShadow, 1).initCapacity(context.allocator, box_shadows.len()); - lab.setLen(box_shadows.len()); - for (box_shadows.slice(), lab.slice_mut()) |*input, *output| { - output.color = input.color.toLAB(context.allocator) orelse input.color.deepClone(context.allocator); - const fields = std.meta.fields(BoxShadow); - inline for (fields) |field| { - if (comptime std.mem.eql(u8, field.name, "color")) continue; - @field(output, field.name) = css.generic.deepClone(field.type, &@field(input, field.name), context.allocator); - } - } - bun.handleOom(dest.append(context.allocator, .{ .@"box-shadow" = .{ lab, VendorPrefix.NONE } })); - } else { - bun.handleOom(dest.append(context.allocator, .{ .@"box-shadow" = .{ box_shadows, prefixes } })); - } - } else { - bun.handleOom(dest.append(context.allocator, .{ .@"box-shadow" = .{ box_shadows, prefixes2 } })); - } - - this.flushed = true; - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/contain.zig b/src/css/properties/contain.zig deleted file mode 100644 index 01715b0adef1..000000000000 --- a/src/css/properties/contain.zig +++ /dev/null @@ -1,22 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; - -const ContainerName = css.css_rules.container.ContainerName; - -const ContainerIdent = ContainerName; - -/// A value for the [container-type](https://drafts.csswg.org/css-contain-3/#container-type) property. -/// Establishes the element as a query container for the purpose of container queries. -pub const ContainerType = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [container-name](https://drafts.csswg.org/css-contain-3/#container-name) property. -pub const ContainerNameList = union(enum) { - /// The `none` keyword. - none, - /// A list of container names. - names: SmallList(ContainerIdent, 1), -}; - -/// A value for the [container](https://drafts.csswg.org/css-contain-3/#container-shorthand) shorthand property. -pub const Container = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); diff --git a/src/css/properties/css_modules.zig b/src/css/properties/css_modules.zig deleted file mode 100644 index eed558d5ef70..000000000000 --- a/src/css/properties/css_modules.zig +++ /dev/null @@ -1,138 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const CustomIdent = css.css_values.ident.CustomIdent; -const CustomIdentList = css.css_values.ident.CustomIdentList; -const CustomIdentFns = css.css_values.ident.CustomIdentFns; - -const Location = css.dependencies.Location; - -/// A value for the [composes](https://github.com/css-modules/css-modules/#dependencies) property from CSS modules. -pub const Composes = struct { - /// A list of class names to compose. - names: CustomIdentList, - /// Where the class names are composed from. - from: ?Specifier, - /// The source location of the `composes` property. - loc: bun.logger.Loc, - cssparser_loc: Location, - - pub fn parse(input: *css.Parser) css.Result(Composes) { - const loc = input.position(); - const loc2 = input.currentSourceLocation(); - var names: CustomIdentList = .{}; - while (input.tryParse(parseOneIdent, .{}).asValue()) |name| { - names.append(input.allocator(), name); - } - - if (names.len() == 0) return .{ .err = input.newCustomError(css.ParserError{ .invalid_declaration = {} }) }; - - const from = if (input.tryParse(css.Parser.expectIdentMatching, .{"from"}).isOk()) switch (Specifier.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } else null; - - return .{ - .result = Composes{ - .names = names, - .from = from, - .loc = bun.logger.Loc{ .start = @intCast(loc) }, - .cssparser_loc = Location.fromSourceLocation(loc2), - }, - }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - var first = true; - for (this.names.slice()) |name| { - if (first) { - first = false; - } else { - try dest.writeChar(' '); - } - try CustomIdentFns.toCss(&name, dest); - } - - if (this.from) |*from| { - try dest.writeStr(" from "); - try from.toCss(dest); - } - } - - fn parseOneIdent(input: *css.Parser) css.Result(CustomIdent) { - const name: CustomIdent = switch (CustomIdent.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (bun.strings.eqlCaseInsensitiveASCII(name.v, "from", true)) return .{ .err = input.newErrorForNextToken() }; - - return .{ .result = name }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// Defines where the class names referenced in the `composes` property are located. -/// -/// See [Composes](Composes). -pub const Specifier = union(enum) { - /// The referenced name is global. - global, - /// The referenced name comes from the specified file. - /// - /// Is an import record index - import_record_index: u32, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn parse(input: *css.Parser) css.Result(Specifier) { - const start_position = input.position(); - if (input.tryParse(css.Parser.expectUrlOrString, .{}).asValue()) |file| { - const import_record_index = switch (input.addImportRecord(file, start_position, .composes)) { - .result => |idx| idx, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = .{ - .import_record_index = import_record_index, - }, - }; - } - if (input.expectIdentMatching("global").asErr()) |e| return .{ .err = e }; - return .{ .result = .global }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return switch (this.*) { - .global => dest.writeStr("global"), - .import_record_index => |import_record_index| { - const url = try dest.getImportRecordUrl(import_record_index); - css.serializer.serializeString(url, dest) catch return dest.addFmtError(); - }, - // .source_index => {}, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/custom.zig b/src/css/properties/custom.zig deleted file mode 100644 index 92c60c7e8423..000000000000 --- a/src/css/properties/custom.zig +++ /dev/null @@ -1,1554 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const css_values = @import("../values/values.zig"); -pub const Printer = css.Printer; -pub const PrintErr = css.PrintErr; -const DashedIdent = css_values.ident.DashedIdent; -const DashedIdentFns = css_values.ident.DashedIdentFns; -const Ident = css_values.ident.Ident; -const IdentFns = css_values.ident.IdentFns; -pub const Result = css.Result; - -pub const CssColor = css.css_values.color.CssColor; -pub const RGBA = css.css_values.color.RGBA; -pub const SRGB = css.css_values.color.SRGB; -pub const HSL = css.css_values.color.HSL; -pub const CSSInteger = css.css_values.number.CSSInteger; -pub const CSSIntegerFns = css.css_values.number.CSSIntegerFns; -pub const CSSNumberFns = css.css_values.number.CSSNumberFns; -pub const Percentage = css.css_values.percentage.Percentage; -pub const Url = css.css_values.url.Url; -pub const DashedIdentReference = css.css_values.ident.DashedIdentReference; -pub const CustomIdent = css.css_values.ident.CustomIdent; -pub const CustomIdentFns = css.css_values.ident.CustomIdentFns; -pub const LengthValue = css.css_values.length.LengthValue; -pub const Angle = css.css_values.angle.Angle; -pub const Time = css.css_values.time.Time; -pub const Resolution = css.css_values.resolution.Resolution; -pub const AnimationName = css.css_properties.animation.AnimationName; -const ComponentParser = css.css_values.color.ComponentParser; - -const SupportsCondition = css.SupportsCondition; -const ColorFallbackKind = css.ColorFallbackKind; - -/// PERF: nullable optimization -pub const TokenList = struct { - v: std.ArrayListUnmanaged(TokenOrValue) = .{}, - - const This = @This(); - - pub fn deinit(this: *TokenList, allocator: Allocator) void { - for (this.v.items) |*token_or_value| { - token_or_value.deinit(allocator); - } - this.v.deinit(allocator); - } - - pub fn toCss( - this: *const This, - dest: *Printer, - is_custom_property: bool, - ) PrintErr!void { - if (!dest.minify and this.v.items.len == 1 and this.v.items[0].isWhitespace()) { - return; - } - - var has_whitespace = false; - for (this.v.items, 0..) |*token_or_value, i| { - switch (token_or_value.*) { - .color => |color| { - try color.toCss(dest); - has_whitespace = false; - }, - .unresolved_color => |color| { - try color.toCss(dest, is_custom_property); - has_whitespace = false; - }, - .url => |url| { - if (dest.dependencies != null and is_custom_property and !url.isAbsolute(try dest.getImportRecords())) { - return dest.newError(css.PrinterErrorKind{ - .ambiguous_url_in_custom_property = .{ .url = (try dest.getImportRecords()).at(url.import_record_idx).path.pretty }, - }, url.loc); - } - try url.toCss(dest); - has_whitespace = false; - }, - .@"var" => |@"var"| { - try @"var".toCss(dest, is_custom_property); - has_whitespace = try this.writeWhitespaceIfNeeded(i, dest); - }, - .env => |env| { - try env.toCss(dest, is_custom_property); - has_whitespace = try this.writeWhitespaceIfNeeded(i, dest); - }, - .function => |f| { - try f.toCss(dest, is_custom_property); - has_whitespace = try this.writeWhitespaceIfNeeded(i, dest); - }, - .length => |v| { - // Do not serialize unitless zero lengths in custom properties as it may break calc(). - const value, const unit = v.toUnitValue(); - try css.serializer.serializeDimension(value, unit, dest); - has_whitespace = false; - }, - .angle => |v| { - try v.toCss(dest); - has_whitespace = false; - }, - .time => |v| { - try v.toCss(dest); - has_whitespace = false; - }, - .resolution => |v| { - try v.toCss(dest); - has_whitespace = false; - }, - .dashed_ident => |v| { - try DashedIdentFns.toCss(&v, dest); - has_whitespace = false; - }, - .animation_name => |v| { - try v.toCss(dest); - has_whitespace = false; - }, - .token => |token| switch (token) { - .delim => |d| { - if (d == '+' or d == '-') { - try dest.writeChar(' '); - bun.assert(d <= 0x7F); - try dest.writeChar(@intCast(d)); - try dest.writeChar(' '); - } else { - const ws_before = !has_whitespace and (d == '/' or d == '*'); - bun.assert(d <= 0x7F); - try dest.delim(@intCast(d), ws_before); - } - has_whitespace = true; - }, - .comma => { - try dest.delim(',', false); - has_whitespace = true; - }, - .close_paren, .close_square, .close_curly => { - try token.toCss(dest); - has_whitespace = try this.writeWhitespaceIfNeeded(i, dest); - }, - .dimension => { - try css.serializer.serializeDimension(token.dimension.num.value, token.dimension.unit, dest); - has_whitespace = false; - }, - .number => |v| { - try css.css_values.number.CSSNumberFns.toCss(&v.value, dest); - has_whitespace = false; - }, - else => { - try token.toCss(dest); - has_whitespace = token == .whitespace; - }, - }, - } - } - } - - pub fn toCssRaw(this: *const TokenList, dest: *Printer) PrintErr!void { - for (this.v.items) |*token_or_value| { - if (token_or_value.* == .token) { - try token_or_value.token.toCss(dest); - } else { - return dest.addFmtError(); - } - } - } - - pub fn writeWhitespaceIfNeeded( - this: *const This, - i: usize, - dest: *Printer, - ) PrintErr!bool { - if (!dest.minify and - i != this.v.items.len - 1 and - !(this.v.items[i + 1] == .token and switch (this.v.items[i + 1].token) { - .comma, .close_paren => true, - else => false, - })) - { - // Whitespace is removed during parsing, so add it back if we aren't minifying. - try dest.writeChar(' '); - return true; - } else return false; - } - - pub fn parse(input: *css.Parser, options: *const css.ParserOptions, depth: usize) Result(TokenList) { - var tokens = ArrayList(TokenOrValue){}; // PERF: deinit on error - if (TokenListFns.parseInto(input, &tokens, options, depth).asErr()) |e| return .{ .err = e }; - - // Slice off leading and trailing whitespace if there are at least two tokens. - // If there is only one token, we must preserve it. e.g. `--foo: ;` is valid. - // PERF(alloc): this feels like a common codepath, idk how I feel about reallocating a new array just to slice off whitespace. - if (tokens.items.len >= 2) { - var slice = tokens.items[0..]; - if (tokens.items.len > 0 and tokens.items[0].isWhitespace()) { - slice = slice[1..]; - } - if (tokens.items.len > 0 and tokens.items[tokens.items.len - 1].isWhitespace()) { - slice = slice[0 .. slice.len - 1]; - } - var newlist = ArrayList(TokenOrValue){}; - newlist.insertSlice(input.allocator(), 0, slice) catch unreachable; - tokens.deinit(input.allocator()); - return .{ .result = TokenList{ .v = newlist } }; - } - - return .{ .result = .{ .v = tokens } }; - } - - pub fn parseWithOptions(input: *css.Parser, options: *const css.ParserOptions) Result(TokenList) { - return parse(input, options, 0); - } - - pub fn parseRaw( - input: *css.Parser, - tokens: *ArrayList(TokenOrValue), - options: *const css.ParserOptions, - depth: usize, - ) Result(void) { - if (depth > 500) { - return .{ .err = input.newCustomError(css.ParserError.maximum_nesting_depth) }; - } - - while (true) { - const state = input.state(); - const token = switch (input.nextIncludingWhitespace()) { - .result => |vv| vv, - .err => break, - }; - switch (token.*) { - .open_paren, .open_square, .open_curly => { - tokens.append( - input.allocator(), - .{ .token = token.* }, - ) catch unreachable; - const closing_delimiter: css.Token = switch (token.*) { - .open_paren => .close_paren, - .open_square => .close_square, - .open_curly => .close_curly, - else => unreachable, - }; - const Closure = struct { - options: *const css.ParserOptions, - depth: usize, - tokens: *ArrayList(TokenOrValue), - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(void) { - return TokenListFns.parseRaw( - input2, - this.tokens, - this.options, - this.depth + 1, - ); - } - }; - var closure = Closure{ - .options = options, - .depth = depth, - .tokens = tokens, - }; - if (input.parseNestedBlock(void, &closure, Closure.parsefn).asErr()) |e| return .{ .err = e }; - tokens.append( - input.allocator(), - .{ .token = closing_delimiter }, - ) catch unreachable; - }, - .function => { - tokens.append( - input.allocator(), - .{ .token = token.* }, - ) catch unreachable; - const Closure = struct { - options: *const css.ParserOptions, - depth: usize, - tokens: *ArrayList(TokenOrValue), - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(void) { - return TokenListFns.parseRaw( - input2, - this.tokens, - this.options, - this.depth + 1, - ); - } - }; - var closure = Closure{ - .options = options, - .depth = depth, - .tokens = tokens, - }; - if (input.parseNestedBlock(void, &closure, Closure.parsefn).asErr()) |e| return .{ .err = e }; - tokens.append( - input.allocator(), - .{ .token = .close_paren }, - ) catch unreachable; - }, - else => { - if (token.isParseError()) { - return .{ - .err = css.ParseError(css.ParserError){ - .kind = .{ .basic = .{ .unexpected_token = token.* } }, - .location = state.sourceLocation(), - }, - }; - } - tokens.append( - input.allocator(), - .{ .token = token.* }, - ) catch unreachable; - }, - } - } - - return .success; - } - - pub fn parseInto( - input: *css.Parser, - tokens: *ArrayList(TokenOrValue), - options: *const css.ParserOptions, - depth: usize, - ) Result(void) { - if (depth > 500) { - return .{ .err = input.newCustomError(css.ParserError.maximum_nesting_depth) }; - } - - var last_is_delim = false; - var last_is_whitespace = false; - - while (true) { - const state = input.state(); - const tok = switch (input.nextIncludingWhitespace()) { - .result => |vv| vv, - .err => break, - }; - switch (tok.*) { - .whitespace, .comment => { - // Skip whitespace if the last token was a delimiter. - // Otherwise, replace all whitespace and comments with a single space character. - if (!last_is_delim) { - tokens.append( - input.allocator(), - .{ .token = .{ .whitespace = " " } }, - ) catch unreachable; - last_is_whitespace = true; - } - continue; - }, - .function => |f| { - // Attempt to parse embedded color values into hex tokens. - if (tryParseColorToken(f, &state, input)) |color| { - tokens.append( - input.allocator(), - .{ .color = color }, - ) catch unreachable; - last_is_delim = false; - last_is_whitespace = false; - } else if (input.tryParse(UnresolvedColor.parse, .{ f, options }).asValue()) |color| { - tokens.append( - input.allocator(), - .{ .unresolved_color = color }, - ) catch unreachable; - last_is_delim = false; - last_is_whitespace = false; - } else if (bun.strings.eql(f, "url")) { - input.reset(&state); - tokens.append( - input.allocator(), - .{ .url = switch (Url.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - ) catch unreachable; - last_is_delim = false; - last_is_whitespace = false; - } else if (bun.strings.eql(f, "var")) { - const Closure = struct { - options: *const css.ParserOptions, - depth: usize, - tokens: *ArrayList(TokenOrValue), - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(TokenOrValue) { - const thevar = switch (Variable.parse(input2, this.options, this.depth + 1)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = TokenOrValue{ .@"var" = thevar } }; - } - }; - var closure = Closure{ - .options = options, - .depth = depth, - .tokens = tokens, - }; - const @"var" = switch (input.parseNestedBlock(TokenOrValue, &closure, Closure.parsefn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - tokens.append( - input.allocator(), - @"var", - ) catch unreachable; - last_is_delim = true; - last_is_whitespace = false; - } else if (bun.strings.eql(f, "env")) { - const Closure = struct { - options: *const css.ParserOptions, - depth: usize, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(TokenOrValue) { - const env = switch (EnvironmentVariable.parseNested(input2, this.options, this.depth + 1)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = TokenOrValue{ .env = env } }; - } - }; - var closure = Closure{ - .options = options, - .depth = depth, - }; - const env = switch (input.parseNestedBlock(TokenOrValue, &closure, Closure.parsefn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - tokens.append( - input.allocator(), - env, - ) catch unreachable; - last_is_delim = true; - last_is_whitespace = false; - } else { - const Closure = struct { - options: *const css.ParserOptions, - depth: usize, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(TokenList) { - const args = switch (TokenListFns.parse(input2, this.options, this.depth + 1)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = args }; - } - }; - var closure = Closure{ - .options = options, - .depth = depth, - }; - const arguments = switch (input.parseNestedBlock(TokenList, &closure, Closure.parsefn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - tokens.append( - input.allocator(), - .{ - .function = .{ - .name = .{ .v = f }, - .arguments = arguments, - }, - }, - ) catch unreachable; - last_is_delim = true; // Whitespace is not required after any of these chars. - last_is_whitespace = false; - } - continue; - }, - .unrestrictedhash, .idhash => { - const h = switch (tok.*) { - .unrestrictedhash => |h| h, - .idhash => |h| h, - else => unreachable, - }; - brk: { - const r, const g, const b, const a = css.color.parseHashColor(h) orelse { - tokens.append( - input.allocator(), - .{ .token = .{ .unrestrictedhash = h } }, - ) catch unreachable; - break :brk; - }; - tokens.append( - input.allocator(), - .{ - .color = CssColor{ .rgba = RGBA.new(r, g, b, a) }, - }, - ) catch unreachable; - } - last_is_delim = false; - last_is_whitespace = false; - continue; - }, - .unquoted_url => { - input.reset(&state); - tokens.append( - input.allocator(), - .{ .url = switch (Url.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - ) catch unreachable; - last_is_delim = false; - last_is_whitespace = false; - continue; - }, - .ident => |name| { - if (bun.strings.startsWith(name, "--")) { - tokens.append(input.allocator(), .{ .dashed_ident = .{ .v = name } }) catch unreachable; - last_is_delim = false; - last_is_whitespace = false; - continue; - } - }, - .open_paren, .open_square, .open_curly => { - tokens.append( - input.allocator(), - .{ .token = tok.* }, - ) catch unreachable; - const closing_delimiter: css.Token = switch (tok.*) { - .open_paren => .close_paren, - .open_square => .close_square, - .open_curly => .close_curly, - else => unreachable, - }; - const Closure = struct { - options: *const css.ParserOptions, - depth: usize, - tokens: *ArrayList(TokenOrValue), - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(void) { - return TokenListFns.parseInto( - input2, - this.tokens, - this.options, - this.depth + 1, - ); - } - }; - var closure = Closure{ - .options = options, - .depth = depth, - .tokens = tokens, - }; - if (input.parseNestedBlock(void, &closure, Closure.parsefn).asErr()) |e| return .{ .err = e }; - tokens.append( - input.allocator(), - .{ .token = closing_delimiter }, - ) catch unreachable; - last_is_delim = true; // Whitespace is not required after any of these chars. - last_is_whitespace = false; - continue; - }, - .dimension => { - const value = if (LengthValue.tryFromToken(tok).asValue()) |length| - TokenOrValue{ .length = length } - else if (Angle.tryFromToken(tok).asValue()) |angle| - TokenOrValue{ .angle = angle } - else if (Time.tryFromToken(tok).asValue()) |time| - TokenOrValue{ .time = time } - else if (Resolution.tryFromToken(tok).asValue()) |resolution| - TokenOrValue{ .resolution = resolution } - else - TokenOrValue{ .token = tok.* }; - - tokens.append( - input.allocator(), - value, - ) catch unreachable; - - last_is_delim = false; - last_is_whitespace = false; - continue; - }, - else => {}, - } - - if (tok.isParseError()) { - return .{ - .err = .{ - .kind = .{ .basic = .{ .unexpected_token = tok.* } }, - .location = state.sourceLocation(), - }, - }; - } - last_is_delim = switch (tok.*) { - .delim, .comma => true, - else => false, - }; - - // If this is a delimiter, and the last token was whitespace, - // replace the whitespace with the delimiter since both are not required. - if (last_is_delim and last_is_whitespace) { - const last = &tokens.items[tokens.items.len - 1]; - last.* = .{ .token = tok.* }; - } else { - tokens.append( - input.allocator(), - .{ .token = tok.* }, - ) catch unreachable; - } - - last_is_whitespace = false; - } - - return .success; - } - - pub fn getFallback(this: *const TokenList, allocator: Allocator, kind: ColorFallbackKind) @This() { - var tokens = TokenList{}; - bun.handleOom(tokens.v.ensureTotalCapacity(allocator, this.v.items.len)); - tokens.v.items.len = this.v.items.len; - for (this.v.items, tokens.v.items[0..this.v.items.len]) |*old, *new| { - new.* = switch (old.*) { - .color => |*color| TokenOrValue{ .color = color.getFallback(allocator, kind) }, - .function => |*f| TokenOrValue{ .function = f.getFallback(allocator, kind) }, - .@"var" => |*v| TokenOrValue{ .@"var" = v.getFallback(allocator, kind) }, - .env => |*e| TokenOrValue{ .env = e.getFallback(allocator, kind) }, - else => old.deepClone(allocator), - }; - } - tokens.v.items.len = this.v.items.len; - return tokens; - } - - pub const Fallbacks = struct { SupportsCondition, TokenList }; - pub fn getFallbacks(this: *const TokenList, allocator: Allocator, targets: css.targets.Targets) css.SmallList(Fallbacks, 2) { - // Get the full list of possible fallbacks, and remove the lowest one, which will replace - // the original declaration. The remaining fallbacks need to be added as @supports rules. - var fallbacks = this.getNecessaryFallbacks(targets); - const lowest_fallback = fallbacks.lowest(); - bun.bits.remove(ColorFallbackKind, &fallbacks, lowest_fallback); - - var res = css.SmallList(Fallbacks, 2){}; - if (fallbacks.p3) { - res.appendAssumeCapacity(.{ - ColorFallbackKind.P3.supportsCondition(), - this.getFallback(allocator, ColorFallbackKind.P3), - }); - } - - if (fallbacks.lab) { - res.appendAssumeCapacity(.{ - ColorFallbackKind.LAB.supportsCondition(), - this.getFallback(allocator, ColorFallbackKind.LAB), - }); - } - - if (!lowest_fallback.isEmpty()) { - for (this.v.items) |*token_or_value| { - switch (token_or_value.*) { - .color => |*color| { - color.* = color.getFallback(allocator, lowest_fallback); - }, - .function => |*f| { - f.* = f.getFallback(allocator, lowest_fallback); - }, - .@"var" => |*v| { - if (v.fallback) |*fallback| { - fallback.* = fallback.getFallback(allocator, lowest_fallback); - } - }, - .env => |*v| { - if (v.fallback) |*fallback| { - fallback.* = fallback.getFallback(allocator, lowest_fallback); - } - }, - else => {}, - } - } - } - - return res; - } - - pub fn getNecessaryFallbacks(this: *const TokenList, targets: css.targets.Targets) ColorFallbackKind { - var fallbacks = ColorFallbackKind{}; - for (this.v.items) |*token_or_value| { - switch (token_or_value.*) { - .color => |*color| { - bun.bits.insert(ColorFallbackKind, &fallbacks, color.getPossibleFallbacks(targets)); - }, - .function => |*f| { - bun.bits.insert(ColorFallbackKind, &fallbacks, f.arguments.getNecessaryFallbacks(targets)); - }, - .@"var" => |*v| { - if (v.fallback) |*fallback| { - bun.bits.insert(ColorFallbackKind, &fallbacks, fallback.getNecessaryFallbacks(targets)); - } - }, - .env => |*v| { - if (v.fallback) |*fallback| { - bun.bits.insert(ColorFallbackKind, &fallbacks, fallback.getNecessaryFallbacks(targets)); - } - }, - else => {}, - } - } - - return fallbacks; - } - - pub fn eql(lhs: *const TokenList, rhs: *const TokenList) bool { - return css.generic.eqlList(TokenOrValue, &lhs.v, &rhs.v); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const TokenList, allocator: Allocator) TokenList { - return .{ - .v = css.deepClone(TokenOrValue, allocator, &this.v), - }; - } -}; -pub const TokenListFns = TokenList; - -/// A color value with an unresolved alpha value (e.g. a variable). -/// These can be converted from the modern slash syntax to older comma syntax. -/// This can only be done when the only unresolved component is the alpha -/// since variables can resolve to multiple tokens. -pub const UnresolvedColor = union(enum) { - /// An rgb() color. - RGB: struct { - /// The red component. - r: f32, - /// The green component. - g: f32, - /// The blue component. - b: f32, - /// The unresolved alpha component. - alpha: TokenList, - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - pub fn __generateHash() void {} - }, - /// An hsl() color. - HSL: struct { - /// The hue component. - h: f32, - /// The saturation component. - s: f32, - /// The lightness component. - l: f32, - /// The unresolved alpha component. - alpha: TokenList, - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - pub fn __generateHash() void {} - }, - /// The light-dark() function. - light_dark: struct { - /// The light value. - light: TokenList, - /// The dark value. - dark: TokenList, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn __generateHash() void {} - }, - const This = @This(); - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const This, allocator: Allocator) This { - return switch (this.*) { - .RGB => |*rgb| .{ .RGB = .{ .r = rgb.r, .g = rgb.g, .b = rgb.b, .alpha = rgb.alpha.deepClone(allocator) } }, - .HSL => |*hsl| .{ .HSL = .{ .h = hsl.h, .s = hsl.s, .l = hsl.l, .alpha = hsl.alpha.deepClone(allocator) } }, - .light_dark => |*light_dark| .{ - .light_dark = .{ - .light = light_dark.light.deepClone(allocator), - .dark = light_dark.dark.deepClone(allocator), - }, - }, - }; - } - - pub fn deinit(this: *This, allocator: Allocator) void { - return switch (this.*) { - .RGB => |*rgb| rgb.alpha.deinit(allocator), - .HSL => |*hsl| hsl.alpha.deinit(allocator), - .light_dark => |*light_dark| { - light_dark.light.deinit(allocator); - light_dark.dark.deinit(allocator); - }, - }; - } - - pub fn toCss( - this: *const This, - dest: *Printer, - is_custom_property: bool, - ) PrintErr!void { - const Helper = struct { - pub fn conv(c: f32) i32 { - return bun.intFromFloat(i32, bun.clamp(@round(c * 255.0), 0.0, 255.0)); - } - }; - - switch (this.*) { - .RGB => |rgb| { - if (dest.targets.shouldCompileSame(.space_separated_color_notation)) { - try dest.writeStr("rgba("); - try css.to_css.integer(i32, Helper.conv(rgb.r), dest); - try dest.delim(',', false); - try css.to_css.integer(i32, Helper.conv(rgb.g), dest); - try dest.delim(',', false); - try css.to_css.integer(i32, Helper.conv(rgb.b), dest); - try rgb.alpha.toCss(dest, is_custom_property); - try dest.writeChar(')'); - return; - } - - try dest.writeStr("rgb("); - try css.to_css.integer(i32, Helper.conv(rgb.r), dest); - try dest.writeChar(' '); - try css.to_css.integer(i32, Helper.conv(rgb.g), dest); - try dest.writeChar(' '); - try css.to_css.integer(i32, Helper.conv(rgb.b), dest); - try dest.delim('/', true); - try rgb.alpha.toCss(dest, is_custom_property); - try dest.writeChar(')'); - }, - .HSL => |hsl| { - if (dest.targets.shouldCompileSame(.space_separated_color_notation)) { - try dest.writeStr("hsla("); - try CSSNumberFns.toCss(&hsl.h, dest); - try dest.delim(',', false); - try (Percentage{ .v = hsl.s }).toCss(dest); - try dest.delim(',', false); - try (Percentage{ .v = hsl.l }).toCss(dest); - try dest.delim(',', false); - try hsl.alpha.toCss(dest, is_custom_property); - try dest.writeChar(')'); - return; - } - - try dest.writeStr("hsl("); - try CSSNumberFns.toCss(&hsl.h, dest); - try dest.writeChar(' '); - try (Percentage{ .v = hsl.s }).toCss(dest); - try dest.writeChar(' '); - try (Percentage{ .v = hsl.l }).toCss(dest); - try dest.delim('/', true); - try hsl.alpha.toCss(dest, is_custom_property); - try dest.writeChar(')'); - return; - }, - .light_dark => |*ld| { - const light: *const TokenList = &ld.light; - const dark: *const TokenList = &ld.dark; - - if (!dest.targets.isCompatible(.light_dark)) { - try dest.writeStr("var(--buncss-light"); - try dest.delim(',', false); - try light.toCss(dest, is_custom_property); - try dest.writeChar(')'); - try dest.whitespace(); - try dest.writeStr("var(--buncss-dark"); - try dest.delim(',', false); - try dark.toCss(dest, is_custom_property); - return dest.writeChar(')'); - } - - try dest.writeStr("light-dark("); - try light.toCss(dest, is_custom_property); - try dest.delim(',', false); - try dark.toCss(dest, is_custom_property); - try dest.writeChar(')'); - }, - } - } - - pub fn parse( - input: *css.Parser, - f: []const u8, - options: *const css.ParserOptions, - ) Result(UnresolvedColor) { - var parser = ComponentParser.new(false); - // css.todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "rgb")) { - const Closure = struct { - options: *const css.ParserOptions, - parser: *ComponentParser, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(UnresolvedColor) { - return this.parser.parseRelative(input2, SRGB, UnresolvedColor, @This().innerParseFn, .{this.options}); - } - pub fn innerParseFn(i: *css.Parser, p: *ComponentParser, opts: *const css.ParserOptions) Result(UnresolvedColor) { - const r, const g, const b, const is_legacy = switch (css.css_values.color.parseRGBComponents(i, p)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (is_legacy) { - return .{ .err = i.newCustomError(css.ParserError.invalid_value) }; - } - if (i.expectDelim('/').asErr()) |e| return .{ .err = e }; - const alpha = switch (TokenListFns.parse(i, opts, 0)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = UnresolvedColor{ - .RGB = .{ - .r = r, - .g = g, - .b = b, - .alpha = alpha, - }, - } }; - } - }; - var closure = Closure{ - .options = options, - .parser = &parser, - }; - return input.parseNestedBlock(UnresolvedColor, &closure, Closure.parsefn); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "hsl")) { - const Closure = struct { - options: *const css.ParserOptions, - parser: *ComponentParser, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(UnresolvedColor) { - return this.parser.parseRelative(input2, HSL, UnresolvedColor, @This().innerParseFn, .{this.options}); - } - pub fn innerParseFn(i: *css.Parser, p: *ComponentParser, opts: *const css.ParserOptions) Result(UnresolvedColor) { - const h, const s, const l, const is_legacy = switch (css.css_values.color.parseHSLHWBComponents(HSL, i, p, false)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (is_legacy) { - return .{ .err = i.newCustomError(css.ParserError.invalid_value) }; - } - if (i.expectDelim('/').asErr()) |e| return .{ .err = e }; - const alpha = switch (TokenListFns.parse(i, opts, 0)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = UnresolvedColor{ - .HSL = .{ - .h = h, - .s = s, - .l = l, - .alpha = alpha, - }, - } }; - } - }; - var closure = Closure{ - .options = options, - .parser = &parser, - }; - return input.parseNestedBlock(UnresolvedColor, &closure, Closure.parsefn); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "light-dark")) { - const Closure = struct { - options: *const css.ParserOptions, - parser: *ComponentParser, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(UnresolvedColor) { - // errdefer doesn't fire on `return .{ .err = ... }` — Result(T) is a - // tagged union, not an error union. Clean up `light` inline. - var light = switch (input2.parseUntilBefore(css.Delimiters{ .comma = true }, TokenList, this, @This().parsefn2)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input2.expectComma().asErr()) |e| { - light.deinit(input2.allocator()); - return .{ .err = e }; - } - const dark = switch (TokenListFns.parse(input2, this.options, 0)) { - .result => |vv| vv, - .err => |e| { - light.deinit(input2.allocator()); - return .{ .err = e }; - }, - }; - return .{ .result = UnresolvedColor{ - .light_dark = .{ - .light = light, - .dark = dark, - }, - } }; - } - - pub fn parsefn2(this: *@This(), input2: *css.Parser) Result(TokenList) { - return TokenListFns.parse(input2, this.options, 1); - } - }; - var closure = Closure{ - .options = options, - .parser = &parser, - }; - return input.parseNestedBlock(UnresolvedColor, &closure, Closure.parsefn); - } else { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - } - - pub fn lightDarkOwned(allocator: Allocator, light: UnresolvedColor, dark: UnresolvedColor) UnresolvedColor { - var lightlist = bun.handleOom(ArrayList(TokenOrValue).initCapacity(allocator, 1)); - bun.handleOom(lightlist.append(allocator, TokenOrValue{ .unresolved_color = light })); - var darklist = bun.handleOom(ArrayList(TokenOrValue).initCapacity(allocator, 1)); - bun.handleOom(darklist.append(allocator, TokenOrValue{ .unresolved_color = dark })); - return UnresolvedColor{ - .light_dark = .{ - .light = css.TokenList{ .v = lightlist }, - .dark = css.TokenList{ .v = darklist }, - }, - }; - } -}; - -/// A CSS variable reference. -pub const Variable = struct { - /// The variable name. - name: DashedIdentReference, - /// A fallback value in case the variable is not defined. - fallback: ?TokenList, - - const This = @This(); - - pub fn deinit(this: *Variable, allocator: Allocator) void { - if (this.fallback) |*fallback| { - fallback.deinit(allocator); - } - } - - pub fn parse( - input: *css.Parser, - options: *const css.ParserOptions, - depth: usize, - ) Result(This) { - const name = switch (DashedIdentReference.parseWithOptions(input, options)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const fallback = if (input.tryParse(css.Parser.expectComma, .{}).isOk()) - switch (TokenList.parse(input, options, depth)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } - else - null; - - return .{ .result = Variable{ .name = name, .fallback = fallback } }; - } - - pub fn toCss( - this: *const This, - dest: *Printer, - is_custom_property: bool, - ) PrintErr!void { - try dest.writeStr("var("); - try this.name.toCss(dest); - if (this.fallback) |*fallback| { - try dest.delim(',', false); - try fallback.toCss(dest, is_custom_property); - } - return try dest.writeChar(')'); - } - - pub fn getFallback(this: *const Variable, allocator: Allocator, kind: ColorFallbackKind) @This() { - return Variable{ - .name = this.name, - .fallback = if (this.fallback) |*fallback| fallback.getFallback(allocator, kind) else null, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const Variable, allocator: Allocator) Variable { - return .{ - .name = this.name, - .fallback = if (this.fallback) |*fallback| fallback.deepClone(allocator) else null, - }; - } -}; - -/// A CSS environment variable reference. -pub const EnvironmentVariable = struct { - /// The environment variable name. - name: EnvironmentVariableName, - /// Optional indices into the dimensions of the environment variable. - /// TODO(zack): this could totally be a smallvec, why isn't it? - indices: ArrayList(CSSInteger) = ArrayList(CSSInteger){}, - /// A fallback value in case the variable is not defined. - fallback: ?TokenList, - - pub fn deinit(this: *EnvironmentVariable, allocator: Allocator) void { - this.indices.deinit(allocator); - if (this.fallback) |*fallback| { - fallback.deinit(allocator); - } - } - - pub fn parse(input: *css.Parser, options: *const css.ParserOptions, depth: usize) Result(EnvironmentVariable) { - if (input.expectFunctionMatching("env").asErr()) |e| return .{ .err = e }; - const Closure = struct { - options: *const css.ParserOptions, - depth: usize, - pub fn parsefn(this: *@This(), i: *css.Parser) Result(EnvironmentVariable) { - return EnvironmentVariable.parseNested(i, this.options, this.depth); - } - }; - var closure = Closure{ - .options = options, - .depth = depth, - }; - return input.parseNestedBlock(EnvironmentVariable, &closure, Closure.parsefn); - } - - pub fn parseNested(input: *css.Parser, options: *const css.ParserOptions, depth: usize) Result(EnvironmentVariable) { - const name = switch (EnvironmentVariableName.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - var indices = ArrayList(i32){}; - while (switch (input.tryParse(CSSIntegerFns.parse, .{})) { - .result => |v| v, - .err => null, - }) |idx| { - indices.append( - input.allocator(), - idx, - ) catch unreachable; - } - - const fallback = if (input.tryParse(css.Parser.expectComma, .{}).isOk()) - switch (TokenListFns.parse(input, options, depth + 1)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } - else - null; - - return .{ .result = EnvironmentVariable{ - .name = name, - .indices = indices, - .fallback = fallback, - } }; - } - - pub fn toCss( - this: *const EnvironmentVariable, - dest: *Printer, - is_custom_property: bool, - ) PrintErr!void { - try dest.writeStr("env("); - try this.name.toCss(dest); - - for (this.indices.items) |index| { - try dest.writeChar(' '); - try css.to_css.integer(i32, index, dest); - } - - if (this.fallback) |*fallback| { - try dest.delim(',', false); - try fallback.toCss(dest, is_custom_property); - } - - return try dest.writeChar(')'); - } - - pub fn getFallback(this: *const EnvironmentVariable, allocator: Allocator, kind: ColorFallbackKind) @This() { - return EnvironmentVariable{ - .name = this.name, - .indices = bun.handleOom(this.indices.clone(allocator)), - .fallback = if (this.fallback) |*fallback| fallback.getFallback(allocator, kind) else null, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const EnvironmentVariable, allocator: Allocator) EnvironmentVariable { - return .{ - .name = this.name, - .indices = bun.handleOom(this.indices.clone(allocator)), - .fallback = if (this.fallback) |*fallback| fallback.deepClone(allocator) else null, - }; - } -}; - -/// A CSS environment variable name. -pub const EnvironmentVariableName = union(enum) { - /// A UA-defined environment variable. - ua: UAEnvironmentVariable, - /// A custom author-defined environment variable. - custom: DashedIdentReference, - /// An unknown environment variable. - unknown: CustomIdent, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn parse(input: *css.Parser) Result(EnvironmentVariableName) { - if (input.tryParse(UAEnvironmentVariable.parse, .{}).asValue()) |ua| { - return .{ .result = .{ .ua = ua } }; - } - - if (input.tryParse(DashedIdentReference.parseWithOptions, .{ - &css.ParserOptions.default( - input.allocator(), - null, - ), - }).asValue()) |dashed| { - return .{ .result = .{ .custom = dashed } }; - } - - const ident = switch (CustomIdentFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .unknown = ident } }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return switch (this.*) { - .ua => |ua| ua.toCss(dest), - .custom => |custom| custom.toCss(dest), - .unknown => |unknown| CustomIdentFns.toCss(&unknown, dest), - }; - } -}; - -/// A UA-defined environment variable name. -pub const UAEnvironmentVariable = enum { - /// The safe area inset from the top of the viewport. - @"safe-area-inset-top", - /// The safe area inset from the right of the viewport. - @"safe-area-inset-right", - /// The safe area inset from the bottom of the viewport. - @"safe-area-inset-bottom", - /// The safe area inset from the left of the viewport. - @"safe-area-inset-left", - /// The viewport segment width. - @"viewport-segment-width", - /// The viewport segment height. - @"viewport-segment-height", - /// The viewport segment top position. - @"viewport-segment-top", - /// The viewport segment left position. - @"viewport-segment-left", - /// The viewport segment bottom position. - @"viewport-segment-bottom", - /// The viewport segment right position. - @"viewport-segment-right", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A custom CSS function. -pub const Function = struct { - /// The function name. - name: Ident, - /// The function arguments. - arguments: TokenList, - - const This = @This(); - - pub fn deinit(this: *Function, allocator: Allocator) void { - this.arguments.deinit(allocator); - } - - pub fn toCss( - this: *const This, - dest: *Printer, - is_custom_property: bool, - ) PrintErr!void { - try IdentFns.toCss(&this.name, dest); - try dest.writeChar('('); - try this.arguments.toCss(dest, is_custom_property); - return try dest.writeChar(')'); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const Function, allocator: Allocator) Function { - return .{ - .name = this.name, - .arguments = this.arguments.deepClone(allocator), - }; - } - - pub fn getFallback(this: *const Function, allocator: Allocator, kind: ColorFallbackKind) @This() { - return Function{ - .name = this.name.deepClone(allocator), - .arguments = this.arguments.getFallback(allocator, kind), - }; - } -}; - -/// A raw CSS token, or a parsed value. -pub const TokenOrValue = union(enum) { - /// A token. - token: css.Token, - /// A parsed CSS color. - color: CssColor, - /// A color with unresolved components. - unresolved_color: UnresolvedColor, - /// A parsed CSS url. - url: Url, - /// A CSS variable reference. - @"var": Variable, - /// A CSS environment variable reference. - env: EnvironmentVariable, - /// A custom CSS function. - function: Function, - /// A length. - length: LengthValue, - /// An angle. - angle: Angle, - /// A time. - time: Time, - /// A resolution. - resolution: Resolution, - /// A dashed ident. - dashed_ident: DashedIdent, - /// An animation name. - animation_name: AnimationName, - - pub fn eql(lhs: *const TokenOrValue, rhs: *const TokenOrValue) bool { - return css.implementEql(TokenOrValue, lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const TokenOrValue, allocator: Allocator) TokenOrValue { - return switch (this.*) { - .token => this.*, - .color => |*color| .{ .color = color.deepClone(allocator) }, - .unresolved_color => |*color| .{ .unresolved_color = color.deepClone(allocator) }, - .url => this.*, - .@"var" => |*@"var"| .{ .@"var" = @"var".deepClone(allocator) }, - .env => |*env| .{ .env = env.deepClone(allocator) }, - .function => |*f| .{ .function = f.deepClone(allocator) }, - .length => this.*, - .angle => this.*, - .time => this.*, - .resolution => this.*, - .dashed_ident => this.*, - .animation_name => this.*, - }; - } - - pub fn deinit(this: *TokenOrValue, allocator: Allocator) void { - return switch (this.*) { - .token => {}, - .color => |*color| color.deinit(allocator), - .unresolved_color => |*color| color.deinit(allocator), - .url => {}, - .@"var" => |*@"var"| @"var".deinit(allocator), - .env => |*env| env.deinit(allocator), - .function => |*f| f.deinit(allocator), - .length => {}, - .angle => {}, - .time => {}, - .resolution => {}, - .dashed_ident => {}, - .animation_name => {}, - }; - } - - pub fn isWhitespace(self: *const TokenOrValue) bool { - switch (self.*) { - .token => |tok| return tok == .whitespace, - else => return false, - } - } -}; - -/// A known property with an unparsed value. -/// -/// This type is used when the value of a known property could not -/// be parsed, e.g. in the case css `var()` references are encountered. -/// In this case, the raw tokens are stored instead. -pub const UnparsedProperty = struct { - /// The id of the property. - property_id: css.PropertyId, - /// The property value, stored as a raw token list. - value: TokenList, - - pub fn parse(property_id: css.PropertyId, input: *css.Parser, options: *const css.ParserOptions) Result(UnparsedProperty) { - const Closure = struct { options: *const css.ParserOptions }; - const value = switch (input.parseUntilBefore(css.Delimiters{ .bang = true, .semicolon = true }, css.TokenList, &Closure{ .options = options }, struct { - pub fn parseFn(self: *const Closure, i: *css.Parser) Result(TokenList) { - return TokenList.parse(i, self.options, 0); - } - }.parseFn)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = .{ .property_id = property_id, .value = value } }; - } - - pub fn getPrefixed(this: *const @This(), allocator: Allocator, targets: css.Targets, feature: css.prefixes.Feature) UnparsedProperty { - var clone = this.deepClone(allocator); - const prefix = this.property_id.prefix(); - clone.property_id = clone.property_id.withPrefix(targets.prefixes(prefix.orNone(), feature)); - return clone; - } - - /// Returns a new UnparsedProperty with the same value and the given property id. - pub fn withPropertyId(this: *const @This(), allocator: Allocator, property_id: css.PropertyId) UnparsedProperty { - return UnparsedProperty{ .property_id = property_id, .value = this.value.deepClone(allocator) }; - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A CSS custom property, representing any unknown property. -pub const CustomProperty = struct { - /// The name of the property. - name: CustomPropertyName, - /// The property value, stored as a raw token list. - value: TokenList, - - pub fn parse(name: CustomPropertyName, input: *css.Parser, options: *const css.ParserOptions) Result(CustomProperty) { - const Closure = struct { - options: *const css.ParserOptions, - - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(TokenList) { - return TokenListFns.parse(input2, this.options, 0); - } - }; - - var closure = Closure{ - .options = options, - }; - - const value = switch (input.parseUntilBefore( - css.Delimiters{ - .bang = true, - .semicolon = true, - }, - TokenList, - &closure, - Closure.parsefn, - )) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = CustomProperty{ - .name = name, - .value = value, - } }; - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A CSS custom property name. -pub const CustomPropertyName = union(enum) { - /// An author-defined CSS custom property. - custom: DashedIdent, - /// An unknown CSS property. - unknown: Ident, - - pub fn toCss(this: *const CustomPropertyName, dest: *Printer) PrintErr!void { - return switch (this.*) { - .custom => |custom| try custom.toCss(dest), - .unknown => |unknown| css.serializer.serializeIdentifier(unknown.v, dest) catch return dest.addFmtError(), - }; - } - - pub fn fromStr(name: []const u8) CustomPropertyName { - if (bun.strings.startsWith(name, "--")) return .{ .custom = .{ .v = name } }; - return .{ .unknown = .{ .v = name } }; - } - - pub fn asStr(self: *const CustomPropertyName) []const u8 { - switch (self.*) { - .custom => |custom| return custom.v, - .unknown => |unknown| return unknown.v, - } - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -pub fn tryParseColorToken(f: []const u8, state: *const css.ParserState, input: *css.Parser) ?CssColor { - // css.todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "rgb") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "rgba") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "hsl") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "hsla") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "hwb") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "lab") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "lch") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "oklab") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "oklch") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "color") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "color-mix") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(f, "light-dark")) - { - const s = input.state(); - input.reset(state); - if (CssColor.parse(input).asValue()) |color| { - return color; - } - input.reset(&s); - } - - return null; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/display.zig b/src/css/properties/display.zig deleted file mode 100644 index 8de870409328..000000000000 --- a/src/css/properties/display.zig +++ /dev/null @@ -1,287 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -/// A value for the [display](https://drafts.csswg.org/css-display-3/#the-display-properties) property. -pub const Display = union(enum) { - /// A display keyword. - keyword: DisplayKeyword, - /// The inside and outside display values. - pair: DisplayPair, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [visibility](https://drafts.csswg.org/css-display-3/#visibility) property. -pub const Visibility = enum { - /// The element is visible. - visible, - /// The element is hidden. - hidden, - /// The element is collapsed. - collapse, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A `display` keyword. -/// -/// See [Display](Display). -pub const DisplayKeyword = enum { - none, - contents, - @"table-row-group", - @"table-header-group", - @"table-footer-group", - @"table-row", - @"table-cell", - @"table-column-group", - @"table-column", - @"table-caption", - @"ruby-base", - @"ruby-text", - @"ruby-base-container", - @"ruby-text-container", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A pair of inside and outside display values, as used in the `display` property. -/// -/// See [Display](Display). -pub const DisplayPair = struct { - /// The outside display value. - outside: DisplayOutside, - /// The inside display value. - inside: DisplayInside, - /// Whether this is a list item. - is_list_item: bool, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var list_item = false; - var outside: ?DisplayOutside = null; - var inside: ?DisplayInside = null; - - while (true) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"list-item"}).isOk()) { - list_item = true; - continue; - } - - if (outside == null) { - if (input.tryParse(DisplayOutside.parse, .{}).asValue()) |o| { - outside = o; - continue; - } - } - - if (inside == null) { - if (input.tryParse(DisplayInside.parse, .{}).asValue()) |i| { - inside = i; - continue; - } - } - - break; - } - - if (list_item or inside != null or outside != null) { - const final_inside: DisplayInside = inside orelse DisplayInside.flow; - const final_outside: DisplayOutside = outside orelse switch (final_inside) { - // "If is omitted, the element’s outside display type - // defaults to block — except for ruby, which defaults to inline." - // https://drafts.csswg.org/css-display/#inside-model - .ruby => .@"inline", - else => .block, - }; - - if (list_item and !(final_inside == .flow or final_inside == .flow_root)) { - return .{ .err = input.newCustomError(.invalid_declaration) }; - } - - return .{ .result = .{ - .outside = final_outside, - .inside = final_inside, - .is_list_item = list_item, - } }; - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - const displayIdentMap = bun.ComptimeStringMap(DisplayPair, .{ - .{ "inline-block", DisplayPair{ .outside = .@"inline", .inside = .flow_root, .is_list_item = false } }, - .{ "inline-table", DisplayPair{ .outside = .@"inline", .inside = .table, .is_list_item = false } }, - .{ "inline-flex", DisplayPair{ .outside = .@"inline", .inside = .{ .flex = css.VendorPrefix{ .none = true } }, .is_list_item = false } }, - .{ "-webkit-inline-flex", DisplayPair{ .outside = .@"inline", .inside = .{ .flex = css.VendorPrefix{ .webkit = true } }, .is_list_item = false } }, - .{ "-ms-inline-flexbox", DisplayPair{ .outside = .@"inline", .inside = .{ .flex = css.VendorPrefix{ .ms = true } }, .is_list_item = false } }, - .{ "-webkit-inline-box", DisplayPair{ .outside = .@"inline", .inside = .{ .box = css.VendorPrefix{ .webkit = true } }, .is_list_item = false } }, - .{ "-moz-inline-box", DisplayPair{ .outside = .@"inline", .inside = .{ .box = css.VendorPrefix{ .moz = true } }, .is_list_item = false } }, - .{ "inline-grid", DisplayPair{ .outside = .@"inline", .inside = .grid, .is_list_item = false } }, - }); - if (displayIdentMap.getASCIIICaseInsensitive(ident)) |pair| { - return .{ .result = pair }; - } - - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const DisplayPair, dest: *css.Printer) css.PrintErr!void { - if (this.outside == .@"inline" and this.inside == .flow_root and !this.is_list_item) { - return dest.writeStr("inline-block"); - } else if (this.outside == .@"inline" and this.inside == .table and !this.is_list_item) { - return dest.writeStr("inline-table"); - } else if (this.outside == .@"inline" and this.inside == .flex and !this.is_list_item) { - try this.inside.flex.toCss(dest); - if (this.inside.flex == css.VendorPrefix{ .ms = true }) { - return dest.writeStr("inline-flexbox"); - } else { - return dest.writeStr("inline-flex"); - } - } else if (this.outside == .@"inline" and this.inside == .box and !this.is_list_item) { - try this.inside.box.toCss(dest); - return dest.writeStr("inline-box"); - } else if (this.outside == .@"inline" and this.inside == .grid and !this.is_list_item) { - return dest.writeStr("inline-grid"); - } else { - const default_outside: DisplayOutside = switch (this.inside) { - .ruby => .@"inline", - else => .block, - }; - - var needs_space = false; - if (!this.outside.eql(&default_outside) or (this.inside.eql(&DisplayInside{ .flow = {} }) and !this.is_list_item)) { - try this.outside.toCss(dest); - needs_space = true; - } - - if (!this.inside.eql(&DisplayInside{ .flow = {} })) { - if (needs_space) { - try dest.writeChar(' '); - } - try this.inside.toCss(dest); - needs_space = true; - } - - if (this.is_list_item) { - if (needs_space) { - try dest.writeChar(' '); - } - try dest.writeStr("list-item"); - } - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A [``](https://drafts.csswg.org/css-display-3/#typedef-display-outside) value. -pub const DisplayOutside = enum { - block, - @"inline", - @"run-in", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A [``](https://drafts.csswg.org/css-display-3/#typedef-display-inside) value. -pub const DisplayInside = union(enum) { - flow, - flow_root, - table, - flex: css.VendorPrefix, - box: css.VendorPrefix, - grid, - ruby, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const displayInsideMap = bun.ComptimeStringMap(DisplayInside, .{ - .{ "flow", DisplayInside.flow }, - .{ "flow-root", DisplayInside.flow_root }, - .{ "table", DisplayInside.table }, - .{ "flex", DisplayInside{ .flex = css.VendorPrefix{ .none = true } } }, - .{ "-webkit-flex", DisplayInside{ .flex = css.VendorPrefix{ .webkit = true } } }, - .{ "-ms-flexbox", DisplayInside{ .flex = css.VendorPrefix{ .ms = true } } }, - .{ "-webkit-box", DisplayInside{ .box = css.VendorPrefix{ .webkit = true } } }, - .{ "-moz-box", DisplayInside{ .box = css.VendorPrefix{ .moz = true } } }, - .{ "grid", DisplayInside.grid }, - .{ "ruby", DisplayInside.ruby }, - }); - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (displayInsideMap.getASCIIICaseInsensitive(ident)) |value| { - return .{ .result = value }; - } - - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const DisplayInside, dest: *css.Printer) css.PrintErr!void { - switch (this.*) { - .flow => try dest.writeStr("flow"), - .flow_root => try dest.writeStr("flow-root"), - .table => try dest.writeStr("table"), - .flex => |prefix| { - try prefix.toCss(dest); - if (prefix == css.VendorPrefix{ .ms = true }) { - try dest.writeStr("flexbox"); - } else { - try dest.writeStr("flex"); - } - }, - .box => |prefix| { - try prefix.toCss(dest); - try dest.writeStr("box"); - }, - .grid => try dest.writeStr("grid"), - .ruby => try dest.writeStr("ruby"), - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/effects.zig b/src/css/properties/effects.zig deleted file mode 100644 index bd75fe7ab542..000000000000 --- a/src/css/properties/effects.zig +++ /dev/null @@ -1,56 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; - -const CssColor = css.css_values.color.CssColor; -const Length = css.css_values.length.LengthValue; -const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage; -const Angle = css.css_values.angle.Angle; -const Url = css.css_values.url.Url; - -/// A value for the [filter](https://drafts.fxtf.org/filter-effects-1/#FilterProperty) and -/// [backdrop-filter](https://drafts.fxtf.org/filter-effects-2/#BackdropFilterProperty) properties. -pub const FilterList = union(enum) { - /// The `none` keyword. - none, - /// A list of filter functions. - filters: SmallList(Filter, 1), -}; - -/// A [filter](https://drafts.fxtf.org/filter-effects-1/#filter-functions) function. -pub const Filter = union(enum) { - /// A `blur()` filter. - blur: Length, - /// A `brightness()` filter. - brightness: NumberOrPercentage, - /// A `contrast()` filter. - contrast: NumberOrPercentage, - /// A `grayscale()` filter. - grayscale: NumberOrPercentage, - /// A `hue-rotate()` filter. - hue_rotate: Angle, - /// An `invert()` filter. - invert: NumberOrPercentage, - /// An `opacity()` filter. - opacity: NumberOrPercentage, - /// A `saturate()` filter. - saturate: NumberOrPercentage, - /// A `sepia()` filter. - sepia: NumberOrPercentage, - /// A `drop-shadow()` filter. - drop_shadow: DropShadow, - /// A `url()` reference to an SVG filter. - url: Url, -}; - -/// A [`drop-shadow()`](https://drafts.fxtf.org/filter-effects-1/#funcdef-filter-drop-shadow) filter function. -pub const DropShadow = struct { - /// The color of the drop shadow. - color: CssColor, - /// The x offset of the drop shadow. - x_offset: Length, - /// The y offset of the drop shadow. - y_offset: Length, - /// The blur radius of the drop shadow. - blur: Length, -}; diff --git a/src/css/properties/flex.rs b/src/css/properties/flex.rs index 78d42b455e0b..fb635d65abe8 100644 --- a/src/css/properties/flex.rs +++ b/src/css/properties/flex.rs @@ -7,7 +7,6 @@ use css::css_properties::align::{AlignContent, AlignItems, AlignSelf, JustifyCon use css::css_values::length::{LengthPercentage, LengthPercentageOrAuto}; use css::css_values::number::{CSSInteger, CSSNumber, CSSNumberFns}; use css::prefixes::Feature as PrefixFeature; -use css::prefixes::is_flex_2009; use css::{PrintErr, Printer, VendorPrefix}; /// A value for the [flex-direction](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#propdef-flex-direction) property. @@ -718,7 +717,7 @@ impl FlexHandler { .targets .prefixes(VendorPrefix::NONE, PrefixFeature::FlexDirection); let mut prefixes_2009 = VendorPrefix::empty(); - if is_flex_2009(targets) { + if PrefixFeature::is_flex_2009(targets) { prefixes_2009.insert(VendorPrefix::WEBKIT); } if prefixes.contains(VendorPrefix::MOZ) { @@ -815,7 +814,7 @@ impl FlexHandler { // 2009 spec, implemented by webkit and firefox if let Some(targets) = &context.targets.browsers { let mut prefixes_2009 = VendorPrefix::empty(); - if is_flex_2009(targets) { + if PrefixFeature::is_flex_2009(targets) { prefixes_2009.insert(VendorPrefix::WEBKIT); } if prefix.contains(VendorPrefix::MOZ) { @@ -864,7 +863,7 @@ impl FlexHandler { .targets .prefixes(VendorPrefix::NONE, PrefixFeature::FlexGrow); let mut prefixes_2009 = VendorPrefix::empty(); - if is_flex_2009(targets) { + if PrefixFeature::is_flex_2009(targets) { prefixes_2009.insert(VendorPrefix::WEBKIT); } if prefixes.contains(VendorPrefix::MOZ) { diff --git a/src/css/properties/flex.zig b/src/css/properties/flex.zig deleted file mode 100644 index 7fdaf41ffd6f..000000000000 --- a/src/css/properties/flex.zig +++ /dev/null @@ -1,949 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const Property = css.Property; -const PropertyId = css.PropertyId; - -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const LengthPercentage = css.css_values.length.LengthPercentage; -const CSSNumber = css.css_values.number.CSSNumber; -const LengthPercentageOrAuto = css.css_values.length.LengthPercentageOrAuto; -const Length = css.css_values.length.LengthValue; -const CSSInteger = css.css_values.number.CSSInteger; - -const isFlex2009 = css.prefixes.Feature.isFlex2009; - -const VendorPrefix = css.VendorPrefix; - -/// A value for the [flex-direction](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#propdef-flex-direction) property. -/// A value for the [flex-direction](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#propdef-flex-direction) property. -pub const FlexDirection = enum { - /// Flex items are laid out in a row. - row, - /// Flex items are laid out in a row, and reversed. - @"row-reverse", - /// Flex items are laid out in a column. - column, - /// Flex items are laid out in a column, and reversed. - @"column-reverse", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() FlexDirection { - return .row; - } - - pub fn to2009(this: *const FlexDirection) struct { BoxOrient, BoxDirection } { - return switch (this.*) { - .row => .{ .horizontal, .normal }, - .column => .{ .vertical, .normal }, - .@"row-reverse" => .{ .horizontal, .reverse }, - .@"column-reverse" => .{ .vertical, .reverse }, - }; - } -}; - -/// A value for the [flex-wrap](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-wrap-property) property. -/// A value for the [flex-wrap](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-wrap-property) property. -pub const FlexWrap = enum { - /// The flex items do not wrap. - nowrap, - /// The flex items wrap. - wrap, - /// The flex items wrap, in reverse. - @"wrap-reverse", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() FlexWrap { - return .nowrap; - } - - pub fn fromStandard(this: *const FlexWrap) ?FlexWrap { - return this; - } -}; - -/// A value for the [flex-flow](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-flow-property) shorthand property. -pub const FlexFlow = struct { - /// The direction that flex items flow. - direction: FlexDirection, - /// How the flex items wrap. - wrap: FlexWrap, - - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"flex-flow", PropertyFieldMap); - - pub const PropertyFieldMap = .{ - .direction = css.PropertyIdTag.@"flex-direction", - .wrap = css.PropertyIdTag.@"flex-wrap", - }; - - pub const VendorPrefixMap = .{ - .direction = true, - .wrap = true, - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var direction: ?FlexDirection = null; - var wrap: ?FlexWrap = null; - - while (true) { - if (direction == null) { - if (input.tryParse(FlexDirection.parse, .{}).asValue()) |value| { - direction = value; - continue; - } - } - if (wrap == null) { - if (input.tryParse(FlexWrap.parse, .{}).asValue()) |value| { - wrap = value; - continue; - } - } - break; - } - - return .{ - .result = FlexFlow{ - .direction = direction orelse FlexDirection.row, - .wrap = wrap orelse FlexWrap.nowrap, - }, - }; - } - - pub fn toCss(this: *const FlexFlow, dest: *css.Printer) css.PrintErr!void { - var needs_space = false; - if (!this.direction.eql(&FlexDirection.default()) or this.wrap.eql(&FlexWrap.default())) { - try this.direction.toCss(dest); - needs_space = true; - } - - if (!this.wrap.eql(&FlexWrap.default())) { - if (needs_space) { - try dest.writeStr(" "); - } - try this.wrap.toCss(dest); - } - - return; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [flex](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-property) shorthand property. -/// A value for the [flex](https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119/#flex-property) shorthand property. -pub const Flex = struct { - /// The flex grow factor. - grow: CSSNumber, - /// The flex shrink factor. - shrink: CSSNumber, - /// The flex basis. - basis: LengthPercentageOrAuto, - - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.flex, PropertyFieldMap); - - pub const PropertyFieldMap = .{ - .grow = css.PropertyIdTag.@"flex-grow", - .shrink = css.PropertyIdTag.@"flex-shrink", - .basis = css.PropertyIdTag.@"flex-basis", - }; - - pub const VendorPrefixMap = .{ - .grow = true, - .shrink = true, - .basis = true, - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"none"}).isOk()) { - return .{ - .result = .{ - .grow = 0.0, - .shrink = 0.0, - .basis = LengthPercentageOrAuto.auto, - }, - }; - } - - var grow: ?CSSNumber = null; - var shrink: ?CSSNumber = null; - var basis: ?LengthPercentageOrAuto = null; - - while (true) { - if (grow == null) { - if (input.tryParse(CSSNumberFns.parse, .{}).asValue()) |value| { - grow = value; - shrink = input.tryParse(CSSNumberFns.parse, .{}).asValue(); - continue; - } - } - - if (basis == null) { - if (input.tryParse(LengthPercentageOrAuto.parse, .{}).asValue()) |value| { - basis = value; - continue; - } - } - - break; - } - - return .{ - .result = .{ - .grow = grow orelse 1.0, - .shrink = shrink orelse 1.0, - .basis = basis orelse LengthPercentageOrAuto{ .length = LengthPercentage{ .percentage = .{ .v = 0.0 } } }, - }, - }; - } - - pub fn toCss(this: *const Flex, dest: *css.Printer) css.PrintErr!void { - if (this.grow == 0.0 and this.shrink == 0.0 and this.basis == .auto) { - try dest.writeStr("none"); - return; - } - - const ZeroKind = enum { - NonZero, - Length, - Percentage, - }; - - // If the basis is unitless 0, we must write all three components to disambiguate. - // If the basis is 0%, we can omit the basis. - const basis_kind = switch (this.basis) { - .length => |lp| brk: { - if (lp == .dimension and lp.dimension.isZero()) break :brk ZeroKind.Length; - if (lp == .percentage and lp.percentage.isZero()) break :brk ZeroKind.Percentage; - break :brk ZeroKind.NonZero; - }, - else => ZeroKind.NonZero, - }; - - if (this.grow != 1.0 or this.shrink != 1.0 or basis_kind != .NonZero) { - try CSSNumberFns.toCss(&this.grow, dest); - if (this.shrink != 1.0 or basis_kind == .Length) { - try dest.writeStr(" "); - try CSSNumberFns.toCss(&this.shrink, dest); - } - } - - if (basis_kind != .Percentage) { - if (this.grow != 1.0 or this.shrink != 1.0 or basis_kind == .Length) { - try dest.writeStr(" "); - } - try this.basis.toCss(dest); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the legacy (prefixed) [box-orient](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#orientation) property. -/// Partially equivalent to `flex-direction` in the standard syntax. -/// A value for the legacy (prefixed) [box-orient](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#orientation) property. -/// Partially equivalent to `flex-direction` in the standard syntax. -pub const BoxOrient = enum { - /// Items are laid out horizontally. - horizontal, - /// Items are laid out vertically. - vertical, - /// Items are laid out along the inline axis, according to the writing direction. - @"inline-axis", - /// Items are laid out along the block axis, according to the writing direction. - @"block-axis", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the legacy (prefixed) [box-direction](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#displayorder) property. -/// Partially equivalent to the `flex-direction` property in the standard syntax. -pub const BoxDirection = enum { - /// Items flow in the natural direction. - normal, - /// Items flow in the reverse direction. - reverse, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -pub const FlexAlign = BoxAlign; - -/// A value for the legacy (prefixed) [box-align](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#alignment) property. -/// Equivalent to the `align-items` property in the standard syntax. -/// A value for the legacy (prefixed) [box-align](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#alignment) property. -/// Equivalent to the `align-items` property in the standard syntax. -pub const BoxAlign = enum { - /// Items are aligned to the start. - start, - /// Items are aligned to the end. - end, - /// Items are centered. - center, - /// Items are aligned to the baseline. - baseline, - /// Items are stretched. - stretch, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn fromStandard(@"align": *const css.css_properties.@"align".AlignItems) ?BoxAlign { - return switch (@"align".*) { - .self_position => |sp| if (sp.overflow == null) switch (sp.value) { - .start, .@"flex-start" => .start, - .end, .@"flex-end" => .end, - .center => .center, - else => null, - } else null, - .stretch => .stretch, - else => null, - }; - } -}; - -/// A value for the legacy (prefixed) [box-pack](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#packing) property. -/// Equivalent to the `justify-content` property in the standard syntax. -/// A value for the legacy (prefixed) [box-pack](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#packing) property. -/// Equivalent to the `justify-content` property in the standard syntax. -pub const BoxPack = enum { - /// Items are justified to the start. - start, - /// Items are justified to the end. - end, - /// Items are centered. - center, - /// Items are justified to the start and end. - justify, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn fromStandard(justify: *const css.css_properties.@"align".JustifyContent) ?BoxPack { - return switch (justify.*) { - .content_distribution => |cd| switch (cd) { - .@"space-between" => .justify, - else => null, - }, - .content_position => |cp| if (cp.overflow == null) switch (cp.value) { - .start, .@"flex-start" => .start, - .end, .@"flex-end" => .end, - .center => .center, - } else null, - else => null, - }; - } -}; - -/// A value for the legacy (prefixed) [box-lines](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#multiple) property. -/// Equivalent to the `flex-wrap` property in the standard syntax. -/// A value for the legacy (prefixed) [box-lines](https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/#multiple) property. -/// Equivalent to the `flex-wrap` property in the standard syntax. -pub const BoxLines = enum { - /// Items are laid out in a single line. - single, - /// Items may wrap into multiple lines. - multiple, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn fromStandard(wrap: *const FlexWrap) ?BoxLines { - return switch (wrap.*) { - .nowrap => .single, - .wrap => .multiple, - else => null, - }; - } -}; - -// Old flex (2012): https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/ -/// A value for the legacy (prefixed) [flex-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-pack) property. -/// Equivalent to the `justify-content` property in the standard syntax. -/// A value for the legacy (prefixed) [flex-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-pack) property. -/// Equivalent to the `justify-content` property in the standard syntax. -pub const FlexPack = enum { - /// Items are justified to the start. - start, - /// Items are justified to the end. - end, - /// Items are centered. - center, - /// Items are justified to the start and end. - justify, - /// Items are distributed evenly, with half size spaces on either end. - distribute, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn fromStandard(justify: *const css.css_properties.@"align".JustifyContent) ?FlexPack { - return switch (justify.*) { - .content_distribution => |cd| switch (cd) { - .@"space-between" => .justify, - .@"space-around" => .distribute, - else => null, - }, - .content_position => |cp| if (cp.overflow == null) switch (cp.value) { - .start, .@"flex-start" => .start, - .end, .@"flex-end" => .end, - .center => .center, - } else null, - else => null, - }; - } -}; - -/// A value for the legacy (prefixed) [flex-item-align](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align) property. -/// Equivalent to the `align-self` property in the standard syntax. -/// A value for the legacy (prefixed) [flex-item-align](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-align) property. -/// Equivalent to the `align-self` property in the standard syntax. -pub const FlexItemAlign = enum { - /// Equivalent to the value of `flex-align`. - auto, - /// The item is aligned to the start. - start, - /// The item is aligned to the end. - end, - /// The item is centered. - center, - /// The item is aligned to the baseline. - baseline, - /// The item is stretched. - stretch, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn fromStandard(justify: *const css.css_properties.@"align".AlignSelf) ?FlexItemAlign { - return switch (justify.*) { - .auto => .auto, - .stretch => .stretch, - .self_position => |sp| if (sp.overflow == null) switch (sp.value) { - .start, .@"flex-start" => .start, - .end, .@"flex-end" => .end, - .center => .center, - else => null, - } else null, - else => null, - }; - } -}; - -/// A value for the legacy (prefixed) [flex-line-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-line-pack) property. -/// Equivalent to the `align-content` property in the standard syntax. -/// A value for the legacy (prefixed) [flex-line-pack](https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/#flex-line-pack) property. -/// Equivalent to the `align-content` property in the standard syntax. -pub const FlexLinePack = enum { - /// Content is aligned to the start. - start, - /// Content is aligned to the end. - end, - /// Content is centered. - center, - /// Content is justified. - justify, - /// Content is distributed evenly, with half size spaces on either end. - distribute, - /// Content is stretched. - stretch, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn fromStandard(justify: *const css.css_properties.@"align".AlignContent) ?FlexLinePack { - return switch (justify.*) { - .content_distribution => |cd| switch (cd) { - .@"space-between" => .justify, - .@"space-around" => .distribute, - .stretch => .stretch, - else => null, - }, - .content_position => |cp| if (cp.overflow == null) switch (cp.value) { - .start, .@"flex-start" => .start, - .end, .@"flex-end" => .end, - .center => .center, - } else null, - else => null, - }; - } -}; - -pub const BoxOrdinalGroup = CSSInteger; - -// A handler for flex-related properties that manages both standard and legacy vendor prefixed values. -pub const FlexHandler = struct { - /// The flex-direction property value and vendor prefix - direction: ?struct { FlexDirection, VendorPrefix } = null, - /// The box-orient property value and vendor prefix (legacy) - box_orient: ?struct { BoxOrient, VendorPrefix } = null, - /// The box-direction property value and vendor prefix (legacy) - box_direction: ?struct { BoxDirection, VendorPrefix } = null, - /// The flex-wrap property value and vendor prefix - wrap: ?struct { FlexWrap, VendorPrefix } = null, - /// The box-lines property value and vendor prefix (legacy) - box_lines: ?struct { BoxLines, VendorPrefix } = null, - /// The flex-grow property value and vendor prefix - grow: ?struct { CSSNumber, VendorPrefix } = null, - /// The box-flex property value and vendor prefix (legacy) - box_flex: ?struct { CSSNumber, VendorPrefix } = null, - /// The flex-positive property value and vendor prefix (legacy) - flex_positive: ?struct { CSSNumber, VendorPrefix } = null, - /// The flex-shrink property value and vendor prefix - shrink: ?struct { CSSNumber, VendorPrefix } = null, - /// The flex-negative property value and vendor prefix (legacy) - flex_negative: ?struct { CSSNumber, VendorPrefix } = null, - /// The flex-basis property value and vendor prefix - basis: ?struct { LengthPercentageOrAuto, VendorPrefix } = null, - /// The preferred-size property value and vendor prefix (legacy) - preferred_size: ?struct { LengthPercentageOrAuto, VendorPrefix } = null, - /// The order property value and vendor prefix - order: ?struct { CSSInteger, VendorPrefix } = null, - /// The box-ordinal-group property value and vendor prefix (legacy) - box_ordinal_group: ?struct { BoxOrdinalGroup, VendorPrefix } = null, - /// The flex-order property value and vendor prefix (legacy) - flex_order: ?struct { CSSInteger, VendorPrefix } = null, - /// Whether any flex-related properties have been set - has_any: bool = false, - - pub fn handleProperty( - this: *@This(), - property: *const Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) bool { - const maybeFlush = struct { - fn maybeFlush( - self: *FlexHandler, - d: *css.DeclarationList, - ctx: *css.PropertyHandlerContext, - comptime prop: []const u8, - val: anytype, - vp: *const VendorPrefix, - ) void { - // If two vendor prefixes for the same property have different - // values, we need to flush what we have immediately to preserve order. - if (@field(self, prop)) |*field| { - if (!std.meta.eql(field[0], val.*) and !bun.bits.contains(css.VendorPrefix, field[1], vp.*)) { - self.flush(d, ctx); - } - } - } - }.maybeFlush; - - const propertyHelper = struct { - fn propertyHelper( - self: *FlexHandler, - ctx: *css.PropertyHandlerContext, - d: *css.DeclarationList, - comptime prop: []const u8, - val: anytype, - vp: *const VendorPrefix, - ) void { - maybeFlush(self, d, ctx, prop, val, vp); - - // Otherwise, update the value and add the prefix - if (@field(self, prop)) |*field| { - field[0] = css.generic.deepClone(@TypeOf(val.*), val, ctx.allocator); - bun.bits.insert(css.VendorPrefix, &field[1], vp.*); - } else { - @field(self, prop) = .{ - css.generic.deepClone(@TypeOf(val.*), val, ctx.allocator), - vp.*, - }; - self.has_any = true; - } - } - }.propertyHelper; - - switch (property.*) { - .@"flex-direction" => |*val| { - if (context.targets.browsers != null) { - this.box_direction = null; - this.box_orient = null; - } - propertyHelper(this, context, dest, "direction", &val[0], &val[1]); - }, - .@"box-orient" => |*val| propertyHelper(this, context, dest, "box_orient", &val[0], &val[1]), - .@"box-direction" => |*val| propertyHelper(this, context, dest, "box_direction", &val[0], &val[1]), - .@"flex-wrap" => |*val| { - if (context.targets.browsers != null) { - this.box_lines = null; - } - propertyHelper(this, context, dest, "wrap", &val[0], &val[1]); - }, - .@"box-lines" => |*val| propertyHelper(this, context, dest, "box_lines", &val[0], &val[1]), - .@"flex-flow" => |*val| { - if (context.targets.browsers != null) { - this.box_direction = null; - this.box_orient = null; - } - propertyHelper(this, context, dest, "direction", &val[0].direction, &val[1]); - propertyHelper(this, context, dest, "wrap", &val[0].wrap, &val[1]); - }, - .@"flex-grow" => |*val| { - if (context.targets.browsers != null) { - this.box_flex = null; - this.flex_positive = null; - } - propertyHelper(this, context, dest, "grow", &val[0], &val[1]); - }, - .@"box-flex" => |*val| propertyHelper(this, context, dest, "box_flex", &val[0], &val[1]), - .@"flex-positive" => |*val| propertyHelper(this, context, dest, "flex_positive", &val[0], &val[1]), - .@"flex-shrink" => |*val| { - if (context.targets.browsers != null) { - this.flex_negative = null; - } - propertyHelper(this, context, dest, "shrink", &val[0], &val[1]); - }, - .@"flex-negative" => |*val| propertyHelper(this, context, dest, "flex_negative", &val[0], &val[1]), - .@"flex-basis" => |*val| { - if (context.targets.browsers != null) { - this.preferred_size = null; - } - propertyHelper(this, context, dest, "basis", &val[0], &val[1]); - }, - .@"flex-preferred-size" => |*val| propertyHelper(this, context, dest, "preferred_size", &val[0], &val[1]), - .flex => |*val| { - if (context.targets.browsers != null) { - this.box_flex = null; - this.flex_positive = null; - this.flex_negative = null; - this.preferred_size = null; - } - maybeFlush(this, dest, context, "grow", &val[0].grow, &val[1]); - maybeFlush(this, dest, context, "shrink", &val[0].shrink, &val[1]); - maybeFlush(this, dest, context, "basis", &val[0].basis, &val[1]); - propertyHelper(this, context, dest, "grow", &val[0].grow, &val[1]); - propertyHelper(this, context, dest, "shrink", &val[0].shrink, &val[1]); - propertyHelper(this, context, dest, "basis", &val[0].basis, &val[1]); - }, - .order => |*val| { - if (context.targets.browsers != null) { - this.box_ordinal_group = null; - this.flex_order = null; - } - propertyHelper(this, context, dest, "order", &val[0], &val[1]); - }, - .@"box-ordinal-group" => |*val| propertyHelper(this, context, dest, "box_ordinal_group", &val[0], &val[1]), - .@"flex-order" => |*val| propertyHelper(this, context, dest, "flex_order", &val[0], &val[1]), - .unparsed => |*val| { - if (isFlexProperty(&val.property_id)) { - this.flush(dest, context); - dest.append(context.allocator, property.deepClone(context.allocator)) catch unreachable; - } else { - return false; - } - }, - else => return false, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - } - - fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) { - return; - } - - this.has_any = false; - - var direction: ?struct { FlexDirection, VendorPrefix } = bun.take(&this.direction); - var wrap: ?struct { FlexWrap, VendorPrefix } = bun.take(&this.wrap); - var grow: ?struct { CSSNumber, VendorPrefix } = bun.take(&this.grow); - var shrink: ?struct { CSSNumber, VendorPrefix } = bun.take(&this.shrink); - var basis = bun.take(&this.basis); - var box_orient = bun.take(&this.box_orient); - var box_direction = bun.take(&this.box_direction); - var box_flex = bun.take(&this.box_flex); - var box_ordinal_group = bun.take(&this.box_ordinal_group); - var box_lines = bun.take(&this.box_lines); - var flex_positive = bun.take(&this.flex_positive); - var flex_negative = bun.take(&this.flex_negative); - var preferred_size = bun.take(&this.preferred_size); - var order = bun.take(&this.order); - var flex_order = bun.take(&this.flex_order); - - // Legacy properties. These are only set if the final standard properties were unset. - legacyProperty(this, "box-orient", bun.take(&box_orient), dest, context); - legacyProperty(this, "box-direction", bun.take(&box_direction), dest, context); - legacyProperty(this, "box-ordinal-group", bun.take(&box_ordinal_group), dest, context); - legacyProperty(this, "box-flex", bun.take(&box_flex), dest, context); - legacyProperty(this, "box-lines", bun.take(&box_lines), dest, context); - legacyProperty(this, "flex-positive", bun.take(&flex_positive), dest, context); - legacyProperty(this, "flex-negative", bun.take(&flex_negative), dest, context); - legacyProperty(this, "flex-preferred-size", bun.take(&preferred_size), dest, context); - legacyProperty(this, "flex-order", bun.take(&flex_order), dest, context); - - if (direction) |val| { - const dir = val[0]; - if (context.targets.browsers) |targets| { - const prefixes = context.targets.prefixes(css.VendorPrefix.NONE, css.prefixes.Feature.flex_direction); - var prefixes_2009 = css.VendorPrefix{}; - if (isFlex2009(targets)) { - prefixes_2009.webkit = true; - } - if (prefixes.moz) { - prefixes_2009.moz = true; - } - if (!prefixes_2009.isEmpty()) { - const orient, const newdir = dir.to2009(); - bun.handleOom(dest.append(context.allocator, Property{ .@"box-orient" = .{ orient, prefixes_2009 } })); - bun.handleOom(dest.append(context.allocator, Property{ .@"box-direction" = .{ newdir, prefixes_2009 } })); - } - } - } - - if (direction != null and wrap != null) { - const dir: *FlexDirection = &direction.?[0]; - const dir_prefix: *VendorPrefix = &direction.?[1]; - const wrapinner: *FlexWrap = &wrap.?[0]; - const wrap_prefix: *VendorPrefix = &wrap.?[1]; - - const intersection = dir_prefix.bitwiseAnd(wrap_prefix.*); - if (!intersection.isEmpty()) { - var prefix = context.targets.prefixes(intersection, css.prefixes.Feature.flex_flow); - // Firefox only implemented the 2009 spec prefixed. - prefix.moz = false; - dest.append(context.allocator, Property{ .@"flex-flow" = .{ - FlexFlow{ - .direction = dir.*, - .wrap = wrapinner.*, - }, - prefix, - } }) catch |err| bun.handleOom(err); - bun.bits.remove(css.VendorPrefix, dir_prefix, intersection); - bun.bits.remove(css.VendorPrefix, wrap_prefix, intersection); - } - } - - this.singleProperty("flex-direction", bun.take(&direction), null, null, dest, context, "flex_direction"); - this.singleProperty("flex-wrap", bun.take(&wrap), null, .{ BoxLines, "box-lines" }, dest, context, "flex_wrap"); - - if (context.targets.browsers) |targets| { - if (grow) |val| { - const g = val[0]; - const prefixes = context.targets.prefixes(css.VendorPrefix.NONE, css.prefixes.Feature.flex_grow); - var prefixes_2009 = css.VendorPrefix{}; - if (isFlex2009(targets)) { - prefixes_2009.webkit = true; - } - if (prefixes.moz) { - prefixes_2009.moz = true; - } - if (!prefixes_2009.isEmpty()) { - bun.handleOom(dest.append(context.allocator, Property{ .@"box-flex" = .{ g, prefixes_2009 } })); - } - } - } - - if (grow != null and shrink != null and basis != null) { - const g = grow.?[0]; - const g_prefix: *VendorPrefix = &grow.?[1]; - const s = shrink.?[0]; - const s_prefix: *VendorPrefix = &shrink.?[1]; - const b = basis.?[0]; - const b_prefix: *VendorPrefix = &basis.?[1]; - - const intersection = g_prefix.bitwiseAnd(s_prefix.bitwiseAnd(b_prefix.*)); - if (!intersection.isEmpty()) { - var prefix = context.targets.prefixes(intersection, css.prefixes.Feature.flex); - // Firefox only implemented the 2009 spec prefixed. - prefix.moz = false; - dest.append(context.allocator, Property{ .flex = .{ - Flex{ - .grow = g, - .shrink = s, - .basis = b, - }, - prefix, - } }) catch |err| bun.handleOom(err); - bun.bits.remove(css.VendorPrefix, g_prefix, intersection); - bun.bits.remove(css.VendorPrefix, s_prefix, intersection); - bun.bits.remove(css.VendorPrefix, b_prefix, intersection); - } - } - - this.singleProperty("flex-grow", bun.take(&grow), "flex-positive", null, dest, context, "flex_grow"); - this.singleProperty("flex-shrink", bun.take(&shrink), "flex-negative", null, dest, context, "flex_shrink"); - this.singleProperty("flex-basis", bun.take(&basis), "flex-preferred-size", null, dest, context, "flex_basis"); - this.singleProperty("order", bun.take(&order), "flex-order", .{ BoxOrdinalGroup, "box-ordinal-group" }, dest, context, "order"); - } - - fn singleProperty( - this: *FlexHandler, - comptime prop: []const u8, - key: anytype, - comptime prop_2012: ?[]const u8, - comptime prop_2009: ?struct { type, []const u8 }, - dest: *css.DeclarationList, - ctx: *css.PropertyHandlerContext, - comptime feature_name: []const u8, - ) void { - _ = this; // autofix - if (key) |value| { - const val = value[0]; - var prefix = value[1]; - if (!prefix.isEmpty()) { - prefix = ctx.targets.prefixes(prefix, @field(css.prefixes.Feature, feature_name)); - if (comptime prop_2009) |p2009| { - if (prefix.none) { - // 2009 spec, implemented by webkit and firefox - if (ctx.targets.browsers) |targets| { - var prefixes_2009 = css.VendorPrefix{}; - if (isFlex2009(targets)) { - prefixes_2009.webkit = true; - } - if (prefix.moz) { - prefixes_2009.moz = true; - } - if (!prefixes_2009.isEmpty()) { - const s = brk: { - const T = comptime p2009[0]; - if (comptime T == BoxOrdinalGroup) break :brk @as(?i32, val); - break :brk p2009[0].fromStandard(&val); - }; - if (s) |v| { - dest.append(ctx.allocator, @unionInit(Property, p2009[1], .{ - v, - prefixes_2009, - })) catch |err| bun.handleOom(err); - } - } - } - } - } - - if (comptime prop_2012) |p2012| { - var ms = true; - if (prefix.ms) { - dest.append(ctx.allocator, @unionInit(Property, p2012, .{ - val, - css.VendorPrefix.MS, - })) catch |err| bun.handleOom(err); - ms = false; - } - - if (!ms) { - prefix.ms = false; - } - } - - // Firefox only implemented the 2009 spec prefixed. - prefix.moz = false; - dest.append(ctx.allocator, @unionInit(Property, prop, .{ - val, - prefix, - })) catch |err| bun.handleOom(err); - } - } - } - - fn legacyProperty(this: *FlexHandler, comptime field_name: []const u8, key: anytype, dest: *css.DeclarationList, ctx: *css.PropertyHandlerContext) void { - _ = this; // autofix - if (key) |value| { - const val = value[0]; - const prefix = value[1]; - if (!prefix.isEmpty()) { - dest.append(ctx.allocator, @unionInit(Property, field_name, .{ - val, - prefix, - })) catch |err| bun.handleOom(err); - } else { - // css.generic.eql(comptime T: type, lhs: *const T, rhs: *const T) - // css.generic.deinit(@TypeOf(val), &val, ctx.allocator); - } - } - } - - fn isFlexProperty(property_id: *const PropertyId) bool { - return switch (property_id.*) { - .@"flex-direction", - .@"box-orient", - .@"box-direction", - .@"flex-wrap", - .@"box-lines", - .@"flex-flow", - .@"flex-grow", - .@"box-flex", - .@"flex-positive", - .@"flex-shrink", - .@"flex-negative", - .@"flex-basis", - .@"flex-preferred-size", - .flex, - .order, - .@"box-ordinal-group", - .@"flex-order", - => true, - else => false, - }; - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/font.zig b/src/css/properties/font.zig deleted file mode 100644 index dc53f33063ad..000000000000 --- a/src/css/properties/font.zig +++ /dev/null @@ -1,1061 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const css_values = css.css_values; -const LengthPercentage = css_values.length.LengthPercentage; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const Percentage = css.css_values.percentage.Percentage; -const Angle = css.css_values.angle.Angle; - -/// A value for the [font-weight](https://www.w3.org/TR/css-fonts-4/#font-weight-prop) property. -pub const FontWeight = union(enum) { - /// An absolute font weight. - absolute: AbsoluteFontWeight, - /// The `bolder` keyword. - bolder, - /// The `lighter` keyword. - lighter, - - // TODO: implement this - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub inline fn default() FontWeight { - return .{ .absolute = AbsoluteFontWeight.default() }; - } - - pub fn isCompatible(this: *const FontWeight, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .absolute => |*a| a.isCompatible(browsers), - .bolder, .lighter => true, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// An [absolute font weight](https://www.w3.org/TR/css-fonts-4/#font-weight-absolute-values), -/// as used in the `font-weight` property. -/// -/// See [FontWeight](FontWeight). -pub const AbsoluteFontWeight = union(enum) { - /// An explicit weight. - weight: CSSNumber, - /// Same as `400`. - normal, - /// Same as `700`. - bold, - - pub const parse = css.DeriveParse(@This()).parse; - - pub fn toCss(this: *const AbsoluteFontWeight, dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .weight => |*weight| CSSNumberFns.toCss(weight, dest), - .normal => try dest.writeStr(if (dest.minify) "400" else "normal"), - .bold => try dest.writeStr(if (dest.minify) "700" else "bold"), - }; - } - - pub fn isCompatible(this: *const AbsoluteFontWeight, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - // Older browsers only supported 100, 200, 300, ...900 rather than arbitrary values. - .weight => |*val| if (!((val.* >= 100.0 and val.* <= 900.0) and @mod(val.*, 100.0) == 0.0)) - css.Feature.font_weight_number.isCompatible(browsers) - else - true, - else => true, - }; - } - - pub inline fn default() AbsoluteFontWeight { - return .normal; - } - - pub fn eql(lhs: *const AbsoluteFontWeight, rhs: *const AbsoluteFontWeight) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [font-size](https://www.w3.org/TR/css-fonts-4/#font-size-prop) property. -pub const FontSize = union(enum) { - /// An explicit size. - length: LengthPercentage, - /// An absolute font size keyword. - absolute: AbsoluteFontSize, - /// A relative font size keyword. - relative: RelativeFontSize, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn isCompatible(this: *const FontSize, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .length => |*l| switch (l.*) { - .dimension => |*d| switch (d.*) { - .rem => css.Feature.font_size_rem.isCompatible(browsers), - else => l.isCompatible(browsers), - }, - else => l.isCompatible(browsers), - }, - .absolute => |*a| a.isCompatible(browsers), - .relative => true, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// An [absolute font size](https://www.w3.org/TR/css-fonts-3/#absolute-size-value), -/// as used in the `font-size` property. -/// -/// See [FontSize](FontSize). -pub const AbsoluteFontSize = enum { - /// "xx-small" - @"xx-small", - /// "x-small" - @"x-small", - /// "small" - small, - /// "medium" - medium, - /// "large" - large, - /// "x-large" - @"x-large", - /// "xx-large" - @"xx-large", - /// "xxx-large" - @"xxx-large", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn isCompatible(this: *const AbsoluteFontSize, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .@"xxx-large" => css.Feature.font_size_x_x_x_large.isCompatible(browsers), - else => true, - }; - } -}; - -/// A [relative font size](https://www.w3.org/TR/css-fonts-3/#relative-size-value), -/// as used in the `font-size` property. -/// -/// See [FontSize](FontSize). -pub const RelativeFontSize = enum { - smaller, - larger, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [font-stretch](https://www.w3.org/TR/css-fonts-4/#font-stretch-prop) property. -pub const FontStretch = union(enum) { - /// A font stretch keyword. - keyword: FontStretchKeyword, - /// A percentage. - percentage: Percentage, - - // TODO: implement this - pub const parse = css.DeriveParse(@This()).parse; - - pub fn toCss(this: *const FontStretch, dest: *css.Printer) css.PrintErr!void { - if (dest.minify) { - const percentage: Percentage = this.intoPercentage(); - return percentage.toCss(dest); - } - - return switch (this.*) { - .percentage => |*val| val.toCss(dest), - .keyword => |*kw| kw.toCss(dest), - }; - } - - pub fn intoPercentage(this: *const FontStretch) Percentage { - return switch (this.*) { - .percentage => |*val| val.*, - .keyword => |*kw| kw.intoPercentage(), - }; - } - - pub fn isCompatible(this: *const FontStretch, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .percentage => css.Feature.font_stretch_percentage.isCompatible(browsers), - .keyword => true, - }; - } - - pub fn eql(lhs: *const FontStretch, rhs: *const FontStretch) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub inline fn default() FontStretch { - return .{ .keyword = FontStretchKeyword.default() }; - } -}; - -/// A [font stretch keyword](https://www.w3.org/TR/css-fonts-4/#font-stretch-prop), -/// as used in the `font-stretch` property. -/// -/// See [FontStretch](FontStretch). -pub const FontStretchKeyword = enum { - /// 100% - normal, - /// 50% - @"ultra-condensed", - /// 62.5% - @"extra-condensed", - /// 75% - condensed, - /// 87.5% - @"semi-condensed", - /// 112.5% - @"semi-expanded", - /// 125% - expanded, - /// 150% - @"extra-expanded", - /// 200% - @"ultra-expanded", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub inline fn default() FontStretchKeyword { - return .normal; - } - - pub fn intoPercentage(this: *const FontStretchKeyword) Percentage { - const val: f32 = switch (this.*) { - .@"ultra-condensed" => 0.5, - .@"extra-condensed" => 0.625, - .condensed => 0.75, - .@"semi-condensed" => 0.875, - .normal => 1.0, - .@"semi-expanded" => 1.125, - .expanded => 1.25, - .@"extra-expanded" => 1.5, - .@"ultra-expanded" => 2.0, - }; - return .{ .v = val }; - } -}; - -/// A value for the [font-family](https://www.w3.org/TR/css-fonts-4/#font-family-prop) property. -pub const FontFamily = union(enum) { - /// A generic family name. - generic: GenericFontFamily, - /// A custom family name. - family_name: []const u8, - - pub fn HashMap(comptime V: type) type { - return std.ArrayHashMapUnmanaged(FontFamily, V, struct { - pub fn hash(_: @This(), key: FontFamily) u32 { - var hasher = std.hash.Wyhash.init(0); - key.hash(&hasher); - return @truncate(hasher.final()); - } - - pub fn eql(_: @This(), a: FontFamily, b: FontFamily, _: usize) bool { - return a.eql(&b); - } - }, false); - } - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectString, .{}).asValue()) |value| { - return .{ .result = .{ .family_name = value } }; - } - - if (input.tryParse(GenericFontFamily.parse, .{}).asValue()) |value| { - return .{ .result = .{ .generic = value } }; - } - - const stralloc = input.allocator(); - const value = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - var string: ?ArrayList(u8) = null; - while (input.tryParse(css.Parser.expectIdent, .{}).asValue()) |ident| { - if (string == null) { - string = ArrayList(u8){}; - bun.handleOom(string.?.appendSlice(stralloc, value)); - } - - if (string) |*s| { - bun.handleOom(s.append(stralloc, ' ')); - bun.handleOom(s.appendSlice(stralloc, ident)); - } - } - - const final_value = if (string) |s| s.items else value; - - return .{ .result = .{ .family_name = final_value } }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - switch (this.*) { - .generic => |val| { - try val.toCss(dest); - }, - .family_name => |val| { - // Generic family names such as sans-serif must be quoted if parsed as a string. - // CSS wide keywords, as well as "default", must also be quoted. - // https://www.w3.org/TR/css-fonts-4/#family-name-syntax - - if (val.len > 0 and - !css.parse_utility.parseString( - dest.allocator, - GenericFontFamily, - val, - GenericFontFamily.parse, - ).isOk()) - { - var id = std.Io.Writer.Allocating.init(dest.allocator); - defer id.deinit(); - var first = true; - var split_iter = std.mem.splitScalar(u8, val, ' '); - while (split_iter.next()) |slice| { - if (first) { - first = false; - } else { - bun.handleOom(id.writer.writeByte(' ') catch |e| switch (e) { - error.WriteFailed => error.OutOfMemory, - }); - } - css.serializer.serializeIdentifier(slice, &id.writer) catch return dest.addFmtError(); - } - if (id.written().len < val.len + 2) { - return dest.writeStr(id.written()); - } - } - return css.serializer.serializeString(val, dest) catch return dest.addFmtError(); - }, - } - } - - pub fn isCompatible(this: *const FontFamily, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .generic => |g| g.isCompatible(browsers), - .family_name => true, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// A [generic font family](https://www.w3.org/TR/css-fonts-4/#generic-font-families) name, -/// as used in the `font-family` property. -/// -/// See [FontFamily](FontFamily). -pub const GenericFontFamily = enum { - serif, - @"sans-serif", - cursive, - fantasy, - monospace, - @"system-ui", - emoji, - math, - fangsong, - @"ui-serif", - @"ui-sans-serif", - @"ui-monospace", - @"ui-rounded", - - // CSS wide keywords. These must be parsed as identifiers so they - // don't get serialized as strings. - // https://www.w3.org/TR/css-values-4/#common-keywords - initial, - inherit, - unset, - // Default is also reserved by the type. - // https://www.w3.org/TR/css-values-4/#custom-idents - default, - - // CSS defaulting keywords - // https://drafts.csswg.org/css-cascade-5/#defaulting-keywords - revert, - @"revert-layer", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn isCompatible(this: *const GenericFontFamily, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .@"system-ui" => css.Feature.font_family_system_ui.isCompatible(browsers), - .@"ui-serif", .@"ui-sans-serif", .@"ui-monospace", .@"ui-rounded" => css.Feature.extended_system_fonts.isCompatible(browsers), - else => true, - }; - } -}; - -/// A value for the [font-style](https://www.w3.org/TR/css-fonts-4/#font-style-prop) property. -pub const FontStyle = union(enum) { - /// Normal font style. - normal, - /// Italic font style. - italic, - /// Oblique font style, with a custom angle. - oblique: Angle, - - pub fn default() FontStyle { - return .normal; - } - - pub fn parse(input: *css.Parser) css.Result(FontStyle) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("normal", ident)) { - return .{ .result = .normal }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("italic", ident)) { - return .{ .result = .italic }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("oblique", ident)) { - const angle = input.tryParse(Angle.parse, .{}).unwrapOr(FontStyle.defaultObliqueAngle()); - return .{ .result = .{ .oblique = angle } }; - } else { - // - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - } - - pub fn toCss(this: *const FontStyle, dest: *Printer) PrintErr!void { - switch (this.*) { - .normal => try dest.writeStr("normal"), - .italic => try dest.writeStr("italic"), - .oblique => |angle| { - try dest.writeStr("oblique"); - if (!angle.eql(&FontStyle.defaultObliqueAngle())) { - try dest.writeChar(' '); - try angle.toCss(dest); - } - }, - } - } - - pub fn isCompatible(this: *const FontStyle, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .oblique => |*angle| if (!angle.eql(&FontStyle.defaultObliqueAngle())) - css.Feature.font_style_oblique_angle.isCompatible(browsers) - else - true, - .normal, .italic => true, - }; - } - - pub fn defaultObliqueAngle() Angle { - return Angle{ .deg = 14.0 }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [font-variant-caps](https://www.w3.org/TR/css-fonts-4/#font-variant-caps-prop) property. -pub const FontVariantCaps = enum { - /// No special capitalization features are applied. - normal, - /// The small capitals feature is used for lower case letters. - @"small-caps", - /// Small capitals are used for both upper and lower case letters. - @"all-small-caps", - /// Petite capitals are used. - @"petite-caps", - /// Petite capitals are used for both upper and lower case letters. - @"all-petite-caps", - /// Enables display of mixture of small capitals for uppercase letters with normal lowercase letters. - unicase, - /// Uses titling capitals. - @"titling-caps", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() FontVariantCaps { - return .normal; - } - - fn isCss2(this: *const FontVariantCaps) bool { - return switch (this.*) { - .normal, .@"small-caps" => true, - else => false, - }; - } - - pub fn parseCss2(input: *css.Parser) css.Result(FontVariantCaps) { - const value = switch (FontVariantCaps.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (!value.isCss2()) { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - return .{ .result = value }; - } - - pub fn isCompatible(_: *const FontVariantCaps, _: bun.css.targets.Browsers) bool { - return true; - } -}; - -/// A value for the [line-height](https://www.w3.org/TR/2020/WD-css-inline-3-20200827/#propdef-line-height) property. -pub const LineHeight = union(enum) { - /// The UA sets the line height based on the font. - normal, - /// A multiple of the element's font size. - number: CSSNumber, - /// An explicit height. - length: LengthPercentage, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn isCompatible(this: *const LineHeight, browsers: bun.css.targets.Browsers) bool { - return switch (this.*) { - .length => |*l| l.isCompatible(browsers), - .normal, .number => true, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn default() LineHeight { - return .normal; - } -}; - -/// A value for the [font](https://www.w3.org/TR/css-fonts-4/#font-prop) shorthand property. -pub const Font = struct { - /// The font family. - family: bun.BabyList(FontFamily), - /// The font size. - size: FontSize, - /// The font style. - style: FontStyle, - /// The font weight. - weight: FontWeight, - /// The font stretch. - stretch: FontStretch, - /// The line height. - line_height: LineHeight, - /// How the text should be capitalized. Only CSS 2.1 values are supported. - variant_caps: FontVariantCaps, - - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.font, PropertyFieldMap); - - pub const PropertyFieldMap = .{ - .family = css.PropertyIdTag.@"font-family", - .size = css.PropertyIdTag.@"font-size", - .style = css.PropertyIdTag.@"font-style", - .weight = css.PropertyIdTag.@"font-weight", - .stretch = css.PropertyIdTag.@"font-stretch", - .line_height = css.PropertyIdTag.@"line-height", - .variant_caps = css.PropertyIdTag.@"font-variant-caps", - }; - - pub fn parse(input: *css.Parser) css.Result(Font) { - var style: ?FontStyle = null; - var weight: ?FontWeight = null; - var stretch: ?FontStretch = null; - var size: ?FontSize = null; - var variant_caps: ?FontVariantCaps = null; - var count: i32 = 0; - - while (true) { - // Skip "normal" since it is valid for several properties, but we don't know which ones it will be used for yet. - if (input.tryParse(css.Parser.expectIdentMatching, .{"normal"}).isOk()) { - count += 1; - continue; - } - - if (style == null) { - if (input.tryParse(FontStyle.parse, .{}).asValue()) |value| { - style = value; - count += 1; - continue; - } - } - - if (weight == null) { - if (input.tryParse(FontWeight.parse, .{}).asValue()) |value| { - weight = value; - count += 1; - continue; - } - } - - if (variant_caps != null) { - if (input.tryParse(FontVariantCaps.parseCss2, .{}).asValue()) |value| { - variant_caps = value; - count += 1; - continue; - } - } - - if (stretch == null) { - if (input.tryParse(FontStretchKeyword.parse, .{}).asValue()) |value| { - stretch = .{ .keyword = value }; - count += 1; - continue; - } - } - - size = switch (@call(.auto, @field(FontSize, "parse"), .{input})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - break; - } - - if (count > 4) return .{ .err = input.newCustomError(css.ParserError.invalid_declaration) }; - - const final_size = size orelse return .{ .err = input.newCustomError(css.ParserError.invalid_declaration) }; - - const line_height = if (input.tryParse(css.Parser.expectDelim, .{'/'}).isOk()) switch (LineHeight.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } else null; - - const family = switch (bun.BabyList(FontFamily).parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = Font{ - .family = family, - .size = final_size, - .style = style orelse FontStyle.default(), - .weight = weight orelse FontWeight.default(), - .stretch = stretch orelse FontStretch.default(), - .line_height = line_height orelse LineHeight.default(), - .variant_caps = variant_caps orelse FontVariantCaps.default(), - } }; - } - - pub fn toCss(this: *const Font, dest: *Printer) PrintErr!void { - if (!this.style.eql(&FontStyle.default())) { - try this.style.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.variant_caps.eql(&FontVariantCaps.default())) { - try this.variant_caps.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.weight.eql(&FontWeight.default())) { - try this.weight.toCss(dest); - try dest.writeChar(' '); - } - - if (!this.stretch.eql(&FontStretch.default())) { - try this.stretch.toCss(dest); - try dest.writeChar(' '); - } - - try this.size.toCss(dest); - - if (!this.line_height.eql(&LineHeight.default())) { - try dest.delim('/', true); - try this.line_height.toCss(dest); - } - - try dest.writeChar(' '); - - const len = this.family.len; - for (this.family.sliceConst(), 0..) |*val, idx| { - try val.toCss(dest); - if (idx < len - 1) { - try dest.delim(',', false); - } - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [vertical align](https://drafts.csswg.org/css2/#propdef-vertical-align) property. -// TODO: there is a more extensive spec in CSS3 but it doesn't seem any browser implements it? https://www.w3.org/TR/css-inline-3/#transverse-alignment -pub const VerticalAlign = union(enum) { - /// A vertical align keyword. - keyword: VerticalAlignKeyword, - /// An explicit length. - length: LengthPercentage, -}; - -/// A keyword for the [vertical align](https://drafts.csswg.org/css2/#propdef-vertical-align) property. -pub const VerticalAlignKeyword = enum { - /// Align the baseline of the box with the baseline of the parent box. - baseline, - /// Lower the baseline of the box to the proper position for subscripts of the parent’s box. - sub, - /// Raise the baseline of the box to the proper position for superscripts of the parent’s box. - super, - /// Align the top of the aligned subtree with the top of the line box. - top, - /// Align the top of the box with the top of the parent’s content area. - @"text-top", - /// Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent. - middle, - /// Align the bottom of the aligned subtree with the bottom of the line box. - bottom, - /// Align the bottom of the box with the bottom of the parent’s content area. - @"text-bottom", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -pub const FontProperty = packed struct(u8) { - @"font-family": bool = false, - @"font-size": bool = false, - @"font-style": bool = false, - @"font-weight": bool = false, - @"font-stretch": bool = false, - @"line-height": bool = false, - @"font-variant-caps": bool = false, - __unused: u1 = 0, - - const FONT = FontProperty{ - .@"font-family" = true, - .@"font-size" = true, - .@"font-style" = true, - .@"font-weight" = true, - .@"font-stretch" = true, - .@"line-height" = true, - .@"font-variant-caps" = true, - }; - - pub fn tryFromPropertyId(property_id: css.PropertyIdTag) ?FontProperty { - inline for (std.meta.fields(FontProperty)) |field| { - if (comptime std.mem.eql(u8, field.name, "__unused")) continue; - const desired = comptime @field(css.PropertyIdTag, field.name); - if (desired == property_id) { - var result: FontProperty = .{}; - @field(result, field.name) = true; - return result; - } - } - if (property_id == .font) { - return FontProperty.FONT; - } - return null; - } -}; - -pub const FontHandler = struct { - family: ?bun.BabyList(FontFamily) = null, - size: ?FontSize = null, - style: ?FontStyle = null, - weight: ?FontWeight = null, - stretch: ?FontStretch = null, - line_height: ?LineHeight = null, - variant_caps: ?FontVariantCaps = null, - flushed_properties: FontProperty = .{}, - has_any: bool = false, - - pub fn handleProperty( - this: *FontHandler, - property: *const css.Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) bool { - switch (property.*) { - .@"font-family" => |*val| this.propertyHelper(dest, context, "family", val), - .@"font-size" => |*val| this.propertyHelper(dest, context, "size", val), - .@"font-style" => |*val| this.propertyHelper(dest, context, "style", val), - .@"font-weight" => |*val| this.propertyHelper(dest, context, "weight", val), - .@"font-stretch" => |*val| this.propertyHelper(dest, context, "stretch", val), - .@"font-variant-caps" => |*val| this.propertyHelper(dest, context, "variant_caps", val), - .@"line-height" => |*val| this.propertyHelper(dest, context, "line_height", val), - .font => |*val| { - this.flushHelper(dest, context, "family", &val.family); - this.flushHelper(dest, context, "size", &val.size); - this.flushHelper(dest, context, "style", &val.style); - this.flushHelper(dest, context, "weight", &val.weight); - this.flushHelper(dest, context, "stretch", &val.stretch); - this.flushHelper(dest, context, "line_height", &val.line_height); - this.flushHelper(dest, context, "variant_caps", &val.variant_caps); - - this.family = css.generic.deepClone(bun.BabyList(FontFamily), &val.family, context.allocator); - this.size = val.size.deepClone(context.allocator); - this.style = val.style.deepClone(context.allocator); - this.weight = val.weight.deepClone(context.allocator); - this.stretch = val.stretch.deepClone(context.allocator); - this.line_height = val.line_height.deepClone(context.allocator); - this.variant_caps = val.variant_caps.deepClone(context.allocator); - this.has_any = true; - // TODO: reset other properties - }, - .unparsed => |*val| { - if (isFontProperty(val.property_id)) { - this.flush(dest, context); - bun.bits.insert(FontProperty, &this.flushed_properties, FontProperty.tryFromPropertyId(val.property_id).?); - bun.handleOom(dest.append(context.allocator, property.*)); - } else { - return false; - } - }, - else => return false, - } - - return true; - } - - inline fn propertyHelper(this: *FontHandler, dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype) void { - this.flushHelper(dest, context, prop, val); - @field(this, prop) = css.generic.deepClone(@TypeOf(val.*), val, context.allocator); - this.has_any = true; - } - - inline fn flushHelper( - this: *FontHandler, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - comptime prop: []const u8, - val: anytype, - ) void { - if (@field(this, prop) != null and - !css.generic.eql(@TypeOf(@field(this, prop).?), &@field(this, prop).?, val) and - context.targets.browsers != null and - !css.generic.isCompatible(@TypeOf(@field(this, prop).?), val, context.targets.browsers.?)) - { - this.flush(dest, context); - } - } - - pub fn finalize(this: *FontHandler, decls: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(decls, context); - this.flushed_properties = .{}; - } - - fn push(self: *FontHandler, d: *css.DeclarationList, ctx: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype) void { - bun.handleOom(d.append(ctx.allocator, @unionInit(css.Property, prop, val))); - var insertion: FontProperty = .{}; - if (comptime std.mem.eql(u8, prop, "font")) { - insertion = FontProperty.FONT; - } else { - @field(insertion, prop) = true; - } - bun.bits.insert(FontProperty, &self.flushed_properties, insertion); - } - - fn flush(this: *FontHandler, decls: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) { - return; - } - - this.has_any = false; - - var family: ?bun.BabyList(FontFamily) = bun.take(&this.family); - if (!this.flushed_properties.@"font-family") { - family = compatibleFontFamily(context.allocator, family, !context.targets.shouldCompileSame(.font_family_system_ui)); - } - - const size: ?FontSize = bun.take(&this.size); - const style: ?FontStyle = bun.take(&this.style); - const weight: ?FontWeight = bun.take(&this.weight); - const stretch: ?FontStretch = bun.take(&this.stretch); - const line_height: ?LineHeight = bun.take(&this.line_height); - const variant_caps: ?FontVariantCaps = bun.take(&this.variant_caps); - - if (family) |*f| { - if (f.len > 1) { - // Dedupe - var sfb = std.heap.stackFallback(664, bun.default_allocator); - const alloc = sfb.get(); - var seen = FontFamily.HashMap(void){}; - defer seen.deinit(alloc); - - var i: usize = 0; - while (i < f.len) { - const gop = bun.handleOom(seen.getOrPut(alloc, f.at(i).*)); - if (gop.found_existing) { - _ = f.orderedRemove(i); - } else { - i += 1; - } - } - } - } - - if (family != null and size != null and style != null and weight != null and stretch != null and line_height != null and variant_caps != null) { - const caps = variant_caps.?; - push(this, decls, context, "font", Font{ - .family = family.?, - .size = size.?, - .style = style.?, - .weight = weight.?, - .stretch = stretch.?, - .line_height = line_height.?, - .variant_caps = if (caps.isCss2()) caps else FontVariantCaps.default(), - }); - - // The `font` property only accepts CSS 2.1 values for font-variant caps. - // If we have a CSS 3+ value, we need to add a separate property. - if (!caps.isCss2()) { - push(this, decls, context, "font-variant-caps", caps); - } - } else { - if (family) |val| { - push(this, decls, context, "font-family", val); - } - - if (size) |val| { - push(this, decls, context, "font-size", val); - } - - if (style) |val| { - push(this, decls, context, "font-style", val); - } - - if (variant_caps) |val| { - push(this, decls, context, "font-variant-caps", val); - } - - if (weight) |val| { - push(this, decls, context, "font-weight", val); - } - - if (stretch) |val| { - push(this, decls, context, "font-stretch", val); - } - - if (line_height) |val| { - push(this, decls, context, "line-height", val); - } - } - } -}; - -const SYSTEM_UI: FontFamily = FontFamily{ .generic = .@"system-ui" }; - -const DEFAULT_SYSTEM_FONTS: []const []const u8 = &.{ - // #1: Supported as the '-apple-system' value (macOS, Safari >= 9.2 < 11, Firefox >= 43) - "-apple-system", - // #2: Supported as the 'BlinkMacSystemFont' value (macOS, Chrome < 56) - "BlinkMacSystemFont", - "Segoe UI", // Windows >= Vista - "Roboto", // Android >= 4 - "Noto Sans", // Plasma >= 5.5 - "Ubuntu", // Ubuntu >= 10.10 - "Cantarell", // GNOME >= 3 - "Helvetica Neue", -}; - -inline fn compatibleFontFamily(allocator: std.mem.Allocator, _family: ?bun.BabyList(FontFamily), is_supported: bool) ?bun.BabyList(FontFamily) { - var family = _family; - if (is_supported) { - return family; - } - - if (family) |*families| { - for (families.sliceConst(), 0..) |v, i| { - if (v.eql(&SYSTEM_UI)) { - for (DEFAULT_SYSTEM_FONTS, 0..) |name, j| { - bun.handleOom(families.insert(allocator, i + j + 1, .{ .family_name = name })); - } - break; - } - } - } - - return family; -} - -inline fn isFontProperty(property_id: css.PropertyId) bool { - return switch (property_id) { - .@"font-family", - .@"font-size", - .@"font-style", - .@"font-weight", - .@"font-stretch", - .@"font-variant-caps", - .@"line-height", - .font, - => true, - else => false, - }; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/generate_properties.ts b/src/css/properties/generate_properties.ts deleted file mode 100644 index 19fc43ebfc44..000000000000 --- a/src/css/properties/generate_properties.ts +++ /dev/null @@ -1,2051 +0,0 @@ -type VendorPrefixes = "none" | "webkit" | "moz" | "ms" | "o"; - -type LogicalGroup = - | "border_color" - | "border_style" - | "border_width" - | "border_radius" - | "margin" - | "scroll_margin" - | "padding" - | "scroll_padding" - | "inset" - | "size" - | "min_size" - | "max_size"; - -type PropertyCategory = "logical" | "physical"; - -type PropertyDef = { - ty: string; - shorthand?: boolean; - valid_prefixes?: VendorPrefixes[]; - logical_group?: { - ty: LogicalGroup; - category: PropertyCategory; - }; - /// By default true - unprefixed?: boolean; - conditional?: { - css_modules: boolean; - }; - eval_branch_quota?: number; - /** - * If parsing a property fails, we fallback to parsing it as `UnparsedProperty`. This is just - * the raw tokens. This is helpful for certain minify property handlers. - * - * In other cases, it's more helpful to throw an error. For example, if the `composes` property, - * is used incorrectly, it is more useful for the user to know about that error. - */ - parse_dont_make_unparsed?: boolean; -}; - -const OUTPUT_FILE = "src/css/properties/properties_generated.zig"; - -async function generateCode(property_defs: Record) { - const EMIT_COMPLETED_MD_FILE = true; - if (EMIT_COMPLETED_MD_FILE) { - const completed = Object.entries(property_defs) - .map(([name, meta]) => `- [x] \`${name}\``) - .join("\n"); - await Bun.$`echo ${completed} > completed.md`; - } - await Bun.$`echo ${prelude()} > ${OUTPUT_FILE}`; - await Bun.$`echo ${generateProperty(property_defs)} >> ${OUTPUT_FILE}`; - await Bun.$`echo ${generatePropertyId(property_defs)} >> ${OUTPUT_FILE}`; - await Bun.$`echo ${generatePropertyIdTag(property_defs)} >> ${OUTPUT_FILE}`; - await Bun.$`vendor/zig/zig.exe fmt ${OUTPUT_FILE}`; -} - -function generatePropertyIdTag(property_defs: Record): string { - return `pub const PropertyIdTag = enum(u16) { - ${Object.keys(property_defs) - .map(key => `${escapeIdent(key)},`) - .join("\n")} - all, - unparsed, - custom, - - /// Helper function used in comptime code to know whether to access the underlying value - /// with tuple indexing syntax because it may have a VendorPrefix associated with it. - pub fn hasVendorPrefix(this: PropertyIdTag) bool { - return switch (this) { - ${Object.entries(property_defs) - .map(([name, meta]) => `.${escapeIdent(name)} => ${meta.valid_prefixes === undefined ? "false" : "true"},`) - .join("\n")} - .unparsed => false, - .custom => false, - .all => false, - }; - } - - /// Helper function used in comptime code to know whether to access the underlying value - /// with tuple indexing syntax because it may have a VendorPrefix associated with it. - pub fn valueType(this: PropertyIdTag) type { - return switch (this) { - ${Object.entries(property_defs) - .map(([name, meta]) => `.${escapeIdent(name)} => ${meta.ty},`) - .join("\n")} - .all => CSSWideKeyword, - .unparsed => UnparsedProperty, - .custom => CustomProperty, - }; - } -};`; -} - -function generateProperty(property_defs: Record): string { - return `pub const Property = union(PropertyIdTag) { -${Object.entries(property_defs) - .map(([name, meta]) => generatePropertyField(name, meta)) - .join("\n")} - all: CSSWideKeyword, - unparsed: UnparsedProperty, - custom: CustomProperty, - - ${generatePropertyImpl(property_defs)} -};`; -} - -function generatePropertyImpl(property_defs: Record): string { - const required_functions = ["deepClone", "parse", "toCss", "eql"]; - - return ` - // Copy manually implemented functions. - pub const toCss = properties_impl.property_mixin.toCss - - // Sanity check to make sure all types have the following functions: - // - deepClone() - // - eql() - // - parse() - // - toCss() - // - // We do this string concatenation thing so we get all the errors at once, - // instead of relying on Zig semantic analysis which usually stops at the first error. - comptime { - const compile_error: []const u8 = compile_error: { - var compile_error: []const u8 = ""; - ${Object.entries(property_defs) - .map(([name, meta]) => { - if (meta.ty != "void" && meta.ty != "CSSNumber" && meta.ty != "CSSInteger") { - return required_functions - .map( - fn => ` - if (!@hasDecl(${meta.ty}, "${fn}")) { - compile_error = compile_error ++ @typeName(${meta.ty}) ++ ": does not have a ${fn}() function.\\n"; - } - `, - ) - .join("\n"); - } - return ""; - }) - .join("\n")} - const final_compile_error = compile_error; - break :compile_error final_compile_error; - }; - if (compile_error.len > 0) { - @compileError(compile_error); - } - } - - /// Parses a CSS property by name. - pub fn parse(property_id: PropertyId, input: *css.Parser, options: *const css.ParserOptions) Result(Property) { - const state = input.state(); - - switch (property_id) { - ${generatePropertyImplParseCases(property_defs)} - .all => return .{ .result = .{ .all = switch (CSSWideKeyword.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }, - .custom => |name| return .{ .result = .{ .custom = switch (CustomProperty.parse(name, input, options)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }, - else => {}, - } - - // If a value was unable to be parsed, treat as an unparsed property. - // This is different from a custom property, handled below, in that the property name is known - // and stored as an enum rather than a string. This lets property handlers more easily deal with it. - // Ideally we'd only do this if var() or env() references were seen, but err on the safe side for now. - input.reset(&state); - return .{ .result = .{ .unparsed = switch (UnparsedProperty.parse(property_id, input, options)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }; - } - - pub fn propertyId(this: *const Property) PropertyId { - return switch (this.*) { - ${Object.entries(property_defs) - .map(([name, meta]) => { - if (meta.valid_prefixes !== undefined) { - return `.${escapeIdent(name)} => |*v| PropertyId{ .${escapeIdent(name)} = v[1] },`; - } - return `.${escapeIdent(name)} => .${escapeIdent(name)},`; - }) - .join("\n")} - .all => PropertyId.all, - .unparsed => |unparsed| unparsed.property_id, - .custom => |c| .{ .custom = c.name }, - }; - } - - pub fn deepClone(this: *const Property, allocator: std.mem.Allocator) Property { - return switch (this.*) { - ${Object.entries(property_defs) - .map(([name, meta]) => { - if (meta.valid_prefixes !== undefined) { - const clone_expr = - meta.ty === "CSSNumber" || meta.ty === "CSSInteger" ? "v[0]" : "v[0].deepClone(allocator)"; - return `.${escapeIdent(name)} => |*v| .{ .${escapeIdent(name)} = .{ ${clone_expr}, v[1] } },`; - } - const clone_expr = - meta.ty === "CSSNumber" || meta.ty === "CSSInteger" - ? "v.*" - : meta.ty.includes("BabyList(") - ? `css.generic.deepClone(${meta.ty}, v, allocator)` - : "v.deepClone(allocator)"; - return `.${escapeIdent(name)} => |*v| .{ .${escapeIdent(name)} = ${clone_expr} },`; - }) - .join("\n")} - .all => |*a| return .{ .all = a.deepClone(allocator) }, - .unparsed => |*u| return .{ .unparsed = u.deepClone(allocator) }, - .custom => |*c| return .{ .custom = c.deepClone(allocator) }, - }; - } - - /// We're going to have this empty for now since not every property has a deinit function. - /// It's not strictly necessary since all allocations are into an arena. - /// It's mostly intended as a performance optimization in the case where mimalloc arena is used, - /// since it can reclaim the memory and use it for subsequent allocations. - /// I haven't benchmarked that though, so I don't actually know how much faster it would actually make it. - pub fn deinit(this: *@This(), allocator: std.mem.Allocator) void { - _ = this; - _ = allocator; - } - - pub inline fn __toCssHelper(this: *const Property) struct{[]const u8, VendorPrefix} { - return switch (this.*) { - ${generatePropertyImplToCssHelper(property_defs)} - .all => .{ "all", VendorPrefix{ .none = true } }, - .unparsed => |*unparsed| brk: { - var prefix = unparsed.property_id.prefix(); - if (prefix.isEmpty()) { - prefix = VendorPrefix{ .none = true }; - } - break :brk .{ unparsed.property_id.name(), prefix }; - }, - .custom => unreachable, - }; - } - - /// Serializes the value of a CSS property without its name or \`!important\` flag. - pub fn valueToCss(this: *const Property, dest: *css.Printer) PrintErr!void { - return switch(this.*) { - ${Object.entries(property_defs) - .map(([name, meta]) => { - const value = meta.valid_prefixes === undefined ? "value" : "value[0]"; - const to_css = - meta.ty === "CSSNumber" - ? `CSSNumberFns.toCss(&${value}, dest)` - : meta.ty === "CSSInteger" - ? `CSSIntegerFns.toCss(&${value}, dest)` - : meta.ty.includes("ArrayList") - ? `css.generic.toCss(${meta.ty}, ${value}, dest)` - : `${value}.toCss(dest)`; - return `.${escapeIdent(name)} => |*value| ${to_css},`; - }) - .join("\n")} - .all => |*keyword| keyword.toCss(dest), - .unparsed => |*unparsed| unparsed.value.toCss(dest, false), - .custom => |*c| c.value.toCss(dest, c.name == .custom), - }; - } - - /// Returns the given longhand property for a shorthand. - pub fn longhand(this: *const Property, property_id: *const PropertyId) ?Property { - switch (this.*) { - ${Object.entries(property_defs) - .filter(([_, meta]) => meta.shorthand) - .map(([name, meta]) => { - if (meta.valid_prefixes !== undefined) { - return `.${escapeIdent(name)} => |*v| { - if (!v[1].eq(property_id.prefix())) return null; - return v[0].longhand(property_id); - },`; - } - - return `.${escapeIdent(name)} => |*v| return v.longhand(property_id),`; - }) - .join("\n")} - else => {}, - } - return null; - } - - pub fn eql(lhs: *const Property, rhs: *const Property) bool { - if (@intFromEnum(lhs.*) != @intFromEnum(rhs.*)) return false; - return switch (lhs.*) { - ${Object.entries(property_defs) - .map(([name, meta]) => { - if (meta.valid_prefixes !== undefined) - return `.${escapeIdent(name)} => |*v| css.generic.eql(${meta.ty}, &v[0], &rhs.${escapeIdent(name)}[0]) and v[1].eq(rhs.${escapeIdent(name)}[1]),`; - return `.${escapeIdent(name)} => |*v| css.generic.eql(${meta.ty}, v, &rhs.${escapeIdent(name)}),`; - }) - .join("\n")} - .unparsed => |*u| u.eql(&rhs.unparsed), - .all => true, - .custom => |*c| c.eql(&rhs.custom), - }; - } -`; -} - -function generatePropertyImplToCssHelper(property_defs: Record): string { - return Object.entries(property_defs) - .map(([name, meta]) => { - const capture = meta.valid_prefixes === undefined ? "" : "|*x|"; - const prefix = meta.valid_prefixes === undefined ? "VendorPrefix{ .none = true }" : 'x.@"1"'; - return `.${escapeIdent(name)} => ${capture} .{"${name}", ${prefix}},`; - }) - .join("\n"); -} - -function generatePropertyImplParseCases(property_defs: Record): string { - return Object.entries(property_defs) - .map(([name, meta]) => { - const capture = meta.valid_prefixes === undefined ? "" : "|pre|"; - const ret = - meta.valid_prefixes === undefined - ? `.{ .${escapeIdent(name)} = c }` - : `.{ .${escapeIdent(name)} = .{ c, pre } }`; - if (meta.parse_dont_make_unparsed === true) { - return `.${escapeIdent(name)} => ${capture} { - ${meta.eval_branch_quota !== undefined ? `@setEvalBranchQuota(${meta.eval_branch_quota});` : ""} - return switch (css.generic.parseWithOptions(${meta.ty}, input, options)) { - .result => |c| return .{ .result = ${ret} }, - .err => |e| return .{ .err = e }, - }; -},`; - } - return `.${escapeIdent(name)} => ${capture} { - ${meta.eval_branch_quota !== undefined ? `@setEvalBranchQuota(${meta.eval_branch_quota});` : ""} - if (css.generic.parseWithOptions(${meta.ty}, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = ${ret} }; - } - } -},`; - }) - .join("\n"); -} - -function generatePropertyField(name: string, meta: PropertyDef): string { - if (meta.valid_prefixes !== undefined) { - return ` ${escapeIdent(name)}: struct{ ${meta.ty}, VendorPrefix },`; - } - return ` ${escapeIdent(name)}: ${meta.ty},`; -} - -function generatePropertyId(property_defs: Record): string { - return `pub const PropertyId = union(PropertyIdTag) { -${Object.entries(property_defs) - .map(([name, meta]) => generatePropertyIdField(name, meta)) - .join("\n")} - all, - unparsed, - custom: CustomPropertyName, - - // Copy manually implemented functions. - pub const toCss = properties_impl.property_id_mixin.toCss; - pub const parse = properties_impl.property_id_mixin.toCss; - pub const fromString = properties_impl.property_id_mixin.toCss; - pub const fromStr = fromString; - -${generatePropertyIdImpl(property_defs)} -};`; -} - -function generatePropertyIdField(name: string, meta: PropertyDef): string { - if (meta.valid_prefixes !== undefined) { - return ` ${escapeIdent(name)}: VendorPrefix,`; - } - return ` ${escapeIdent(name)},`; -} - -function generatePropertyIdImpl(property_defs: Record): string { - return ` - /// Returns the property name, without any vendor prefixes. - pub inline fn name(this: *const PropertyId) []const u8 { - if (this.* == .custom) return this.custom.asStr(); - return @tagName(this.*); - } - - /// Returns the vendor prefix for this property id. - pub fn prefix(this: *const PropertyId) VendorPrefix { - return switch (this.*) { - ${generatePropertyIdImplPrefix(property_defs)} - .all, .custom, .unparsed => VendorPrefix{}, - }; - } - - pub fn fromNameAndPrefix(name1: []const u8, pre: VendorPrefix) ?PropertyId { - const Enum = enum { ${Object.entries(property_defs) - .map( - ([prop_name, def], i) => `${escapeIdent(prop_name)}${i === Object.keys(property_defs).length - 1 ? "" : ", "}`, - ) - .join("")} }; - const Map = comptime bun.ComptimeEnumMap(Enum); - if (Map.getASCIIICaseInsensitive(name1)) |prop| { - switch (prop) { - ${Object.entries(property_defs).map(([name, meta]) => { - return `.${escapeIdent(name)} => { - const allowed_prefixes = ${constructVendorPrefix(meta.valid_prefixes)}; - if (allowed_prefixes.contains(pre)) return ${meta.valid_prefixes === undefined ? `.${escapeIdent(name)}` : `.{ .${escapeIdent(name)} = pre }`}; - }`; - })} - } - } - - return null; - } - - pub fn withPrefix(this: *const PropertyId, pre: VendorPrefix) PropertyId { - return switch (this.*) { - ${Object.entries(property_defs) - .map(([prop_name, def]) => { - if (def.valid_prefixes === undefined) return `.${escapeIdent(prop_name)} => .${escapeIdent(prop_name)},`; - return `.${escapeIdent(prop_name)} => .{ .${escapeIdent(prop_name)} = pre },`; - }) - .join("\n")} - else => this.*, - }; - } - - pub fn addPrefix(this: *PropertyId, pre: VendorPrefix) void { - return switch (this.*) { - ${Object.entries(property_defs) - .map(([prop_name, def]) => { - if (def.valid_prefixes === undefined) return `.${escapeIdent(prop_name)} => {},`; - return `.${escapeIdent(prop_name)} => |*p| { p.insert(pre); },`; - }) - .join("\n")} - else => {}, - }; - } - - pub inline fn deepClone(this: *const PropertyId, _: std.mem.Allocator) PropertyId { - return this.*; - } - - pub fn eql(lhs: *const PropertyId, rhs: *const PropertyId) bool { - if (@intFromEnum(lhs.*) != @intFromEnum(rhs.*)) return false; - inline for (bun.meta.EnumFields(PropertyId), std.meta.fields(PropertyId)) |enum_field, union_field| { - if (enum_field.value == @intFromEnum(lhs.*)) { - if (comptime union_field.type == css.VendorPrefix) { - return @field(lhs, union_field.name).eql(@field(rhs, union_field.name)); - } else { - return true; - } - } - } - unreachable; - } - - pub fn hash(this: *const PropertyId, hasher: *std.hash.Wyhash) void { - const tag = @intFromEnum(this.*); - hasher.update(std.mem.asBytes(&tag)); - } - - pub fn setPrefixesForTargets(this: *PropertyId, targets: Targets) void { - switch (this.*) { - ${Object.entries(property_defs) - .map(([name, meta]) => { - if (meta.unprefixed === false || meta.valid_prefixes === undefined) return `.${escapeIdent(name)} => {},`; - return `.${escapeIdent(name)} => |*x| { - x.* = targets.prefixes(x.*, Feature.${featureName(name)}); - }, - `; - }) - .join("\n")} - else => {}, - } - } -`; -} - -function generatePropertyIdImplPrefix(property_defs: Record): string { - return Object.entries(property_defs) - .map(([name, meta]) => { - if (meta.valid_prefixes === undefined) return `.${escapeIdent(name)} => VendorPrefix{},`; - return `.${escapeIdent(name)} => |p| p,`; - }) - .join("\n"); -} - -// TODO: todo_stuff.match_ignore_ascii_case -function generatePropertyIdImplFromNameAndPrefix(property_defs: Record): string { - return Object.entries(property_defs) - .map(([name, meta]) => { - if (name === "unparsed") return ""; - return `if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name1, "${name}")) { - const allowed_prefixes = ${constructVendorPrefix(meta.valid_prefixes)}; - if (allowed_prefixes.contains(pre)) return ${meta.valid_prefixes === undefined ? `.${escapeIdent(name)}` : `.{ .${escapeIdent(name)} = pre }`}; -} else `; - }) - .join("\n"); -} - -function constructVendorPrefix(prefixes: VendorPrefixes[] | undefined): string { - if (prefixes === undefined) return `VendorPrefix{ .none = true }`; - return `VendorPrefix{ ${[`.none = true`, ...prefixes.map(prefix => `.${prefix} = true`)].join(", ")} }`; -} - -function needsEscaping(name: string): boolean { - switch (name) { - case "align": - return true; - case "var": - default: { - return ["-", "(", ")", " ", ":", ";", ","].some(c => name.includes(c)); - } - } -} - -function escapeIdent(name: string): string { - if (needsEscaping(name)) { - return `@"${name}"`; - } - return name; -} - -generateCode({ - "background-color": { - ty: "CssColor", - }, - "background-image": { - ty: "SmallList(Image, 1)", - }, - "background-position-x": { - ty: "SmallList(css_values.position.HorizontalPosition, 1)", - }, - "background-position-y": { - ty: "SmallList(css_values.position.VerticalPosition, 1)", - }, - "background-position": { - ty: "SmallList(background.BackgroundPosition, 1)", - shorthand: true, - }, - "background-size": { - ty: "SmallList(background.BackgroundSize, 1)", - }, - "background-repeat": { - ty: "SmallList(background.BackgroundRepeat, 1)", - }, - "background-attachment": { - ty: "SmallList(background.BackgroundAttachment, 1)", - }, - "background-clip": { - ty: "SmallList(background.BackgroundClip, 1)", - valid_prefixes: ["webkit", "moz"], - }, - "background-origin": { - ty: "SmallList(background.BackgroundOrigin, 1)", - }, - background: { - ty: "SmallList(background.Background, 1)", - }, - "box-shadow": { - ty: "SmallList(box_shadow.BoxShadow, 1)", - valid_prefixes: ["webkit", "moz"], - }, - opacity: { - ty: "css.css_values.alpha.AlphaValue", - }, - color: { - ty: "CssColor", - }, - display: { - ty: "display.Display", - }, - visibility: { - ty: "display.Visibility", - }, - width: { - ty: "size.Size", - logical_group: { ty: "size", category: "physical" }, - }, - height: { - ty: "size.Size", - logical_group: { ty: "size", category: "physical" }, - }, - "min-width": { - ty: "size.Size", - logical_group: { ty: "min_size", category: "physical" }, - }, - "min-height": { - ty: "size.Size", - logical_group: { ty: "min_size", category: "physical" }, - }, - "max-width": { - ty: "size.MaxSize", - logical_group: { ty: "max_size", category: "physical" }, - }, - "max-height": { - ty: "size.MaxSize", - logical_group: { ty: "max_size", category: "physical" }, - }, - "block-size": { - ty: "size.Size", - logical_group: { ty: "size", category: "logical" }, - }, - "inline-size": { - ty: "size.Size", - logical_group: { ty: "size", category: "logical" }, - }, - "min-block-size": { - ty: "size.Size", - logical_group: { ty: "min_size", category: "logical" }, - }, - "min-inline-size": { - ty: "size.Size", - logical_group: { ty: "min_size", category: "logical" }, - }, - "max-block-size": { - ty: "size.MaxSize", - logical_group: { ty: "max_size", category: "logical" }, - }, - "max-inline-size": { - ty: "size.MaxSize", - logical_group: { ty: "max_size", category: "logical" }, - }, - "box-sizing": { - ty: "size.BoxSizing", - valid_prefixes: ["webkit", "moz"], - }, - "aspect-ratio": { - ty: "size.AspectRatio", - }, - overflow: { - ty: "overflow.Overflow", - shorthand: true, - }, - "overflow-x": { - ty: "overflow.OverflowKeyword", - }, - "overflow-y": { - ty: "overflow.OverflowKeyword", - }, - "text-overflow": { - ty: "overflow.TextOverflow", - valid_prefixes: ["o"], - }, - position: { - ty: "position.Position", - }, - top: { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "physical" }, - }, - bottom: { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "physical" }, - }, - left: { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "physical" }, - }, - right: { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "physical" }, - }, - "inset-block-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "logical" }, - }, - "inset-block-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "logical" }, - }, - "inset-inline-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "logical" }, - }, - "inset-inline-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "inset", category: "logical" }, - }, - "inset-block": { - ty: "margin_padding.InsetBlock", - shorthand: true, - }, - "inset-inline": { - ty: "margin_padding.InsetInline", - shorthand: true, - }, - inset: { - ty: "margin_padding.Inset", - shorthand: true, - }, - "border-spacing": { - ty: "css.css_values.size.Size2D(Length)", - }, - "border-top-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "physical" }, - }, - "border-bottom-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "physical" }, - }, - "border-left-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "physical" }, - }, - "border-right-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "physical" }, - }, - "border-block-start-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "logical" }, - }, - "border-block-end-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "logical" }, - }, - "border-inline-start-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "logical" }, - }, - "border-inline-end-color": { - ty: "CssColor", - logical_group: { ty: "border_color", category: "logical" }, - }, - "border-top-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "physical" }, - }, - "border-bottom-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "physical" }, - }, - "border-left-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "physical" }, - }, - "border-right-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "physical" }, - }, - "border-block-start-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "logical" }, - }, - "border-block-end-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "logical" }, - }, - "border-inline-start-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "logical" }, - }, - "border-inline-end-style": { - ty: "border.LineStyle", - logical_group: { ty: "border_style", category: "logical" }, - }, - "border-top-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "physical" }, - }, - "border-bottom-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "physical" }, - }, - "border-left-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "physical" }, - }, - "border-right-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "physical" }, - }, - "border-block-start-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "logical" }, - }, - "border-block-end-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "logical" }, - }, - "border-inline-start-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "logical" }, - }, - "border-inline-end-width": { - ty: "BorderSideWidth", - logical_group: { ty: "border_width", category: "logical" }, - }, - "border-top-left-radius": { - ty: "Size2D(LengthPercentage)", - valid_prefixes: ["webkit", "moz"], - logical_group: { ty: "border_radius", category: "physical" }, - }, - "border-top-right-radius": { - ty: "Size2D(LengthPercentage)", - valid_prefixes: ["webkit", "moz"], - logical_group: { ty: "border_radius", category: "physical" }, - }, - "border-bottom-left-radius": { - ty: "Size2D(LengthPercentage)", - valid_prefixes: ["webkit", "moz"], - logical_group: { ty: "border_radius", category: "physical" }, - }, - "border-bottom-right-radius": { - ty: "Size2D(LengthPercentage)", - valid_prefixes: ["webkit", "moz"], - logical_group: { ty: "border_radius", category: "physical" }, - }, - "border-start-start-radius": { - ty: "Size2D(LengthPercentage)", - logical_group: { ty: "border_radius", category: "logical" }, - }, - "border-start-end-radius": { - ty: "Size2D(LengthPercentage)", - logical_group: { ty: "border_radius", category: "logical" }, - }, - "border-end-start-radius": { - ty: "Size2D(LengthPercentage)", - logical_group: { ty: "border_radius", category: "logical" }, - }, - "border-end-end-radius": { - ty: "Size2D(LengthPercentage)", - logical_group: { ty: "border_radius", category: "logical" }, - }, - "border-radius": { - ty: "BorderRadius", - valid_prefixes: ["webkit", "moz"], - shorthand: true, - }, - "border-image-source": { - ty: "Image", - }, - "border-image-outset": { - ty: "Rect(LengthOrNumber)", - }, - "border-image-repeat": { - ty: "BorderImageRepeat", - }, - "border-image-width": { - ty: "Rect(BorderImageSideWidth)", - }, - "border-image-slice": { - ty: "BorderImageSlice", - }, - "border-image": { - ty: "BorderImage", - valid_prefixes: ["webkit", "moz", "o"], - shorthand: true, - }, - "border-color": { - ty: "BorderColor", - shorthand: true, - }, - "border-style": { - ty: "BorderStyle", - shorthand: true, - }, - "border-width": { - ty: "BorderWidth", - shorthand: true, - }, - "border-block-color": { - ty: "BorderBlockColor", - shorthand: true, - }, - "border-block-style": { - ty: "BorderBlockStyle", - shorthand: true, - }, - "border-block-width": { - ty: "BorderBlockWidth", - shorthand: true, - }, - "border-inline-color": { - ty: "BorderInlineColor", - shorthand: true, - }, - "border-inline-style": { - ty: "BorderInlineStyle", - shorthand: true, - }, - "border-inline-width": { - ty: "BorderInlineWidth", - shorthand: true, - }, - border: { - ty: "Border", - shorthand: true, - }, - "border-top": { - ty: "BorderTop", - shorthand: true, - }, - "border-bottom": { - ty: "BorderBottom", - shorthand: true, - }, - "border-left": { - ty: "BorderLeft", - shorthand: true, - }, - "border-right": { - ty: "BorderRight", - shorthand: true, - }, - "border-block": { - ty: "BorderBlock", - shorthand: true, - }, - "border-block-start": { - ty: "BorderBlockStart", - shorthand: true, - }, - "border-block-end": { - ty: "BorderBlockEnd", - shorthand: true, - }, - "border-inline": { - ty: "BorderInline", - shorthand: true, - }, - "border-inline-start": { - ty: "BorderInlineStart", - shorthand: true, - }, - "border-inline-end": { - ty: "BorderInlineEnd", - shorthand: true, - }, - outline: { - ty: "Outline", - shorthand: true, - }, - "outline-color": { - ty: "CssColor", - }, - "outline-style": { - ty: "OutlineStyle", - }, - "outline-width": { - ty: "BorderSideWidth", - }, - "flex-direction": { - ty: "FlexDirection", - valid_prefixes: ["webkit", "ms"], - }, - "flex-wrap": { - ty: "FlexWrap", - valid_prefixes: ["webkit", "ms"], - }, - "flex-flow": { - ty: "FlexFlow", - valid_prefixes: ["webkit", "ms"], - shorthand: true, - }, - "flex-grow": { - ty: "CSSNumber", - valid_prefixes: ["webkit"], - }, - "flex-shrink": { - ty: "CSSNumber", - valid_prefixes: ["webkit"], - }, - "flex-basis": { - ty: "LengthPercentageOrAuto", - valid_prefixes: ["webkit"], - }, - flex: { - ty: "Flex", - valid_prefixes: ["webkit", "ms"], - shorthand: true, - }, - order: { - ty: "CSSInteger", - valid_prefixes: ["webkit"], - }, - "align-content": { - ty: "AlignContent", - valid_prefixes: ["webkit"], - }, - "justify-content": { - ty: "JustifyContent", - valid_prefixes: ["webkit"], - }, - "place-content": { - ty: "PlaceContent", - shorthand: true, - }, - "align-self": { - ty: "AlignSelf", - valid_prefixes: ["webkit"], - }, - "justify-self": { - ty: "JustifySelf", - }, - "place-self": { - ty: "PlaceSelf", - shorthand: true, - }, - "align-items": { - ty: "AlignItems", - valid_prefixes: ["webkit"], - }, - "justify-items": { - ty: "JustifyItems", - }, - "place-items": { - ty: "PlaceItems", - shorthand: true, - }, - "row-gap": { - ty: "GapValue", - }, - "column-gap": { - ty: "GapValue", - }, - gap: { - ty: "Gap", - shorthand: true, - }, - "box-orient": { - ty: "BoxOrient", - valid_prefixes: ["webkit", "moz"], - unprefixed: false, - }, - "box-direction": { - ty: "BoxDirection", - valid_prefixes: ["webkit", "moz"], - unprefixed: false, - }, - "box-ordinal-group": { - ty: "CSSInteger", - valid_prefixes: ["webkit", "moz"], - unprefixed: false, - }, - "box-align": { - ty: "BoxAlign", - valid_prefixes: ["webkit", "moz"], - unprefixed: false, - }, - "box-flex": { - ty: "CSSNumber", - valid_prefixes: ["webkit", "moz"], - unprefixed: false, - }, - "box-flex-group": { - ty: "CSSInteger", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - "box-pack": { - ty: "BoxPack", - valid_prefixes: ["webkit", "moz"], - unprefixed: false, - }, - "box-lines": { - ty: "BoxLines", - valid_prefixes: ["webkit", "moz"], - unprefixed: false, - }, - "flex-pack": { - ty: "FlexPack", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "flex-order": { - ty: "CSSInteger", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "flex-align": { - ty: "BoxAlign", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "flex-item-align": { - ty: "FlexItemAlign", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "flex-line-pack": { - ty: "FlexLinePack", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "flex-positive": { - ty: "CSSNumber", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "flex-negative": { - ty: "CSSNumber", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "flex-preferred-size": { - ty: "LengthPercentageOrAuto", - valid_prefixes: ["ms"], - unprefixed: false, - }, - "margin-top": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "physical" }, - }, - "margin-bottom": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "physical" }, - }, - "margin-left": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "physical" }, - }, - "margin-right": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "physical" }, - eval_branch_quota: 5000, - }, - "margin-block-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "logical" }, - eval_branch_quota: 5000, - }, - "margin-block-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "logical" }, - }, - "margin-inline-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "logical" }, - }, - "margin-inline-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "margin", category: "logical" }, - }, - "margin-block": { - ty: "MarginBlock", - shorthand: true, - }, - "margin-inline": { - ty: "MarginInline", - shorthand: true, - }, - margin: { - ty: "Margin", - shorthand: true, - eval_branch_quota: 5000, - }, - "padding-top": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "physical" }, - }, - "padding-bottom": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "physical" }, - }, - "padding-left": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "physical" }, - }, - "padding-right": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "physical" }, - }, - "padding-block-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "logical" }, - }, - "padding-block-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "logical" }, - }, - "padding-inline-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "logical" }, - }, - "padding-inline-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "padding", category: "logical" }, - }, - "padding-block": { - ty: "PaddingBlock", - shorthand: true, - }, - "padding-inline": { - ty: "PaddingInline", - shorthand: true, - }, - padding: { - ty: "Padding", - shorthand: true, - }, - "scroll-margin-top": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "physical" }, - }, - "scroll-margin-bottom": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "physical" }, - }, - "scroll-margin-left": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "physical" }, - }, - "scroll-margin-right": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "physical" }, - }, - "scroll-margin-block-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "logical" }, - }, - "scroll-margin-block-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "logical" }, - }, - "scroll-margin-inline-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "logical" }, - }, - "scroll-margin-inline-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_margin", category: "logical" }, - }, - "scroll-margin-block": { - ty: "ScrollMarginBlock", - shorthand: true, - }, - "scroll-margin-inline": { - ty: "ScrollMarginInline", - shorthand: true, - }, - "scroll-margin": { - ty: "ScrollMargin", - shorthand: true, - }, - "scroll-padding-top": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "physical" }, - }, - "scroll-padding-bottom": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "physical" }, - }, - "scroll-padding-left": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "physical" }, - }, - "scroll-padding-right": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "physical" }, - }, - "scroll-padding-block-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "logical" }, - }, - "scroll-padding-block-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "logical" }, - }, - "scroll-padding-inline-start": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "logical" }, - }, - "scroll-padding-inline-end": { - ty: "LengthPercentageOrAuto", - logical_group: { ty: "scroll_padding", category: "logical" }, - }, - "scroll-padding-block": { - ty: "ScrollPaddingBlock", - shorthand: true, - }, - "scroll-padding-inline": { - ty: "ScrollPaddingInline", - shorthand: true, - }, - "scroll-padding": { - ty: "ScrollPadding", - shorthand: true, - }, - "font-weight": { - ty: "FontWeight", - }, - "font-size": { - ty: "FontSize", - }, - "font-stretch": { - ty: "FontStretch", - }, - "font-family": { - ty: "BabyList(FontFamily)", - }, - "font-style": { - ty: "FontStyle", - }, - "font-variant-caps": { - ty: "FontVariantCaps", - }, - "line-height": { - ty: "LineHeight", - }, - font: { - ty: "Font", - shorthand: true, - }, - // "vertical-align": { - // ty: "VerticalAlign", - // }, - // "font-palette": { - // ty: "DashedIdentReference", - // }, - "transition-property": { - ty: "SmallList(PropertyId, 1)", - valid_prefixes: ["webkit", "moz", "ms"], - }, - "transition-duration": { - ty: "SmallList(Time, 1)", - valid_prefixes: ["webkit", "moz", "ms"], - }, - "transition-delay": { - ty: "SmallList(Time, 1)", - valid_prefixes: ["webkit", "moz", "ms"], - }, - "transition-timing-function": { - ty: "SmallList(EasingFunction, 1)", - valid_prefixes: ["webkit", "moz", "ms"], - }, - transition: { - ty: "SmallList(Transition, 1)", - valid_prefixes: ["webkit", "moz", "ms"], - shorthand: true, - }, - // "animation-name": { - // ty: "AnimationNameList", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-duration": { - // ty: "SmallList(Time, 1)", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-timing-function": { - // ty: "SmallList(EasingFunction, 1)", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-iteration-count": { - // ty: "SmallList(AnimationIterationCount, 1)", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-direction": { - // ty: "SmallList(AnimationDirection, 1)", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-play-state": { - // ty: "SmallList(AnimationPlayState, 1)", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-delay": { - // ty: "SmallList(Time, 1)", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-fill-mode": { - // ty: "SmallList(AnimationFillMode, 1)", - // valid_prefixes: ["webkit", "moz", "o"], - // }, - // "animation-composition": { - // ty: "SmallList(AnimationComposition, 1)", - // }, - // "animation-timeline": { - // ty: "SmallList(AnimationTimeline, 1)", - // }, - // "animation-range-start": { - // ty: "SmallList(AnimationRangeStart, 1)", - // }, - // "animation-range-end": { - // ty: "SmallList(AnimationRangeEnd, 1)", - // }, - // "animation-range": { - // ty: "SmallList(AnimationRange, 1)", - // }, - // animation: { - // ty: "AnimationList", - // valid_prefixes: ["webkit", "moz", "o"], - // shorthand: true, - // }, - transform: { - ty: "TransformList", - valid_prefixes: ["webkit", "moz", "ms", "o"], - }, - "transform-origin": { - ty: "Position", - valid_prefixes: ["webkit", "moz", "ms", "o"], - }, - "transform-style": { - ty: "TransformStyle", - valid_prefixes: ["webkit", "moz"], - }, - "transform-box": { - ty: "TransformBox", - }, - "backface-visibility": { - ty: "BackfaceVisibility", - valid_prefixes: ["webkit", "moz"], - }, - perspective: { - ty: "Perspective", - valid_prefixes: ["webkit", "moz"], - }, - "perspective-origin": { - ty: "Position", - valid_prefixes: ["webkit", "moz"], - }, - translate: { - ty: "Translate", - }, - rotate: { - ty: "Rotate", - }, - scale: { - ty: "Scale", - }, - // "text-transform": { - // ty: "TextTransform", - // }, - // "white-space": { - // ty: "WhiteSpace", - // }, - // "tab-size": { - // ty: "LengthOrNumber", - // valid_prefixes: ["moz", "o"], - // }, - // "word-break": { - // ty: "WordBreak", - // }, - // "line-break": { - // ty: "LineBreak", - // }, - // hyphens: { - // ty: "Hyphens", - // valid_prefixes: ["webkit", "moz", "ms"], - // }, - // "overflow-wrap": { - // ty: "OverflowWrap", - // }, - // "word-wrap": { - // ty: "OverflowWrap", - // }, - // "text-align": { - // ty: "TextAlign", - // }, - // "text-align-last": { - // ty: "TextAlignLast", - // valid_prefixes: ["moz"], - // }, - // "text-justify": { - // ty: "TextJustify", - // }, - // "word-spacing": { - // ty: "Spacing", - // }, - // "letter-spacing": { - // ty: "Spacing", - // }, - // "text-indent": { - // ty: "TextIndent", - // }, - // "text-decoration-line": { - // ty: "TextDecorationLine", - // valid_prefixes: ["webkit", "moz"], - // }, - // "text-decoration-style": { - // ty: "TextDecorationStyle", - // valid_prefixes: ["webkit", "moz"], - // }, - "text-decoration-color": { - ty: "CssColor", - valid_prefixes: ["webkit", "moz"], - }, - // "text-decoration-thickness": { - // ty: "TextDecorationThickness", - // }, - // "text-decoration": { - // ty: "TextDecoration", - // valid_prefixes: ["webkit", "moz"], - // shorthand: true, - // }, - // "text-decoration-skip-ink": { - // ty: "TextDecorationSkipInk", - // valid_prefixes: ["webkit"], - // }, - // "text-emphasis-style": { - // ty: "TextEmphasisStyle", - // valid_prefixes: ["webkit"], - // }, - "text-emphasis-color": { - ty: "CssColor", - valid_prefixes: ["webkit"], - }, - // "text-emphasis": { - // ty: "TextEmphasis", - // valid_prefixes: ["webkit"], - // shorthand: true, - // }, - // "text-emphasis-position": { - // ty: "TextEmphasisPosition", - // valid_prefixes: ["webkit"], - // }, - "text-shadow": { - ty: "SmallList(TextShadow, 1)", - }, - // "text-size-adjust": { - // ty: "TextSizeAdjust", - // valid_prefixes: ["webkit", "moz", "ms"], - // }, - direction: { - ty: "Direction", - }, - // "unicode-bidi": { - // ty: "UnicodeBidi", - // }, - // "box-decoration-break": { - // ty: "BoxDecorationBreak", - // valid_prefixes: ["webkit"], - // }, - // resize: { - // ty: "Resize", - // }, - // cursor: { - // ty: "Cursor", - // }, - // TODO: Hello future Zack, if you uncomment this, remember to uncomment the corresponding value in FallbackHandler in prefix_handler.rs :) - // "caret-color": { - // ty: "ColorOrAuto", - // }, - // "caret-shape": { - // ty: "CaretShape", - // }, - // TODO: Hello future Zack, if you uncomment this, remember to uncomment the corresponding value in FallbackHandler in prefix_handler.rs :) - // caret: { - // ty: "Caret", - // shorthand: true, - // }, - // "user-select": { - // ty: "UserSelect", - // valid_prefixes: ["webkit", "moz", "ms"], - // }, - // "accent-color": { - // ty: "ColorOrAuto", - // }, - // appearance: { - // ty: "Appearance", - // valid_prefixes: ["webkit", "moz", "ms"], - // }, - // "list-style-type": { - // ty: "ListStyleType", - // }, - // "list-style-image": { - // ty: "Image", - // }, - // "list-style-position": { - // ty: "ListStylePosition", - // }, - // "list-style": { - // ty: "ListStyle", - // shorthand: true, - // }, - // "marker-side": { - // ty: "MarkerSide", - // }, - composes: { - ty: "Composes", - conditional: { css_modules: true }, - parse_dont_make_unparsed: true, - }, - // TODO: Hello future Zack, if you uncomment this, remember to uncomment the corresponding value in FallbackHandler in prefix_handler.rs :) - // fill: { - // ty: "SVGPaint", - // }, - // "fill-rule": { - // ty: "FillRule", - // }, - // "fill-opacity": { - // ty: "AlphaValue", - // }, - // TODO: Hello future Zack, if you uncomment this, remember to uncomment the corresponding value in FallbackHandler in prefix_handler.rs :) - // stroke: { - // ty: "SVGPaint", - // }, - // "stroke-opacity": { - // ty: "AlphaValue", - // }, - // "stroke-width": { - // ty: "LengthPercentage", - // }, - // "stroke-linecap": { - // ty: "StrokeLinecap", - // }, - // "stroke-linejoin": { - // ty: "StrokeLinejoin", - // }, - // "stroke-miterlimit": { - // ty: "CSSNumber", - // }, - // "stroke-dasharray": { - // ty: "StrokeDasharray", - // }, - // "stroke-dashoffset": { - // ty: "LengthPercentage", - // }, - // "marker-start": { - // ty: "Marker", - // }, - // "marker-mid": { - // ty: "Marker", - // }, - // "marker-end": { - // ty: "Marker", - // }, - // marker: { - // ty: "Marker", - // }, - // "color-interpolation": { - // ty: "ColorInterpolation", - // }, - // "color-interpolation-filters": { - // ty: "ColorInterpolation", - // }, - // "color-rendering": { - // ty: "ColorRendering", - // }, - // "shape-rendering": { - // ty: "ShapeRendering", - // }, - // "text-rendering": { - // ty: "TextRendering", - // }, - // "image-rendering": { - // ty: "ImageRendering", - // }, - // "clip-path": { - // ty: "ClipPath", - // valid_prefixes: ["webkit"], - // }, - // "clip-rule": { - // ty: "FillRule", - // }, - "mask-image": { - ty: "SmallList(Image, 1)", - valid_prefixes: ["webkit"], - }, - "mask-mode": { - ty: "SmallList(MaskMode, 1)", - }, - "mask-repeat": { - ty: "SmallList(BackgroundRepeat, 1)", - valid_prefixes: ["webkit"], - }, - "mask-position-x": { - ty: "SmallList(HorizontalPosition, 1)", - }, - "mask-position-y": { - ty: "SmallList(VerticalPosition, 1)", - }, - "mask-position": { - ty: "SmallList(Position, 1)", - valid_prefixes: ["webkit"], - }, - "mask-clip": { - ty: "SmallList(MaskClip, 1)", - valid_prefixes: ["webkit"], - eval_branch_quota: 5000, - }, - "mask-origin": { - ty: "SmallList(GeometryBox, 1)", - valid_prefixes: ["webkit"], - }, - "mask-size": { - ty: "SmallList(BackgroundSize, 1)", - valid_prefixes: ["webkit"], - }, - "mask-composite": { - ty: "SmallList(MaskComposite, 1)", - }, - "mask-type": { - ty: "MaskType", - }, - mask: { - ty: "SmallList(Mask, 1)", - valid_prefixes: ["webkit"], - shorthand: true, - }, - "mask-border-source": { - ty: "Image", - }, - "mask-border-mode": { - ty: "MaskBorderMode", - }, - "mask-border-slice": { - ty: "BorderImageSlice", - }, - "mask-border-width": { - ty: "Rect(BorderImageSideWidth)", - }, - "mask-border-outset": { - ty: "Rect(LengthOrNumber)", - }, - "mask-border-repeat": { - ty: "BorderImageRepeat", - }, - "mask-border": { - ty: "MaskBorder", - shorthand: true, - }, - // WebKit additions - "-webkit-mask-composite": { - ty: "SmallList(WebKitMaskComposite, 1)", - }, - "mask-source-type": { - ty: "SmallList(WebKitMaskSourceType, 1)", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - "mask-box-image": { - ty: "BorderImage", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - "mask-box-image-source": { - ty: "Image", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - "mask-box-image-slice": { - ty: "BorderImageSlice", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - "mask-box-image-width": { - ty: "Rect(BorderImageSideWidth)", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - "mask-box-image-outset": { - ty: "Rect(LengthOrNumber)", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - "mask-box-image-repeat": { - ty: "BorderImageRepeat", - valid_prefixes: ["webkit"], - unprefixed: false, - }, - - // TODO: Hello future Zack, if you uncomment this, remember to uncomment the corresponding value in FallbackHandler in prefix_handler.rs :) - // filter: { - // ty: "FilterList", - // valid_prefixes: ["webkit"], - // }, - // TODO: Hello future Zack, if you uncomment this, remember to uncomment the corresponding value in FallbackHandler in prefix_handler.rs :) - // "backdrop-filter": { - // ty: "FilterList", - // valid_prefixes: ["webkit"], - // }, - // "z-index": { - // ty: "position.ZIndex", - // }, - // "container-type": { - // ty: "ContainerType", - // }, - // "container-name": { - // ty: "ContainerNameList", - // }, - // container: { - // ty: "Container", - // shorthand: true, - // }, - // "view-transition-name": { - // ty: "CustomIdent", - // }, - "color-scheme": { - ty: "ColorScheme", - }, -}); - -function prelude() { - return /* zig */ `const std = @import("std"); -const bun = @import("bun"); -const Allocator = std.mem.Allocator; - -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const VendorPrefix = css.VendorPrefix; - -const properties_impl = @import("./properties_impl.zig"); - -const CSSWideKeyword = css.css_properties.CSSWideKeyword; -const UnparsedProperty = css.css_properties.custom.UnparsedProperty; -const CustomProperty = css.css_properties.custom.CustomProperty; -const Targets = css.targets.Targets; -const Feature = css.prefixes.Feature; - -const ColorScheme = css.css_properties.ui.ColorScheme; - -const TransformList = css.css_properties.transform.TransformList; -const TransformStyle = css.css_properties.transform.TransformStyle; -const TransformBox = css.css_properties.transform.TransformBox; -const BackfaceVisibility = css.css_properties.transform.BackfaceVisibility; -const Perspective = css.css_properties.transform.Perspective; -const Translate = css.css_properties.transform.Translate; -const Rotate = css.css_properties.transform.Rotate; -const Scale = css.css_properties.transform.Scale; - -const css_values = css.css_values; -const CssColor = css.css_values.color.CssColor; -const Image = css.css_values.image.Image; -const Length = css.css_values.length.Length; -const LengthValue = css.css_values.length.LengthValue; -const LengthPercentage = css_values.length.LengthPercentage; -const LengthPercentageOrAuto = css_values.length.LengthPercentageOrAuto; -const PropertyCategory = css.PropertyCategory; -const LogicalGroup = css.LogicalGroup; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const CSSInteger = css.css_values.number.CSSInteger; -const CSSIntegerFns = css.css_values.number.CSSIntegerFns; -const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage; -const Percentage = css.css_values.percentage.Percentage; -const Angle = css.css_values.angle.Angle; -const DashedIdentReference = css.css_values.ident.DashedIdentReference; -const Time = css.css_values.time.Time; -const EasingFunction = css.css_values.easing.EasingFunction; -const CustomIdent = css.css_values.ident.CustomIdent; -const CSSString = css.css_values.string.CSSString; -const DashedIdent = css.css_values.ident.DashedIdent; -const Url = css.css_values.url.Url; -const CustomIdentList = css.css_values.ident.CustomIdentList; -const Location = css.Location; -const HorizontalPosition = css.css_values.position.HorizontalPosition; -const VerticalPosition = css.css_values.position.VerticalPosition; -const ContainerName = css.css_rules.container.ContainerName; - -pub const font = css.css_properties.font; -const border = css.css_properties.border; -const border_radius = css.css_properties.border_radius; -const border_image = css.css_properties.border_image; -const outline = css.css_properties.outline; -const flex = css.css_properties.flex; -const @"align" = css.css_properties.@"align"; -const margin_padding = css.css_properties.margin_padding; -const transition = css.css_properties.transition; -const animation = css.css_properties.animation; -const transform = css.css_properties.transform; -const text = css.css_properties.text; -const ui = css.css_properties.ui; -const list = css.css_properties.list; -const css_modules = css.css_properties.css_modules; -const svg = css.css_properties.svg; -const shape = css.css_properties.shape; -const masking = css.css_properties.masking; -const background = css.css_properties.background; -const effects = css.css_properties.effects; -const contain = css.css_properties.contain; -const custom = css.css_properties.custom; -const position = css.css_properties.position; -const box_shadow = css.css_properties.box_shadow; -const size = css.css_properties.size; -const overflow = css.css_properties.overflow; - -const BorderSideWidth = border.BorderSideWidth; -const Size2D = css_values.size.Size2D; -const BorderRadius = border_radius.BorderRadius; -const Rect = css_values.rect.Rect; -const LengthOrNumber = css_values.length.LengthOrNumber; -const BorderImageRepeat = border_image.BorderImageRepeat; -const BorderImageSideWidth = border_image.BorderImageSideWidth; -const BorderImageSlice = border_image.BorderImageSlice; -const BorderImage = border_image.BorderImage; -const BorderColor = border.BorderColor; -const BorderStyle = border.BorderStyle; -const BorderWidth = border.BorderWidth; -const BorderBlockColor = border.BorderBlockColor; -const BorderBlockStyle = border.BorderBlockStyle; -const BorderBlockWidth = border.BorderBlockWidth; -const BorderInlineColor = border.BorderInlineColor; -const BorderInlineStyle = border.BorderInlineStyle; -const BorderInlineWidth = border.BorderInlineWidth; -const Border = border.Border; -const BorderTop = border.BorderTop; -const BorderRight = border.BorderRight; -const BorderLeft = border.BorderLeft; -const BorderBottom = border.BorderBottom; -const BorderBlockStart = border.BorderBlockStart; -const BorderBlockEnd = border.BorderBlockEnd; -const BorderInlineStart = border.BorderInlineStart; -const BorderInlineEnd = border.BorderInlineEnd; -const BorderBlock = border.BorderBlock; -const BorderInline = border.BorderInline; -const Outline = outline.Outline; -const OutlineStyle = outline.OutlineStyle; -const FlexDirection = flex.FlexDirection; -const FlexWrap = flex.FlexWrap; -const FlexFlow = flex.FlexFlow; -const Flex = flex.Flex; -const BoxOrient = flex.BoxOrient; -const BoxDirection = flex.BoxDirection; -const BoxAlign = flex.BoxAlign; -const BoxPack = flex.BoxPack; -const BoxLines = flex.BoxLines; -const FlexPack = flex.FlexPack; -const FlexItemAlign = flex.FlexItemAlign; -const FlexLinePack = flex.FlexLinePack; -const AlignContent = @"align".AlignContent; -const JustifyContent = @"align".JustifyContent; -const PlaceContent = @"align".PlaceContent; -const AlignSelf = @"align".AlignSelf; -const JustifySelf = @"align".JustifySelf; -const PlaceSelf = @"align".PlaceSelf; -const AlignItems = @"align".AlignItems; -const JustifyItems = @"align".JustifyItems; -const PlaceItems = @"align".PlaceItems; -const GapValue = @"align".GapValue; -const Gap = @"align".Gap; -const MarginBlock = margin_padding.MarginBlock; -const Margin = margin_padding.Margin; -const MarginInline = margin_padding.MarginInline; -const PaddingBlock = margin_padding.PaddingBlock; -const PaddingInline = margin_padding.PaddingInline; -const Padding = margin_padding.Padding; -const ScrollMarginBlock = margin_padding.ScrollMarginBlock; -const ScrollMarginInline = margin_padding.ScrollMarginInline; -const ScrollMargin = margin_padding.ScrollMargin; -const ScrollPaddingBlock = margin_padding.ScrollPaddingBlock; -const ScrollPaddingInline = margin_padding.ScrollPaddingInline; -const ScrollPadding = margin_padding.ScrollPadding; -const FontWeight = font.FontWeight; -const FontSize = font.FontSize; -const FontStretch = font.FontStretch; -const FontFamily = font.FontFamily; -const FontStyle = font.FontStyle; -const FontVariantCaps = font.FontVariantCaps; -const LineHeight = font.LineHeight; -const Font = font.Font; -// const VerticalAlign = font.VerticalAlign; -const Transition = transition.Transition; -// const AnimationNameList = animation.AnimationNameList; -// const AnimationList = animation.AnimationList; -// const AnimationIterationCount = animation.AnimationIterationCount; -// const AnimationDirection = animation.AnimationDirection; -// const AnimationPlayState = animation.AnimationPlayState; -// const AnimationFillMode = animation.AnimationFillMode; -// const AnimationComposition = animation.AnimationComposition; -// const AnimationTimeline = animation.AnimationTimeline; -// const AnimationRangeStart = animation.AnimationRangeStart; -// const AnimationRangeEnd = animation.AnimationRangeEnd; -// const AnimationRange = animation.AnimationRange; -// const TransformList = transform.TransformList; -// const TransformStyle = transform.TransformStyle; -// const TransformBox = transform.TransformBox; -// const BackfaceVisibility = transform.BackfaceVisibility; -// const Perspective = transform.Perspective; -// const Translate = transform.Translate; -// const Rotate = transform.Rotate; -// const Scale = transform.Scale; -// const TextTransform = text.TextTransform; -// const WhiteSpace = text.WhiteSpace; -// const WordBreak = text.WordBreak; -// const LineBreak = text.LineBreak; -// const Hyphens = text.Hyphens; -// const OverflowWrap = text.OverflowWrap; -// const TextAlign = text.TextAlign; -// const TextIndent = text.TextIndent; -// const Spacing = text.Spacing; -// const TextJustify = text.TextJustify; -// const TextAlignLast = text.TextAlignLast; -// const TextDecorationLine = text.TextDecorationLine; -// const TextDecorationStyle = text.TextDecorationStyle; -// const TextDecorationThickness = text.TextDecorationThickness; -// const TextDecoration = text.TextDecoration; -// const TextDecorationSkipInk = text.TextDecorationSkipInk; -// const TextEmphasisStyle = text.TextEmphasisStyle; -// const TextEmphasis = text.TextEmphasis; -// const TextEmphasisPositionVertical = text.TextEmphasisPositionVertical; -// const TextEmphasisPositionHorizontal = text.TextEmphasisPositionHorizontal; -// const TextEmphasisPosition = text.TextEmphasisPosition; -const TextShadow = text.TextShadow; -// const TextSizeAdjust = text.TextSizeAdjust; -const Direction = text.Direction; -// const UnicodeBidi = text.UnicodeBidi; -// const BoxDecorationBreak = text.BoxDecorationBreak; -// const Resize = ui.Resize; -// const Cursor = ui.Cursor; -// const ColorOrAuto = ui.ColorOrAuto; -// const CaretShape = ui.CaretShape; -// const Caret = ui.Caret; -// const UserSelect = ui.UserSelect; -// const Appearance = ui.Appearance; -// const ColorScheme = ui.ColorScheme; -// const ListStyleType = list.ListStyleType; -// const ListStylePosition = list.ListStylePosition; -// const ListStyle = list.ListStyle; -// const MarkerSide = list.MarkerSide; -const Composes = css_modules.Composes; -// const SVGPaint = svg.SVGPaint; -// const FillRule = shape.FillRule; -// const AlphaValue = shape.AlphaValue; -// const StrokeLinecap = svg.StrokeLinecap; -// const StrokeLinejoin = svg.StrokeLinejoin; -// const StrokeDasharray = svg.StrokeDasharray; -// const Marker = svg.Marker; -// const ColorInterpolation = svg.ColorInterpolation; -// const ColorRendering = svg.ColorRendering; -// const ShapeRendering = svg.ShapeRendering; -// const TextRendering = svg.TextRendering; -// const ImageRendering = svg.ImageRendering; -const ClipPath = masking.ClipPath; -const MaskMode = masking.MaskMode; -const MaskClip = masking.MaskClip; -const GeometryBox = masking.GeometryBox; -const MaskComposite = masking.MaskComposite; -const MaskType = masking.MaskType; -const Mask = masking.Mask; -const MaskBorderMode = masking.MaskBorderMode; -const MaskBorder = masking.MaskBorder; -const WebKitMaskComposite = masking.WebKitMaskComposite; -const WebKitMaskSourceType = masking.WebKitMaskSourceType; -const BackgroundRepeat = background.BackgroundRepeat; -const BackgroundSize = background.BackgroundSize; -// const FilterList = effects.FilterList; -// const ContainerType = contain.ContainerType; -// const Container = contain.Container; -// const ContainerNameList = contain.ContainerNameList; -const CustomPropertyName = custom.CustomPropertyName; -const display = css.css_properties.display; - -const Position = position.Position; - -const Result = css.Result; - -const BabyList = bun.BabyList; -const ArrayList = std.ArrayListUnmanaged; -const SmallList = css.SmallList; - -`; -} - -function featureName(name: string): string { - return name.replaceAll("-", "_"); -} diff --git a/src/css/properties/grid.zig b/src/css/properties/grid.zig deleted file mode 100644 index 2bc9cfdd2589..000000000000 --- a/src/css/properties/grid.zig +++ /dev/null @@ -1,540 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const LengthPercentage = css.css_values.length.LengthPercentage; -const CustomIdent = css.css_values.ident.CustomIdent; -const CSSNumber = css.css_values.number.CSSNumber; -const CustomIdentList = css.css_values.ident.CustomIdentList; -const CSSInteger = css.css_values.number.CSSInteger; - -/// A [track sizing](https://drafts.csswg.org/css-grid-2/#track-sizing) value -/// for the `grid-template-rows` and `grid-template-columns` properties. -pub const TrackSizing = union(enum) { - /// No explicit grid tracks. - none, - /// A list of grid tracks. - tracklist: TrackList, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; -}; - -/// A [``](https://drafts.csswg.org/css-grid-2/#typedef-track-list) value, -/// as used in the `grid-template-rows` and `grid-template-columns` properties. -/// -/// See [TrackSizing](TrackSizing). -pub const TrackList = struct { - /// A list of line names. - line_names: bun.BabyList(CustomIdentList), - /// A list of grid track items. - items: bun.BabyList(TrackListItem), - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var line_names = BabyList(CustomIdentList){}; - var items = BabyList(TrackListItem){}; - - while (true) { - const line_name = input.tryParse(parseLineNames, .{}).asValue() orelse CustomIdentList{}; - bun.handleOom(line_names.append(input.allocator(), line_name)); - - if (input.tryParse(TrackSize.parse, .{}).asValue()) |track_size| { - // TODO: error handling - bun.handleOom(items.append(.{ .track_size = track_size })); - } else if (input.tryParse(TrackRepeat.parse, .{}).asValue()) |repeat| { - // TODO: error handling - bun.handleOom(items.append(.{ .track_repeat = repeat })); - } else { - break; - } - } - - if (items.len == 0) { - return .{ .err = input.newCustomError(.invalid_declaration) }; - } - - return .{ .result = .{ - .line_names = line_names, - .items = items, - } }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - var items_index = 0; - var first = true; - - for (this.line_names.sliceConst()) |*names| { - if (!names.isEmpty()) try serializeLineNames(names, dest); - - if (items_index < this.items.len) { - const item = this.items.at(items_index); - items_index += 1; - - // Whitespace is required if there are no line names. - if (!names.isEmpty()) { - try dest.whitespace(); - } else if (!first) { - try dest.writeChar(' '); - } - - switch (item.*) { - .track_repeat => |*repeat| try repeat.toCss(dest), - .track_size => |*size| try size.toCss(dest), - } - } - - first = false; - } - } -}; - -/// Either a track size or `repeat()` function. -/// -/// See [TrackList](TrackList). -pub const TrackListItem = union(enum) { - /// A track size. - track_size: TrackSize, - /// A `repeat()` function. - track_repeat: TrackRepeat, -}; - -/// A [track size](https://drafts.csswg.org/css-grid-2/#typedef-track-size) value. -/// -/// See [TrackList](TrackList). -pub const TrackSize = union(enum) { - /// An explicit track breadth. - track_breadth: TrackBreadth, - /// The `minmax()` function. - min_max: struct { - /// The minimum value. - min: TrackBreadth, - /// The maximum value. - max: TrackBreadth, - }, - /// The `fit-content()` function. - fit_content: LengthPercentage, - - pub fn default() @This() { - return .{ .track_breadth = TrackBreadth.auto }; - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(TrackBreadth.parse, .{}).asValue()) |breadth| { - return .{ .result = .{ .track_breadth = breadth } }; - } - - if (input.tryParse(css.Parser.expectFunctionMatching, .{"minmax"}).isOk()) { - return input.parseNestedBlock(struct { - pub fn parse(i: *css.Parser) css.Result(TrackSize) { - const min = switch (TrackBreadth.parseInternal(i, false)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - return .{ - .result = .{ .min_max = .{ .min = min, .max = switch (TrackBreadth.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }, - }; - } - }.parseFn); - } - - if (input.expectFunctionMatching("fit-content").asErr()) |e| return .{ .err = e }; - - const len = switch (input.parseNestedBlock(css.voidWrap(LengthPercentage, LengthPercentage.parse))) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = .{ .fit_content = len } }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - switch (this.*) { - .track_breadth => |breadth| try breadth.toCss(dest), - .min_max => |mm| { - try dest.writeStr("minmax("); - try mm.min.toCss(dest); - try dest.delim(',', false); - try mm.max.toCss(dest); - try dest.writeChar(')'); - }, - .fit_content => |len| { - try dest.writeStr("fit-content("); - try len.toCss(dest); - try dest.writeChar(')'); - }, - } - } -}; - -pub const TrackSizeList = struct { - v: SmallList(TrackSize, 1) = .{}, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var res = SmallList(TrackSize, 1){}; - while (input.tryParse(TrackSize.parse, .{}).asValue()) |size| { - bun.handleOom(res.append(input.allocator(), size)); - } - - if (res.len() == 1 and res.at(0).eql(&TrackSize.default())) { - res.clearRetainingCapacity(); - } - - return .{ .result = .{ .v = res } }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - if (this.v.len() == 0) { - try dest.writeStr("auto"); - return; - } - - var first = true; - for (this.v.slice()) |item| { - if (first) { - first = false; - } else { - try dest.writeChar(' '); - } - try item.toCss(dest); - } - } -}; - -/// A [track breadth](https://drafts.csswg.org/css-grid-2/#typedef-track-breadth) value. -/// -/// See [TrackSize](TrackSize). -pub const TrackBreadth = union(enum) { - /// An explicit length. - length: LengthPercentage, - /// A flex factor. - flex: CSSNumber, - /// The `min-content` keyword. - min_content, - /// The `max-content` keyword. - max_content, - /// The `auto` keyword. - auto, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - return TrackBreadth.parseInternal(input, true); - } - - fn parseInternal(input: *css.Parser, allow_flex: bool) css.Result(@This()) { - if (input.tryParse(LengthPercentage.parse, .{}).asValue()) |len| { - return .{ .result = .{ .length = len } }; - } - - if (allow_flex) { - if (input.tryParse(TrackBreadth.parseFlex, .{}).asValue()) |flex| { - return .{ .result = .{ .flex = flex } }; - } - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "auto")) { - return .{ .result = .auto }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "min-content")) { - return .{ .result = .min_content }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "max-content")) { - return .{ .result = .max_content }; - } - - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - fn parseFlex(input: *css.Parser) css.Result(CSSNumber) { - const location = input.currentSourceLocation(); - const token = switch (input.next()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (token == .dimension) { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(token.dimension.unit, "fr") and token.dimension.value >= 0.0) { - return .{ .result = token.dimension.value }; - } - } - - return .{ .err = location.newUnexpectedTokenError(token) }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - switch (this.*) { - .auto => try dest.writeStr("auto"), - .min_content => try dest.writeStr("min-content"), - .max_content => try dest.writeStr("max-content"), - .length => |len| try len.toCss(dest), - // .flex => |flex| try css.CSSNumberFns.serializeDimension(&flex, "fr", dest), - .flex => |flex| css.serializer.serializeDimension(flex, "fr", dest), - } - } -}; - -/// A `repeat()` function. -/// -/// See [TrackList](TrackList). -pub const TrackRepeat = struct { - /// The repeat count. - count: RepeatCount, - /// The line names to repeat. - line_names: bun.BabyList(CustomIdentList), - /// The track sizes to repeat. - track_sizes: bun.BabyList(TrackSize), - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.expectFunctionMatching("repeat").asErr()) |e| return .{ .err = e }; - - return input.parseNestedBlock(struct { - fn parse(i: *css.Parser) css.Result(TrackRepeat) { - const count = switch (@call(.auto, @field(RepeatCount, "parse"), .{i})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (i.expectComma().asErr()) |e| return .{ .err = e }; - - // TODO: this code will not compile if used - var line_names = bun.BabyList(CustomIdentList).init(i.allocator); - var track_sizes = bun.BabyList(TrackSize).init(i.allocator); - - while (true) { - const line_name = i.tryParse(parseLineNames, .{}).unwrapOr(CustomIdentList{}); - bun.handleOom(line_names.append(i.allocator(), line_name)); - - if (input.tryParse(TrackSize.parse, .{}).asValue()) |track_size| { - // TODO: error handling - bun.handleOom(track_sizes.append(i.allocator(), track_size)); - } else { - break; - } - } - - return .{ .result = .{ - .count = count, - .line_names = line_names, - .track_sizes = track_sizes, - } }; - } - }.parse); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - try dest.writeStr("repeat("); - try this.count.toCss(dest); - try dest.delim(',', false); - - var track_sizes_index = 0; - var first = true; - for (this.line_names.sliceConst()) |*names| { - if (!names.isEmpty()) { - try serializeLineNames(names, dest); - } - - if (track_sizes_index < this.track_sizes.len) { - const size = this.track_sizes.at(track_sizes_index); - track_sizes_index += 1; - - if (!names.isEmpty()) { - try dest.whitespace(); - } else if (!first) { - try dest.writeChar(' '); - } - try size.toCss(dest); - } - - first = false; - } - - try dest.writeChar(')'); - } -}; - -fn serializeLineNames(names: []const CustomIdent, dest: *Printer) PrintErr!void { - try dest.writeChar('['); - var first = true; - for (names) |*name| { - if (first) { - first = false; - } else { - try dest.writeChar(' '); - } - try writeIdent(&name.value, dest); - } - try dest.writeChar(']'); -} - -fn writeIdent(name: []const u8, dest: *Printer) PrintErr!void { - const css_module_grid_enabled = if (dest.css_module) |*css_module| css_module.config.grid else false; - if (css_module_grid_enabled) { - if (dest.css_module) |*css_module| { - if (css_module.config.pattern.segments.last()) |last| { - if (last != css.css_modules.Segment.local) { - return try dest.addInvalidCssModulesPatternInGridError(); - } - } - } - } - - try dest.writeIdent(name, css_module_grid_enabled); -} - -fn parseLineNames(input: *css.Parser) css.Result(CustomIdentList) { - if (input.expectSquareBracketBlock().asErr()) |e| return .{ .err = e }; - - return input.parseNestedBlock(struct { - fn parse(i: *css.Parser) css.Result(CustomIdentList) { - var values = CustomIdentList{}; - - while (input.tryParse(CustomIdent.parse, .{}).asValue()) |ident| { - bun.handleOom(values.append(i.allocator(), ident)); - } - - return .{ .result = values }; - } - }.parse); -} - -/// A [``](https://drafts.csswg.org/css-grid-2/#typedef-track-repeat) value, -/// used in the `repeat()` function. -/// -/// See [TrackRepeat](TrackRepeat). -pub const RepeatCount = union(enum) { - /// The number of times to repeat. - number: CSSInteger, - /// The `auto-fill` keyword. - @"auto-fill", - /// The `auto-fit` keyword. - @"auto-fit", - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } -}; - -/// A grid template areas value. -/// See https://drafts.csswg.org/css-grid-2/#propdef-grid-template-areas -pub const GridTemplateAreas = union(enum) { - /// No named grid areas. - none, - /// Defines the list of named grid areas. - areas: struct { - /// The number of columns in the grid. - columns: u32, - /// A flattened list of grid area names. - /// Unnamed areas specified by the `.` token are represented as null. - areas: SmallList(?[]const u8, 1), - }, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(struct { - fn parse(i: *css.Parser) css.Result(void) { - return i.expectIdentMatching("none"); - } - }.parse, .{}).asValue()) |_| { - return .{ .result = .none }; - } - - var tokens = SmallList(?[]const u8, 1){}; - var row: u32 = 0; - var columns: u32 = 0; - - if (input.tryParse(css.Parser.expectString, .{}).asValue()) |s| { - const parsed_columns = switch (parseString(input.allocator(), s, &tokens)) { - .result => |v| v, - .err => return .{input.newError(.qualified_rule_invalid)}, - }; - - if (row == 0) { - columns = parsed_columns; - } else if (parsed_columns != columns) return .{ .err = input.newCustomError(.invalid_declaration) }; - - row += 1; - } - - return .{ .result = .{ .areas = .{ - .columns = columns, - .areas = tokens, - } } }; - } - - const HTML_SPACE_CHARACTERS: []const u8 = &.{ 0x0020, 0x0009, 0x000a, 0x000c, 0x000d }; - - fn parseString(allocator: Allocator, s: []const u8, tokens: *SmallList(?[]const u8, 1)) bun.Maybe(u32, void) { - var string = s; - var column = 0; - - while (true) { - const rest = bun.strings.trim(string, HTML_SPACE_CHARACTERS); - if (rest.len == 0) { - // Each string must produce a valid token. - if (column == 0) return .{ .err = {} }; - break; - } - - column += 1; - - if (bun.strings.startsWithChar(rest, '.')) { - const idx = idx: { - for (rest, 0..) |*c, i| { - if (c.* != '.') { - break :idx i; - } - } - break :idx rest.len; - }; - string = rest[idx..]; - } - - const starts_with_name_codepoint = brk: { - if (rest.len == 0) break :brk false; - break :brk isNameCodepoint(rest[0]); - }; - - if (!starts_with_name_codepoint) return .{ .err = {} }; - - const token_len = token_len: { - for (rest, 0..) |*c, i| { - if (!isNameCodepoint(c.*)) { - break :token_len i; - } - } - break :token_len rest.len; - }; - const token = rest[0..token_len]; - bun.handleOom(tokens.append(allocator, token)); - string = rest[token_len..]; - } - - return .{ .result = column }; - } -}; - -fn isNameCodepoint(c: u8) bool { - // alpha numeric, -, _, o - return c >= 'a' and c <= 'z' or c >= 'A' and c <= 'Z' or c == '_' or c >= '0' and c <= '9' or c == '-' or c >= 0x80; // codepoints larger than ascii; -} - -const std = @import("std"); -const Allocator = std.mem.Allocator; - -const bun = @import("bun"); -const BabyList = bun.BabyList; diff --git a/src/css/properties/list.zig b/src/css/properties/list.zig deleted file mode 100644 index 45e6b0a88f28..000000000000 --- a/src/css/properties/list.zig +++ /dev/null @@ -1,64 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const CustomIdent = css.css_values.ident.CustomIdent; -const CSSString = css.css_values.string.CSSString; -const Image = css.css_values.image.Image; - -/// A value for the [list-style-type](https://www.w3.org/TR/2020/WD-css-lists-3-20201117/#text-markers) property. -pub const ListStyleType = union(enum) { - /// No marker. - none, - /// An explicit marker string. - string: CSSString, - /// A named counter style. - counter_style: CounterStyle, -}; - -/// A [counter-style](https://www.w3.org/TR/css-counter-styles-3/#typedef-counter-style) name. -pub const CounterStyle = union(enum) { - /// A predefined counter style name. - predefined: PredefinedCounterStyle, - /// A custom counter style name. - name: CustomIdent, - /// An inline `symbols()` definition. - symbols: Symbols, - - const Symbols = struct { - /// The counter system. - system: SymbolsType, - /// The symbols. - symbols: ArrayList(Symbol), - }; -}; - -/// A single [symbol](https://www.w3.org/TR/css-counter-styles-3/#funcdef-symbols) as used in the -/// `symbols()` function. -/// -/// See [CounterStyle](CounterStyle). -const Symbol = union(enum) { - /// A string. - string: CSSString, - /// An image. - image: Image, -}; - -/// A [predefined counter](https://www.w3.org/TR/css-counter-styles-3/#predefined-counters) style. -pub const PredefinedCounterStyle = @compileError(css.todo_stuff.depth); - -/// A [``](https://www.w3.org/TR/css-counter-styles-3/#typedef-symbols-type) value, -/// as used in the `symbols()` function. -/// -/// See [CounterStyle](CounterStyle). -pub const SymbolsType = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [list-style-position](https://www.w3.org/TR/2020/WD-css-lists-3-20201117/#list-style-position-property) property. -pub const ListStylePosition = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [list-style](https://www.w3.org/TR/2020/WD-css-lists-3-20201117/#list-style-property) shorthand property. -pub const ListStyle = @compileError(css.todo_stuff.depth); - -/// A value for the [marker-side](https://www.w3.org/TR/2020/WD-css-lists-3-20201117/#marker-side) property. -pub const MarkerSide = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/properties/margin_padding.zig b/src/css/properties/margin_padding.zig deleted file mode 100644 index 83f128e0cf59..000000000000 --- a/src/css/properties/margin_padding.zig +++ /dev/null @@ -1,852 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Property = css.Property; -const PropertyIdTag = css.PropertyIdTag; -const PropertyCategory = css.logical.PropertyCategory; - -const LengthPercentageOrAuto = css.css_values.length.LengthPercentageOrAuto; - -/// A value for the [inset](https://drafts.csswg.org/css-logical/#propdef-inset) shorthand property. -pub const Inset = struct { - top: LengthPercentageOrAuto, - right: LengthPercentageOrAuto, - bottom: LengthPercentageOrAuto, - left: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.inset); - const css_impl = css.DefineRectShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.top, - .right = css.PropertyIdTag.right, - .bottom = css.PropertyIdTag.bottom, - .left = css.PropertyIdTag.left, - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [inset-block](https://drafts.csswg.org/css-logical/#propdef-inset-block) shorthand property. -pub const InsetBlock = struct { - /// The block start value. - block_start: LengthPercentageOrAuto, - /// The block end value. - block_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"inset-block"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .block_start = css.PropertyIdTag.@"inset-block-start", - .block_end = css.PropertyIdTag.@"inset-block-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [inset-inline](https://drafts.csswg.org/css-logical/#propdef-inset-inline) shorthand property. -pub const InsetInline = struct { - /// The inline start value. - inline_start: LengthPercentageOrAuto, - /// The inline end value. - inline_end: LengthPercentageOrAuto, - - pub const PropertyFieldMap = .{ - .inline_start = css.PropertyIdTag.@"inset-inline-start", - .inline_end = css.PropertyIdTag.@"inset-inline-end", - }; - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"inset-inline"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [margin-block](https://drafts.csswg.org/css-logical/#propdef-margin-block) shorthand property. -pub const MarginBlock = struct { - /// The block start value. - block_start: LengthPercentageOrAuto, - /// The block end value. - block_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"margin-block"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .block_start = css.PropertyIdTag.@"margin-block-start", - .block_end = css.PropertyIdTag.@"margin-block-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [margin-inline](https://drafts.csswg.org/css-logical/#propdef-margin-inline) shorthand property. -pub const MarginInline = struct { - /// The inline start value. - inline_start: LengthPercentageOrAuto, - /// The inline end value. - inline_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"margin-inline"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .inline_start = css.PropertyIdTag.@"margin-inline-start", - .inline_end = css.PropertyIdTag.@"margin-inline-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [margin](https://drafts.csswg.org/css-box-4/#propdef-margin) shorthand property. -pub const Margin = struct { - top: LengthPercentageOrAuto, - right: LengthPercentageOrAuto, - bottom: LengthPercentageOrAuto, - left: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.margin); - const css_impl = css.DefineRectShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.@"margin-top", - .right = css.PropertyIdTag.@"margin-right", - .bottom = css.PropertyIdTag.@"margin-bottom", - .left = css.PropertyIdTag.@"margin-left", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [padding-block](https://drafts.csswg.org/css-logical/#propdef-padding-block) shorthand property. -pub const PaddingBlock = struct { - /// The block start value. - block_start: LengthPercentageOrAuto, - /// The block end value. - block_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"padding-block"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .block_start = css.PropertyIdTag.@"padding-block-start", - .block_end = css.PropertyIdTag.@"padding-block-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [padding-inline](https://drafts.csswg.org/css-logical/#propdef-padding-inline) shorthand property. -pub const PaddingInline = struct { - /// The inline start value. - inline_start: LengthPercentageOrAuto, - /// The inline end value. - inline_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"padding-inline"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .inline_start = css.PropertyIdTag.@"padding-inline-start", - .inline_end = css.PropertyIdTag.@"padding-inline-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [padding](https://drafts.csswg.org/css-box-4/#propdef-padding) shorthand property. -pub const Padding = struct { - top: LengthPercentageOrAuto, - right: LengthPercentageOrAuto, - bottom: LengthPercentageOrAuto, - left: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.padding); - const css_impl = css.DefineRectShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.@"padding-top", - .right = css.PropertyIdTag.@"padding-right", - .bottom = css.PropertyIdTag.@"padding-bottom", - .left = css.PropertyIdTag.@"padding-left", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [scroll-margin-block](https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-margin-block) shorthand property. -pub const ScrollMarginBlock = struct { - /// The block start value. - block_start: LengthPercentageOrAuto, - /// The block end value. - block_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"scroll-margin-block"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .block_start = css.PropertyIdTag.@"scroll-margin-block-start", - .block_end = css.PropertyIdTag.@"scroll-margin-block-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [scroll-margin-inline](https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-margin-inline) shorthand property. -pub const ScrollMarginInline = struct { - /// The inline start value. - inline_start: LengthPercentageOrAuto, - /// The inline end value. - inline_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"scroll-margin-inline"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .inline_start = css.PropertyIdTag.@"scroll-margin-inline-start", - .inline_end = css.PropertyIdTag.@"scroll-margin-inline-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [scroll-margin](https://drafts.csswg.org/css-scroll-snap/#scroll-margin) shorthand property. -pub const ScrollMargin = struct { - top: LengthPercentageOrAuto, - right: LengthPercentageOrAuto, - bottom: LengthPercentageOrAuto, - left: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"scroll-margin"); - const css_impl = css.DefineRectShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.@"scroll-margin-top", - .right = css.PropertyIdTag.@"scroll-margin-right", - .bottom = css.PropertyIdTag.@"scroll-margin-bottom", - .left = css.PropertyIdTag.@"scroll-margin-left", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [scroll-padding-block](https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-padding-block) shorthand property. -pub const ScrollPaddingBlock = struct { - /// The block start value. - block_start: LengthPercentageOrAuto, - /// The block end value. - block_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"scroll-padding-block"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .block_start = css.PropertyIdTag.@"scroll-padding-block-start", - .block_end = css.PropertyIdTag.@"scroll-padding-block-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [scroll-padding-inline](https://drafts.csswg.org/css-scroll-snap/#propdef-scroll-padding-inline) shorthand property. -pub const ScrollPaddingInline = struct { - /// The inline start value. - inline_start: LengthPercentageOrAuto, - /// The inline end value. - inline_end: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"scroll-padding-inline"); - const css_impl = css.DefineSizeShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .inline_start = css.PropertyIdTag.@"scroll-padding-inline-start", - .inline_end = css.PropertyIdTag.@"scroll-padding-inline-end", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [scroll-padding](https://drafts.csswg.org/css-scroll-snap/#scroll-padding) shorthand property. -pub const ScrollPadding = struct { - top: LengthPercentageOrAuto, - right: LengthPercentageOrAuto, - bottom: LengthPercentageOrAuto, - left: LengthPercentageOrAuto, - - // TODO: bring this back - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"scroll-padding"); - const css_impl = css.DefineRectShorthand(@This(), LengthPercentageOrAuto); - pub const toCss = css_impl.toCss; - pub const parse = css_impl.parse; - - pub const PropertyFieldMap = .{ - .top = css.PropertyIdTag.@"scroll-padding-top", - .right = css.PropertyIdTag.@"scroll-padding-right", - .bottom = css.PropertyIdTag.@"scroll-padding-bottom", - .left = css.PropertyIdTag.@"scroll-padding-left", - }; - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -pub const MarginHandler = NewSizeHandler( - PropertyIdTag.@"margin-top", - PropertyIdTag.@"margin-bottom", - PropertyIdTag.@"margin-left", - PropertyIdTag.@"margin-right", - PropertyIdTag.@"margin-block-start", - PropertyIdTag.@"margin-block-end", - PropertyIdTag.@"margin-inline-start", - PropertyIdTag.@"margin-inline-end", - PropertyIdTag.margin, - PropertyIdTag.@"margin-block", - PropertyIdTag.@"margin-inline", - PropertyCategory.physical, - .{ - .feature = css.Feature.logical_margin, - .shorthand_feature = css.Feature.logical_margin_shorthand, - }, -); - -pub const PaddingHandler = NewSizeHandler( - PropertyIdTag.@"padding-top", - PropertyIdTag.@"padding-bottom", - PropertyIdTag.@"padding-left", - PropertyIdTag.@"padding-right", - PropertyIdTag.@"padding-block-start", - PropertyIdTag.@"padding-block-end", - PropertyIdTag.@"padding-inline-start", - PropertyIdTag.@"padding-inline-end", - PropertyIdTag.padding, - PropertyIdTag.@"padding-block", - PropertyIdTag.@"padding-inline", - PropertyCategory.physical, - .{ - .feature = css.Feature.logical_padding, - .shorthand_feature = css.Feature.logical_padding_shorthand, - }, -); - -pub const ScrollMarginHandler = NewSizeHandler( - PropertyIdTag.@"scroll-margin-top", - PropertyIdTag.@"scroll-margin-bottom", - PropertyIdTag.@"scroll-margin-left", - PropertyIdTag.@"scroll-margin-right", - PropertyIdTag.@"scroll-margin-block-start", - PropertyIdTag.@"scroll-margin-block-end", - PropertyIdTag.@"scroll-margin-inline-start", - PropertyIdTag.@"scroll-margin-inline-end", - PropertyIdTag.@"scroll-margin", - PropertyIdTag.@"scroll-margin-block", - PropertyIdTag.@"scroll-margin-inline", - PropertyCategory.physical, - null, -); - -pub const InsetHandler = NewSizeHandler( - PropertyIdTag.top, - PropertyIdTag.bottom, - PropertyIdTag.left, - PropertyIdTag.right, - PropertyIdTag.@"inset-block-start", - PropertyIdTag.@"inset-block-end", - PropertyIdTag.@"inset-inline-start", - PropertyIdTag.@"inset-inline-end", - PropertyIdTag.inset, - PropertyIdTag.@"inset-block", - PropertyIdTag.@"inset-inline", - PropertyCategory.physical, - .{ - .feature = css.Feature.logical_inset, - .shorthand_feature = css.Feature.logical_inset, - }, -); - -pub fn NewSizeHandler( - comptime top_prop: css.PropertyIdTag, - comptime bottom_prop: css.PropertyIdTag, - comptime left_prop: css.PropertyIdTag, - comptime right_prop: css.PropertyIdTag, - comptime block_start_prop: css.PropertyIdTag, - comptime block_end_prop: css.PropertyIdTag, - comptime inline_start_prop: css.PropertyIdTag, - comptime inline_end_prop: css.PropertyIdTag, - comptime shorthand_prop: css.PropertyIdTag, - comptime block_shorthand: css.PropertyIdTag, - comptime inline_shorthand: css.PropertyIdTag, - comptime shorthand_category: css.logical.PropertyCategory, - comptime shorthand_extra: ?struct { feature: css.compat.Feature, shorthand_feature: css.compat.Feature }, -) type { - return struct { - top: ?LengthPercentageOrAuto = null, - bottom: ?LengthPercentageOrAuto = null, - left: ?LengthPercentageOrAuto = null, - right: ?LengthPercentageOrAuto = null, - block_start: ?Property = null, - block_end: ?Property = null, - inline_start: ?Property = null, - inline_end: ?Property = null, - has_any: bool = false, - category: css.logical.PropertyCategory = css.logical.PropertyCategory.default(), - - pub fn handleProperty( - this: *@This(), - property: *const Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) bool { - switch (@as(PropertyIdTag, property.*)) { - top_prop => this.propertyHelper("top", top_prop.valueType(), &@field(property, @tagName(top_prop)), PropertyCategory.physical, dest, context), - bottom_prop => this.propertyHelper("bottom", bottom_prop.valueType(), &@field(property, @tagName(bottom_prop)), PropertyCategory.physical, dest, context), - left_prop => this.propertyHelper("left", left_prop.valueType(), &@field(property, @tagName(left_prop)), PropertyCategory.physical, dest, context), - right_prop => this.propertyHelper("right", right_prop.valueType(), &@field(property, @tagName(right_prop)), PropertyCategory.physical, dest, context), - block_start_prop => { - this.flushHelper("block_start", block_start_prop.valueType(), &@field(property, @tagName(block_start_prop)), PropertyCategory.logical, dest, context); - this.logicalPropertyHelper("block_start", property.deepClone(context.allocator), dest, context); - }, - block_end_prop => { - this.flushHelper("block_end", block_end_prop.valueType(), &@field(property, @tagName(block_end_prop)), PropertyCategory.logical, dest, context); - this.logicalPropertyHelper("block_end", property.deepClone(context.allocator), dest, context); - }, - inline_start_prop => { - this.flushHelper("inline_start", inline_start_prop.valueType(), &@field(property, @tagName(inline_start_prop)), PropertyCategory.logical, dest, context); - this.logicalPropertyHelper("inline_start", property.deepClone(context.allocator), dest, context); - }, - inline_end_prop => { - this.flushHelper("inline_end", inline_end_prop.valueType(), &@field(property, @tagName(inline_end_prop)), PropertyCategory.logical, dest, context); - this.logicalPropertyHelper("inline_end", property.deepClone(context.allocator), dest, context); - }, - block_shorthand => { - const val = &@field(property, @tagName(block_shorthand)); - this.flushHelper("block_start", block_start_prop.valueType(), &val.block_start, .logical, dest, context); - this.flushHelper("block_end", block_end_prop.valueType(), &val.block_end, .logical, dest, context); - this.logicalPropertyHelper("block_start", @unionInit(Property, @tagName(block_start_prop), val.block_start.deepClone(context.allocator)), dest, context); - this.logicalPropertyHelper("block_end", @unionInit(Property, @tagName(block_end_prop), val.block_end.deepClone(context.allocator)), dest, context); - }, - inline_shorthand => { - const val = &@field(property, @tagName(inline_shorthand)); - this.flushHelper("inline_start", inline_start_prop.valueType(), &val.inline_start, .logical, dest, context); - this.flushHelper("inline_end", inline_end_prop.valueType(), &val.inline_end, .logical, dest, context); - this.logicalPropertyHelper("inline_start", @unionInit(Property, @tagName(inline_start_prop), val.inline_start.deepClone(context.allocator)), dest, context); - this.logicalPropertyHelper("inline_end", @unionInit(Property, @tagName(inline_end_prop), val.inline_end.deepClone(context.allocator)), dest, context); - }, - shorthand_prop => { - const val = &@field(property, @tagName(shorthand_prop)); - this.flushHelper("top", top_prop.valueType(), &val.top, shorthand_category, dest, context); - this.flushHelper("right", right_prop.valueType(), &val.right, shorthand_category, dest, context); - this.flushHelper("bottom", bottom_prop.valueType(), &val.bottom, shorthand_category, dest, context); - this.flushHelper("left", left_prop.valueType(), &val.left, shorthand_category, dest, context); - this.top = val.top.deepClone(context.allocator); - this.right = val.right.deepClone(context.allocator); - this.bottom = val.bottom.deepClone(context.allocator); - this.left = val.left.deepClone(context.allocator); - this.block_start = null; - this.block_end = null; - this.inline_start = null; - this.inline_end = null; - this.has_any = true; - }, - css.PropertyIdTag.unparsed => { - switch (property.unparsed.property_id) { - top_prop, bottom_prop, left_prop, right_prop, block_start_prop, block_end_prop, inline_start_prop, inline_end_prop, block_shorthand, inline_shorthand, shorthand_prop => { - // Even if we weren't able to parse the value (e.g. due to var() references), - // we can still add vendor prefixes to the property itself. - switch (property.unparsed.property_id) { - block_start_prop => this.logicalPropertyHelper("block_start", property.deepClone(context.allocator), dest, context), - block_end_prop => this.logicalPropertyHelper("block_end", property.deepClone(context.allocator), dest, context), - inline_start_prop => this.logicalPropertyHelper("inline_start", property.deepClone(context.allocator), dest, context), - inline_end_prop => this.logicalPropertyHelper("inline_end", property.deepClone(context.allocator), dest, context), - else => { - this.flush(dest, context); - dest.append(context.allocator, property.deepClone(context.allocator)) catch unreachable; - }, - } - }, - else => return false, - } - }, - else => return false, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - } - - fn flushHelper( - this: *@This(), - comptime field: []const u8, - comptime T: type, - val: *const T, - comptime category: PropertyCategory, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - // If the category changes betweet logical and physical, - // or if the value contains syntax that isn't supported across all targets, - // preserve the previous value as a fallback. - if (category != this.category or (@field(this, field) != null and context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?))) { - this.flush(dest, context); - } - } - - fn propertyHelper( - this: *@This(), - comptime field: []const u8, - comptime T: type, - val: *const T, - comptime category: PropertyCategory, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - this.flushHelper(field, T, val, category, dest, context); - @field(this, field) = val.deepClone(context.allocator); - this.category = category; - this.has_any = true; - } - - fn logicalPropertyHelper( - this: *@This(), - comptime field: []const u8, - val: css.Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - // Assume unparsed properties might contain unsupported syntax that we must preserve as a fallback. - if (this.category != PropertyCategory.logical or (@field(this, field) != null and val == .unparsed)) { - this.flush(dest, context); - } - - if (@field(this, field)) |*p| p.deinit(context.allocator); - @field(this, field) = val; - this.category = PropertyCategory.logical; - this.has_any = true; - } - - fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - - this.has_any = false; - - const top = bun.take(&this.top); - const bottom = bun.take(&this.bottom); - const left = bun.take(&this.left); - const right = bun.take(&this.right); - const logical_supported = if (comptime shorthand_extra != null) !context.shouldCompileLogical(shorthand_extra.?.feature) else true; - - if ((shorthand_category != .logical or logical_supported) and top != null and bottom != null and left != null and right != null) { - dest.append( - context.allocator, - @unionInit( - Property, - @tagName(shorthand_prop), - .{ - .top = top.?, - .bottom = bottom.?, - .left = left.?, - .right = right.?, - }, - ), - ) catch |err| bun.handleOom(err); - } else { - if (top) |t| { - dest.append( - context.allocator, - @unionInit(Property, @tagName(top_prop), t), - ) catch |err| bun.handleOom(err); - } - - if (bottom) |b| { - dest.append( - context.allocator, - @unionInit(Property, @tagName(bottom_prop), b), - ) catch |err| bun.handleOom(err); - } - - if (left) |b| { - dest.append( - context.allocator, - @unionInit(Property, @tagName(left_prop), b), - ) catch |err| bun.handleOom(err); - } - - if (right) |b| { - dest.append( - context.allocator, - @unionInit(Property, @tagName(right_prop), b), - ) catch |err| bun.handleOom(err); - } - } - - var block_start = bun.take(&this.block_start); - var block_end = bun.take(&this.block_end); - var inline_start = bun.take(&this.inline_start); - var inline_end = bun.take(&this.inline_end); - - if (logical_supported) { - this.logicalSideHelper(&block_start, &block_end, "block_start", "block_end", block_shorthand, block_start_prop, block_end_prop, logical_supported, dest, context); - } else { - this.prop(&block_start, block_start_prop, top_prop, dest, context); - this.prop(&block_end, block_end_prop, bottom_prop, dest, context); - } - - if (logical_supported) { - this.logicalSideHelper(&inline_start, &inline_end, "inline_start", "inline_end", inline_shorthand, inline_start_prop, inline_end_prop, logical_supported, dest, context); - } else if (inline_start != null or inline_end != null) { - if (inline_start != null and inline_start.? == @field(Property, @tagName(inline_start_prop)) and inline_end != null and inline_end.? == @field(Property, @tagName(inline_end_prop)) and - @field(inline_start.?, @tagName(inline_start_prop)).eql(&@field(inline_end.?, @tagName(inline_end_prop)))) - { - this.prop(&inline_start, inline_start_prop, left_prop, dest, context); - this.prop(&inline_end, inline_end_prop, right_prop, dest, context); - } else { - this.logicalPropHelper(&inline_start, inline_start_prop, left_prop, right_prop, dest, context); - this.logicalPropHelper(&inline_end, inline_end_prop, right_prop, left_prop, dest, context); - } - } - } - - inline fn logicalPropHelper( - this: *@This(), - val: *?Property, - comptime logical: css.PropertyIdTag, - comptime ltr: css.PropertyIdTag, - comptime rtl: css.PropertyIdTag, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - _ = this; // autofix - _ = dest; // autofix - if (val.*) |*_v| { - if (@as(css.PropertyIdTag, _v.*) == logical) { - const v = &@field(_v, @tagName(logical)); - context.addLogicalRule( - context.allocator, - @unionInit(Property, @tagName(ltr), v.deepClone(context.allocator)), - @unionInit(Property, @tagName(rtl), v.deepClone(context.allocator)), - ); - } else if (_v.* == .unparsed) { - const v = &_v.unparsed; - context.addLogicalRule( - context.allocator, - Property{ - .unparsed = v.withPropertyId(context.allocator, ltr), - }, - Property{ - .unparsed = v.withPropertyId(context.allocator, rtl), - }, - ); - } - } - } - - inline fn logicalSideHelper( - this: *@This(), - start: *?Property, - end: *?Property, - comptime start_name: []const u8, - comptime end_name: []const u8, - comptime shorthand_property: css.PropertyIdTag, - comptime start_prop: css.PropertyIdTag, - comptime end_prop: css.PropertyIdTag, - logical_supported: bool, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - _ = this; // autofix - const shorthand_supported = logical_supported and if (comptime shorthand_extra != null) !context.shouldCompileLogical(shorthand_extra.?.shorthand_feature) else true; - - if (start.* != null and @as(PropertyIdTag, start.*.?) == start_prop and - end.* != null and @as(PropertyIdTag, end.*.?) == end_prop and - shorthand_supported) - { - const ValueType = shorthand_property.valueType(); - var value: ValueType = undefined; - @field(value, start_name) = @field(start.*.?, @tagName(start_prop)).deepClone(context.allocator); - @field(value, end_name) = @field(end.*.?, @tagName(end_prop)).deepClone(context.allocator); - if (std.meta.fields(ValueType).len != 2) { - @compileError(@typeName(ValueType) ++ " has more than two fields. This could cause undefined memory."); - } - - dest.append(context.allocator, @unionInit( - Property, - @tagName(shorthand_property), - value, - )) catch |err| bun.handleOom(err); - } else { - if (start.* != null) { - bun.handleOom(dest.append(context.allocator, start.*.?)); - } - if (end.* != null) { - bun.handleOom(dest.append(context.allocator, end.*.?)); - } - } - } - - inline fn prop( - this: *@This(), - val: *?Property, - comptime logical: css.PropertyIdTag, - comptime physical: css.PropertyIdTag, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - _ = this; // autofix - if (val.*) |*v| { - if (@as(css.PropertyIdTag, v.*) == logical) { - dest.append( - context.allocator, - @unionInit( - Property, - @tagName(physical), - @field(v, @tagName(logical)), - ), - ) catch |err| bun.handleOom(err); - } else if (v.* == .unparsed) { - dest.append( - context.allocator, - Property{ - .unparsed = v.unparsed.withPropertyId(context.allocator, physical), - }, - ) catch |err| bun.handleOom(err); - } - } - } - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/masking.zig b/src/css/properties/masking.zig deleted file mode 100644 index c83fa51fcde6..000000000000 --- a/src/css/properties/masking.zig +++ /dev/null @@ -1,572 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const LengthPercentage = css.css_values.length.LengthPercentage; -const Image = css.css_values.image.Image; -const Rect = css.css_values.rect.Rect; -const Url = css.css_values.url.Url; -const LengthOrNumber = css.css_values.length.LengthOrNumber; -const Position = css.css_values.position.Position; - -const BorderRadius = css.css_properties.border_radius.BorderRadius; -const FillRule = css.css_properties.shape.FillRule; - -const BackgroundSize = css.css_properties.background.BackgroundSize; -const BackgroundRepeat = css.css_properties.background.BackgroundRepeat; -const BorderImageSlice = css.css_properties.border_image.BorderImageSlice; -const BorderImageSideWidth = css.css_properties.border_image.BorderImageSideWidth; -const BorderImageRepeat = css.css_properties.border_image.BorderImageRepeat; -const BorderImage = css.css_properties.border_image.BorderImage; - -const VendorPrefix = css.VendorPrefix; - -/// A value for the [clip-path](https://www.w3.org/TR/css-masking-1/#the-clip-path) property. -const ClipPath = union(enum) { - /// No clip path. - None, - /// A url reference to an SVG path element. - Url: Url, - /// A basic shape, positioned according to the reference box. - Shape: struct { - /// A basic shape. - // todo_stuff.think_about_mem_mgmt - shape: *BasicShape, - /// A reference box that the shape is positioned according to. - reference_box: GeometryBox, - }, - /// A reference box. - Box: GeometryBox, -}; - -/// A [``](https://www.w3.org/TR/css-masking-1/#typedef-geometry-box) value -/// as used in the `mask-clip` and `clip-path` properties. -pub const GeometryBox = enum { - /// The painted content is clipped to the content box. - @"border-box", - /// The painted content is clipped to the padding box. - @"padding-box", - /// The painted content is clipped to the border box. - @"content-box", - /// The painted content is clipped to the margin box. - @"margin-box", - /// The painted content is clipped to the object bounding box. - @"fill-box", - /// The painted content is clipped to the stroke bounding box. - @"stroke-box", - /// Uses the nearest SVG viewport as reference box. - @"view-box", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn intoMaskClip(this: *const @This()) MaskClip { - return MaskClip{ .@"geometry-box" = this.* }; - } - - pub fn default() GeometryBox { - return .@"border-box"; - } -}; - -/// A CSS [``](https://www.w3.org/TR/css-shapes-1/#basic-shape-functions) value. -pub const BasicShape = union(enum) { - /// An inset rectangle. - Inset: InsetRect, - /// A circle. - Circle: Circle, - /// An ellipse. - Ellipse: Ellipse, - /// A polygon. - Polygon: Polygon, -}; - -/// An [`inset()`](https://www.w3.org/TR/css-shapes-1/#funcdef-inset) rectangle shape. -const InsetRect = struct { - /// The rectangle. - rect: Rect(LengthPercentage), - /// A corner radius for the rectangle. - radius: BorderRadius, -}; - -/// A [`circle()`](https://www.w3.org/TR/css-shapes-1/#funcdef-circle) shape. -pub const Circle = struct { - /// The radius of the circle. - radius: ShapeRadius, - /// The position of the center of the circle. - position: Position, -}; - -/// An [`ellipse()`](https://www.w3.org/TR/css-shapes-1/#funcdef-ellipse) shape. -pub const Ellipse = struct { - /// The x-radius of the ellipse. - radius_x: ShapeRadius, - /// The y-radius of the ellipse. - radius_y: ShapeRadius, - /// The position of the center of the ellipse. - position: Position, -}; - -/// A [`polygon()`](https://www.w3.org/TR/css-shapes-1/#funcdef-polygon) shape. -pub const Polygon = struct { - /// The fill rule used to determine the interior of the polygon. - fill_rule: FillRule, - /// The points of each vertex of the polygon. - points: ArrayList(Point), -}; - -/// A [``](https://www.w3.org/TR/css-shapes-1/#typedef-shape-radius) value -/// that defines the radius of a `circle()` or `ellipse()` shape. -pub const ShapeRadius = union(enum) { - /// An explicit length or percentage. - LengthPercentage: LengthPercentage, - /// The length from the center to the closest side of the box. - ClosestSide, - /// The length from the center to the farthest side of the box. - FarthestSide, -}; - -/// A point within a `polygon()` shape. -/// -/// See [Polygon](Polygon). -pub const Point = struct { - /// The x position of the point. - x: LengthPercentage, - /// The y position of the point. - y: LengthPercentage, -}; - -/// A value for the [mask-mode](https://www.w3.org/TR/css-masking-1/#the-mask-mode) property. -pub const MaskMode = enum { - /// The luminance values of the mask image is used. - luminance, - /// The alpha values of the mask image is used. - alpha, - /// If an SVG source is used, the value matches the `mask-type` property. Otherwise, the alpha values are used. - @"match-source", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() MaskMode { - return .@"match-source"; - } -}; - -/// A value for the [mask-clip](https://www.w3.org/TR/css-masking-1/#the-mask-clip) property. -pub const MaskClip = union(enum) { - /// A geometry box. - @"geometry-box": GeometryBox, - /// The painted content is not clipped. - @"no-clip", - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [mask-composite](https://www.w3.org/TR/css-masking-1/#the-mask-composite) property. -pub const MaskComposite = enum { - /// The source is placed over the destination. - add, - /// The source is placed, where it falls outside of the destination. - subtract, - /// The parts of source that overlap the destination, replace the destination. - intersect, - /// The non-overlapping regions of source and destination are combined. - exclude, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() MaskComposite { - return .add; - } -}; - -/// A value for the [mask-type](https://www.w3.org/TR/css-masking-1/#the-mask-type) property. -pub const MaskType = enum { - /// The luminance values of the mask is used. - luminance, - /// The alpha values of the mask is used. - alpha, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [mask](https://www.w3.org/TR/css-masking-1/#the-mask) shorthand property. -pub const Mask = struct { - /// The mask image. - image: Image, - /// The position of the mask. - position: Position, - /// The size of the mask image. - size: BackgroundSize, - /// How the mask repeats. - repeat: BackgroundRepeat, - /// The box in which the mask is clipped. - clip: MaskClip, - /// The origin of the mask. - origin: GeometryBox, - /// How the mask is composited with the element. - composite: MaskComposite, - /// How the mask image is interpreted. - mode: MaskMode, - - pub const PropertyFieldMap = .{ - .image = css.PropertyIdTag.@"mask-image", - .position = css.PropertyIdTag.@"mask-position", - .size = css.PropertyIdTag.@"mask-size", - .repeat = css.PropertyIdTag.@"mask-repeat", - .clip = css.PropertyIdTag.@"mask-clip", - .origin = css.PropertyIdTag.@"mask-origin", - .composite = css.PropertyIdTag.@"mask-composite", - .mode = css.PropertyIdTag.@"mask-mode", - }; - - pub const VendorPrefixMap = .{ - .image = true, - .position = true, - .size = true, - .repeat = true, - .clip = true, - .origin = true, - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var image: ?Image = null; - var position: ?Position = null; - var size: ?BackgroundSize = null; - var repeat: ?BackgroundRepeat = null; - var clip: ?MaskClip = null; - var origin: ?GeometryBox = null; - var composite: ?MaskComposite = null; - var mode: ?MaskMode = null; - - while (true) { - if (image == null) { - if (input.tryParse(Image.parse, .{}).asValue()) |value| { - image = value; - continue; - } - } - - if (position == null) { - if (input.tryParse(Position.parse, .{}).asValue()) |value| { - position = value; - size = input.tryParse(struct { - pub inline fn parseFn(i: *css.Parser) css.Result(BackgroundSize) { - if (i.expectDelim('/').asErr()) |e| return .{ .err = e }; - return BackgroundSize.parse(i); - } - }.parseFn, .{}).asValue(); - continue; - } - } - - if (repeat == null) { - if (input.tryParse(BackgroundRepeat.parse, .{}).asValue()) |value| { - repeat = value; - continue; - } - } - - if (origin == null) { - if (input.tryParse(GeometryBox.parse, .{}).asValue()) |value| { - origin = value; - continue; - } - } - - if (clip == null) { - if (input.tryParse(MaskClip.parse, .{}).asValue()) |value| { - clip = value; - continue; - } - } - - if (composite == null) { - if (input.tryParse(MaskComposite.parse, .{}).asValue()) |value| { - composite = value; - continue; - } - } - - if (mode == null) { - if (input.tryParse(MaskMode.parse, .{}).asValue()) |value| { - mode = value; - continue; - } - } - - break; - } - - if (clip == null) { - if (origin) |o| { - clip = o.intoMaskClip(); - } - } - - return .{ .result = .{ - .image = image orelse Image.default(), - .position = position orelse Position.default(), - .repeat = repeat orelse BackgroundRepeat.default(), - .size = size orelse BackgroundSize.default(), - .origin = origin orelse .@"border-box", - .clip = clip orelse GeometryBox.@"border-box".intoMaskClip(), - .composite = composite orelse .add, - .mode = mode orelse .@"match-source", - } }; - } - - pub fn toCss(this: *const Mask, dest: *css.Printer) css.PrintErr!void { - try this.image.toCss(dest); - - if (!this.position.eql(&Position.default()) or !this.size.eql(&BackgroundSize.default())) { - try dest.writeChar(' '); - try this.position.toCss(dest); - - if (!this.size.eql(&BackgroundSize.default())) { - try dest.delim('/', true); - try this.size.toCss(dest); - } - } - - if (!this.repeat.eql(&BackgroundRepeat.default())) { - try dest.writeChar(' '); - try this.repeat.toCss(dest); - } - - if (!this.origin.eql(&GeometryBox.@"border-box") or !this.clip.eql(&GeometryBox.@"border-box".intoMaskClip())) { - try dest.writeChar(' '); - try this.origin.toCss(dest); - - if (!this.clip.eql(&this.origin.intoMaskClip())) { - try dest.writeChar(' '); - try this.clip.toCss(dest); - } - } - - if (!this.composite.eql(&MaskComposite.default())) { - try dest.writeChar(' '); - try this.composite.toCss(dest); - } - - if (!this.mode.eql(&MaskMode.default())) { - try dest.writeChar(' '); - try this.mode.toCss(dest); - } - - return; - } - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [mask-border-mode](https://www.w3.org/TR/css-masking-1/#the-mask-border-mode) property. -pub const MaskBorderMode = enum { - /// The luminance values of the mask image is used. - luminance, - /// The alpha values of the mask image is used. - alpha, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; - - pub fn default() @This() { - return .alpha; - } -}; - -/// A value for the [mask-border](https://www.w3.org/TR/css-masking-1/#the-mask-border) shorthand property. -/// A value for the [mask-border](https://www.w3.org/TR/css-masking-1/#the-mask-border) shorthand property. -pub const MaskBorder = struct { - /// The mask image. - source: Image, - /// The offsets that define where the image is sliced. - slice: BorderImageSlice, - /// The width of the mask image. - width: Rect(BorderImageSideWidth), - /// The amount that the image extends beyond the border box. - outset: Rect(LengthOrNumber), - /// How the mask image is scaled and tiled. - repeat: BorderImageRepeat, - /// How the mask image is interpreted. - mode: MaskBorderMode, - - // (old using name space) css.DefineShorthand(@This(), css.PropertyIdTag.@"mask-border", PropertyFieldMap); - - pub const PropertyFieldMap = .{ - .source = css.PropertyIdTag.@"mask-border-source", - .slice = css.PropertyIdTag.@"mask-border-slice", - .width = css.PropertyIdTag.@"mask-border-width", - .outset = css.PropertyIdTag.@"mask-border-outset", - .repeat = css.PropertyIdTag.@"mask-border-repeat", - .mode = css.PropertyIdTag.@"mask-border-mode", - }; - - pub fn parse(input: *css.Parser) css.Result(@This()) { - const Closure = struct { - mode: ?MaskBorderMode = null, - }; - var closure = Closure{ .mode = null }; - const border_image = BorderImage.parseWithCallback(input, &closure, struct { - inline fn callback(c: *Closure, p: *css.Parser) bool { - if (c.mode == null) { - if (p.tryParse(MaskBorderMode.parse, .{}).asValue()) |value| { - c.mode = value; - return true; - } - } - return false; - } - }.callback); - - if (border_image.isOk() or closure.mode != null) { - const bi = border_image.unwrapOr(comptime BorderImage.default()); - return .{ .result = MaskBorder{ - .source = bi.source, - .slice = bi.slice, - .width = bi.width, - .outset = bi.outset, - .repeat = bi.repeat, - .mode = closure.mode orelse MaskBorderMode.default(), - } }; - } else { - return .{ .err = input.newCustomError(.invalid_declaration) }; - } - } - - pub fn toCss(this: *const MaskBorder, dest: *css.Printer) css.PrintErr!void { - try BorderImage.toCssInternal( - &this.source, - &this.slice, - &this.width, - &this.outset, - &this.repeat, - dest, - ); - if (!this.mode.eql(&MaskBorderMode.default())) { - try dest.writeChar(' '); - try this.mode.toCss(dest); - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [-webkit-mask-composite](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-composite) -/// property. -/// -/// See also [MaskComposite](MaskComposite). -/// A value for the [-webkit-mask-composite](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-mask-composite) -/// property. -/// -/// See also [MaskComposite](MaskComposite). -pub const WebKitMaskComposite = enum { - clear, - copy, - /// Equivalent to `add` in the standard `mask-composite` syntax. - @"source-over", - /// Equivalent to `intersect` in the standard `mask-composite` syntax. - @"source-in", - /// Equivalent to `subtract` in the standard `mask-composite` syntax. - @"source-out", - @"source-atop", - @"destination-over", - @"destination-in", - @"destination-out", - @"destination-atop", - /// Equivalent to `exclude` in the standard `mask-composite` syntax. - xor, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [-webkit-mask-source-type](https://github.com/WebKit/WebKit/blob/6eece09a1c31e47489811edd003d1e36910e9fd3/Source/WebCore/css/CSSProperties.json#L6578-L6587) -/// property. -/// -/// See also [MaskMode](MaskMode). -/// A value for the [-webkit-mask-source-type](https://github.com/WebKit/WebKit/blob/6eece09a1c31e47489811edd003d1e36910e9fd3/Source/WebCore/css/CSSProperties.json#L6578-L6587) -/// property. -/// -/// See also [MaskMode](MaskMode). -pub const WebKitMaskSourceType = enum { - /// Equivalent to `match-source` in the standard `mask-mode` syntax. - auto, - /// The luminance values of the mask image is used. - luminance, - /// The alpha values of the mask image is used. - alpha, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -pub fn getWebkitMaskProperty(property_id: *const css.PropertyId) ?css.PropertyId { - return switch (property_id.*) { - .@"mask-border-source" => .{ .@"mask-box-image-source" = VendorPrefix.WEBKIT }, - .@"mask-border-slice" => .{ .@"mask-box-image-slice" = VendorPrefix.WEBKIT }, - .@"mask-border-width" => .{ .@"mask-box-image-width" = VendorPrefix.WEBKIT }, - .@"mask-border-outset" => .{ .@"mask-box-image-outset" = VendorPrefix.WEBKIT }, - .@"mask-border-repeat" => .{ .@"mask-box-image-repeat" = VendorPrefix.WEBKIT }, - .@"mask-border" => .{ .@"mask-box-image" = VendorPrefix.WEBKIT }, - .@"mask-composite" => css.PropertyId.@"-webkit-mask-composite", - .@"mask-mode" => .{ .@"mask-source-type" = VendorPrefix.WEBKIT }, - else => null, - }; -} - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/outline.zig b/src/css/properties/outline.zig deleted file mode 100644 index da3cedecdc68..000000000000 --- a/src/css/properties/outline.zig +++ /dev/null @@ -1,33 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const GenericBorder = css.css_properties.border.GenericBorder; -const LineStyle = css.css_properties.border.LineStyle; - -/// A value for the [outline](https://drafts.csswg.org/css-ui/#outline) shorthand property. -pub const Outline = GenericBorder(OutlineStyle, 11); - -/// A value for the [outline-style](https://drafts.csswg.org/css-ui/#outline-style) property. -pub const OutlineStyle = union(enum) { - /// The `auto` keyword. - auto: void, - /// A value equivalent to the `border-style` property. - line_style: LineStyle, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn default() @This() { - return .{ .line_style = .none }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/overflow.zig b/src/css/properties/overflow.zig deleted file mode 100644 index 9953558d06e2..000000000000 --- a/src/css/properties/overflow.zig +++ /dev/null @@ -1,80 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -/// A value for the [overflow](https://www.w3.org/TR/css-overflow-3/#overflow-properties) shorthand property. -pub const Overflow = struct { - /// A value for the [overflow](https://www.w3.org/TR/css-overflow-3/#overflow-properties) shorthand property. - x: OverflowKeyword, - /// The overflow mode for the y direction. - y: OverflowKeyword, - - pub fn parse(input: *css.Parser) css.Result(Overflow) { - const x = switch (OverflowKeyword.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const y = switch (input.tryParse(OverflowKeyword.parse, .{})) { - .result => |v| v, - else => x, - }; - return .{ .result = Overflow{ .x = x, .y = y } }; - } - - pub fn toCss(this: *const Overflow, dest: *css.Printer) css.PrintErr!void { - try this.x.toCss(dest); - if (this.y != this.x) { - try dest.writeChar(' '); - try this.y.toCss(dest); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub inline fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// An [overflow](https://www.w3.org/TR/css-overflow-3/#overflow-properties) keyword -/// as used in the `overflow-x`, `overflow-y`, and `overflow` properties. -pub const OverflowKeyword = enum { - /// Overflowing content is visible. - visible, - /// Overflowing content is hidden. Programmatic scrolling is allowed. - hidden, - /// Overflowing content is clipped. Programmatic scrolling is not allowed. - clip, - /// The element is scrollable. - scroll, - /// Overflowing content scrolls if needed. - auto, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [text-overflow](https://www.w3.org/TR/css-overflow-3/#text-overflow) property. -pub const TextOverflow = enum { - /// Overflowing text is clipped. - clip, - /// Overflowing text is truncated with an ellipsis. - ellipsis, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/position.zig b/src/css/properties/position.zig deleted file mode 100644 index 733c2b78f25c..000000000000 --- a/src/css/properties/position.zig +++ /dev/null @@ -1,82 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -/// A value for the [position](https://www.w3.org/TR/css-position-3/#position-property) property. -pub const Position = union(enum) { - /// The box is laid in the document flow. - static, - /// The box is laid out in the document flow and offset from the resulting position. - relative, - /// The box is taken out of document flow and positioned in reference to its relative ancestor. - absolute, - /// Similar to relative but adjusted according to the ancestor scrollable element. - sticky: css.VendorPrefix, - /// The box is taken out of the document flow and positioned in reference to the page viewport. - fixed, - - pub fn parse(input: *css.Parser) css.Result(Position) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const PositionKeyword = enum { - static, - relative, - absolute, - fixed, - sticky, - @"-webkit-sticky", - }; - - const keyword_map = bun.ComptimeStringMap(PositionKeyword, .{ - .{ "static", .static }, - .{ "relative", .relative }, - .{ "absolute", .absolute }, - .{ "fixed", .fixed }, - .{ "sticky", .sticky }, - .{ "-webkit-sticky", .@"-webkit-sticky" }, - }); - - const keyword = keyword_map.get(ident) orelse { - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - }; - - return .{ .result = switch (keyword) { - .static => .static, - .relative => .relative, - .absolute => .absolute, - .fixed => .fixed, - .sticky => .{ .sticky = css.VendorPrefix{ .none = true } }, - .@"-webkit-sticky" => .{ .sticky = css.VendorPrefix{ .webkit = true } }, - } }; - } - - pub fn toCss(this: *const Position, dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .static => dest.writeStr("static"), - .relative => dest.writeStr("relative"), - .absolute => dest.writeStr("absolute"), - .fixed => dest.writeStr("fixed"), - .sticky => |prefix| { - try prefix.toCss(dest); - return dest.writeStr("sticky"); - }, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/prefix_handler.zig b/src/css/properties/prefix_handler.zig deleted file mode 100644 index 5af8023c1f04..000000000000 --- a/src/css/properties/prefix_handler.zig +++ /dev/null @@ -1,135 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const VendorPrefix = css.VendorPrefix; - -const PropertyIdTag = css.PropertyIdTag; -const Property = css.Property; -const UnparsedProperty = css.css_properties.custom.UnparsedProperty; - -/// *NOTE* The struct field names must match their corresponding names in `Property`! -pub const FallbackHandler = struct { - color: ?usize = null, - @"text-shadow": ?usize = null, - // TODO: add these back plz - // filter: ?usize = null, - // @"backdrop-filter": ?usize = null, - // fill: ?usize = null, - // stroke: ?usize = null, - // @"caret-color": ?usize = null, - // caret: ?usize = null, - - const field_count = @typeInfo(FallbackHandler).Struct.fields.len; - - pub fn handleProperty( - this: *FallbackHandler, - property: *const Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) bool { - inline for (std.meta.fields(FallbackHandler)) |field| { - if (@intFromEnum(@field(PropertyIdTag, field.name)) == @intFromEnum(@as(PropertyIdTag, property.*))) { - const has_vendor_prefix = comptime PropertyIdTag.hasVendorPrefix(@field(PropertyIdTag, field.name)); - var val = if (comptime has_vendor_prefix) - @field(property, field.name)[0].deepClone(context.allocator) - else - @field(property, field.name).deepClone(context.allocator); - - if (@field(this, field.name) == null) { - const fallbacks = val.getFallbacks(context.allocator, context.targets); - const has_fallbacks = !fallbacks.isEmpty(); - - for (fallbacks.slice()) |fallback| { - dest.append( - context.allocator, - @unionInit( - Property, - field.name, - if (comptime has_vendor_prefix) - .{ fallback, @field(property, field.name)[1] } - else - fallback, - ), - ) catch |err| bun.handleOom(err); - } - if (comptime has_vendor_prefix) { - if (has_fallbacks and @field(property, field.name[1]).contains(VendorPrefix{ .none = true })) { - @field(property, field.name[1]) = css.VendorPrefix{ .none = true }; - } - } - } - - if (@field(this, field.name) == null or - context.targets.browsers != null and !val.isCompatible(context.targets.browsers.?)) - { - @field(this, field.name) = dest.items.len; - dest.append( - context.allocator, - @unionInit( - Property, - field.name, - if (comptime has_vendor_prefix) - .{ val, @field(property, field.name)[1] } - else - val, - ), - ) catch |err| bun.handleOom(err); - } else if (@field(this, field.name) != null) { - const index = @field(this, field.name).?; - dest.items[index] = @unionInit( - Property, - field.name, - if (comptime has_vendor_prefix) - .{ val, @field(property, field.name)[1] } - else - val, - ); - } else { - val.deinit(context.allocator); - } - - return true; - } - } - - if (@as(PropertyIdTag, property.*) == .unparsed) { - const val: *const UnparsedProperty = &property.unparsed; - var unparsed, const index = unparsed_and_index: { - inline for (std.meta.fields(FallbackHandler)) |field| { - if (@intFromEnum(@field(PropertyIdTag, field.name)) == @intFromEnum(val.property_id)) { - const has_vendor_prefix = comptime PropertyIdTag.hasVendorPrefix(@field(PropertyIdTag, field.name)); - const newval = newval: { - if (comptime has_vendor_prefix) { - if (@field(val.property_id, field.name)[1].contains(VendorPrefix{ .none = true })) - break :newval val.getPrefixed(context.targets, @field(css.prefixes.Feature, field.name)); - } - break :newval val.deepClone(context.allocator); - }; - break :unparsed_and_index .{ newval, &@field(this, field.name) }; - } - } - return false; - }; - - context.addUnparsedFallbacks(&unparsed); - if (index.*) |i| { - dest.items[i] = Property{ .unparsed = unparsed }; - } else { - index.* = dest.items.len; - bun.handleOom(dest.append(context.allocator, Property{ .unparsed = unparsed })); - } - - return true; - } - - return false; - } - - pub fn finalize(this: *FallbackHandler, _: *css.DeclarationList, _: *css.PropertyHandlerContext) void { - inline for (std.meta.fields(FallbackHandler)) |field| { - @field(this, field.name) = null; - } - } -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/properties/properties.zig b/src/css/properties/properties.zig deleted file mode 100644 index 9058dcac95a8..000000000000 --- a/src/css/properties/properties.zig +++ /dev/null @@ -1,1886 +0,0 @@ -const Position = position.Position; - -pub const CustomPropertyName = @import("./custom.zig").CustomPropertyName; - -pub const @"align" = @import("./align.zig"); -pub const animation = @import("./animation.zig"); -pub const background = @import("./background.zig"); -pub const border = @import("./border.zig"); -pub const border_image = @import("./border_image.zig"); -pub const border_radius = @import("./border_radius.zig"); -pub const box_shadow = @import("./box_shadow.zig"); -pub const contain = @import("./contain.zig"); -pub const css_modules = @import("./css_modules.zig"); -pub const custom = @import("./custom.zig"); -pub const display = @import("./display.zig"); -pub const effects = @import("./effects.zig"); -pub const flex = @import("./flex.zig"); -pub const font = @import("./font.zig"); -pub const grid = @import("./grid.zig"); -pub const list = @import("./list.zig"); -pub const margin_padding = @import("./margin_padding.zig"); -pub const masking = @import("./masking.zig"); -pub const outline = @import("./outline.zig"); -pub const overflow = @import("./overflow.zig"); -pub const position = @import("./position.zig"); -pub const prefix_handler = @import("./prefix_handler.zig"); -pub const shape = @import("./shape.zig"); -pub const size = @import("./size.zig"); -pub const svg = @import("./svg.zig"); -pub const text = @import("./text.zig"); -pub const transform = @import("./transform.zig"); -pub const transition = @import("./transition.zig"); -pub const ui = @import("./ui.zig"); - -pub const PropertyId = generated.PropertyId; -pub const Property = generated.Property; -pub const PropertyIdTag = generated.PropertyIdTag; - -/// A [CSS-wide keyword](https://drafts.csswg.org/css-cascade-5/#defaulting-keywords). -pub const CSSWideKeyword = enum { - /// The property's initial value. - initial, - /// The property's computed value on the parent element. - inherit, - /// Either inherit or initial depending on whether the property is inherited. - unset, - /// Rolls back the cascade to the cascaded value of the earlier origin. - revert, - /// Rolls back the cascade to the value of the previous cascade layer. - @"revert-layer", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -// pub fn DefineProperties(comptime properties: anytype) type { -// const input_fields: []const std.builtin.Type.StructField = std.meta.fields(@TypeOf(properties)); -// const total_fields_len = input_fields.len + 2; // +2 for the custom property and the `all` property -// const TagSize = u16; -// const PropertyIdT, const max_enum_name_length: usize = brk: { -// var max: usize = 0; -// var property_id_type = std.builtin.Type.Enum{ -// .tag_type = TagSize, -// .is_exhaustive = true, -// .decls = &.{}, -// .fields = undefined, -// }; -// var enum_fields: [total_fields_len]std.builtin.Type.EnumField = undefined; -// for (input_fields, 0..) |field, i| { -// enum_fields[i] = .{ -// .name = field.name, -// .value = i, -// }; -// max = @max(max, field.name.len); -// } -// enum_fields[input_fields.len] = std.builtin.Type.EnumField{ -// .name = "all", -// .value = input_fields.len, -// // }; -// // enum_fields[input_fields.len + 1] = std.builtin.Type.EnumField{ -// .name = "custom", -// .value = input_fields.len + 1, -// }; -// property_id_type.fields = &enum_fields; -// break :brk .{ property_id_type, max }; -// }; - -// const types: []const type = types: { -// var types: [total_fields_len]type = undefined; -// inline for (input_fields, 0..) |field, i| { -// types[i] = @field(properties, field.name).ty; - -// if (std.mem.eql(u8, field.name, "transition-property")) { -// types[i] = struct { SmallList(PropertyIdT, 1), css.VendorPrefix }; -// } - -// // Validate it - -// const value = @field(properties, field.name); -// const ValueT = @TypeOf(value); -// const value_ty = value.ty; -// const ValueTy = @TypeOf(value_ty); -// const value_ty_info = @typeInfo(ValueTy); -// // If `valid_prefixes` is defined, the `ty` should be a two item tuple where -// // the second item is of type `VendorPrefix` -// if (@hasField(ValueT, "valid_prefixes")) { -// if (!value_ty_info.Struct.is_tuple) { -// @compileError("Expected a tuple type for `ty` when `valid_prefixes` is defined"); -// } -// if (value_ty_info.Struct.fields[1].type != css.VendorPrefix) { -// @compileError("Expected the second item in the tuple to be of type `VendorPrefix`"); -// } -// } -// } -// types[input_fields.len] = void; -// types[input_fields.len + 1] = CustomPropertyName; -// break :types &types; -// }; -// const PropertyT = PropertyT: { -// var union_fields: [total_fields_len]std.builtin.Type.UnionField = undefined; -// inline for (input_fields, 0..) |input_field, i| { -// const Ty = types[i]; -// union_fields[i] = std.builtin.Type.UnionField{ -// .alignment = @alignOf(Ty), -// .type = type, -// .name = input_field.name, -// }; -// } -// union_fields[input_fields.len] = std.builtin.Type.UnionField{ -// .alignment = 0, -// .type = void, -// .name = "all", -// }; -// union_fields[input_fields.len + 1] = std.builtin.Type.UnionField{ -// .alignment = @alignOf(CustomPropertyName), -// .type = CustomPropertyName, -// .name = "custom", -// }; -// break :PropertyT std.builtin.Type.Union{ -// .layout = .auto, -// .tag_type = PropertyIdT, -// .decls = &.{}, -// .fields = union_fields, -// }; -// }; -// _ = PropertyT; // autofix -// return struct { -// pub const PropertyId = PropertyIdT; - -// pub fn propertyIdEq(lhs: PropertyId, rhs: PropertyId) bool { -// _ = lhs; // autofix -// _ = rhs; // autofix -// @compileError(css.todo_stuff.depth); -// } - -// pub fn propertyIdIsShorthand(id: PropertyId) bool { -// inline for (std.meta.fields(PropertyId)) |field| { -// if (field.value == @intFromEnum(id)) { -// const is_shorthand = if (@hasField(@TypeOf(@field(properties, field.name)), "shorthand")) -// @field(@field(properties, field.name), "shorthand") -// else -// false; -// return is_shorthand; -// } -// } -// return false; -// } - -// /// PropertyId.prefix() -// pub fn propertyIdPrefix(id: PropertyId) css.VendorPrefix { -// _ = id; // autofix -// @compileError(css.todo_stuff.depth); -// } - -// /// PropertyId.name() -// pub fn propertyIdName(id: PropertyId) []const u8 { -// _ = id; // autofix -// @compileError(css.todo_stuff.depth); -// } - -// pub fn propertyIdFromStr(name: []const u8) PropertyId { -// const prefix, const name_ref = if (bun.strings.startsWithCaseInsensitiveAscii(name, "-webkit-")) -// .{ css.VendorPrefix.webkit, name[8..] } -// else if (bun.strings.startsWithCaseInsensitiveAscii(name, "-moz-")) -// .{ css.VendorPrefix.moz, name[5..] } -// else if (bun.strings.startsWithCaseInsensitiveAscii(name, "-o-")) -// .{ css.VendorPrefix.moz, name[3..] } -// else if (bun.strings.startsWithCaseInsensitiveAscii(name, "-ms-")) -// .{ css.VendorPrefix.moz, name[4..] } -// else -// .{ css.VendorPrefix.none, name }; - -// return parsePropertyIdFromNameAndPrefix(name_ref, prefix) catch .{ -// .custom = CustomPropertyName.fromStr(name), -// }; -// } - -// pub fn parsePropertyIdFromNameAndPrefix(name: []const u8, prefix: css.VendorPrefix) Error!PropertyId { -// var buffer: [max_enum_name_length]u8 = undefined; -// if (name.len > buffer.len) { -// // TODO: actual source just returns empty Err(()) -// return Error.InvalidPropertyName; -// } -// const lower = bun.strings.copyLowercase(name, buffer[0..name.len]); -// inline for (std.meta.fields(PropertyIdT)) |field_| { -// const field: std.builtin.Type.EnumField = field_; -// // skip custom -// if (bun.strings.eql(field.name, "custom")) continue; - -// if (bun.strings.eql(lower, field.name)) { -// const prop = @field(properties, field.name); -// const allowed_prefixes = allowed_prefixes: { -// var prefixes: css.VendorPrefix = if (@hasField(@TypeOf(prop), "unprefixed") and !prop.unprefixed) -// css.VendorPrefix{} -// else -// css.VendorPrefix{ .none = true }; - -// if (@hasField(@TypeOf(prop), "valid_prefixes")) { -// prefixes = css.VendorPrefix.bitwiseOr(prefixes, prop.valid_prefixes); -// } - -// break :allowed_prefixes prefixes; -// }; - -// if (allowed_prefixes.contains(prefix)) return @enumFromInt(field.value); -// } -// } -// return Error.InvalidPropertyName; -// } -// }; -// } - -// /// SmallList(PropertyId) -// const SmallListPropertyIdPlaceholder = struct {}; - -// pub const Property = DefineProperties(.{ -// .@"background-color" = .{ -// .ty = CssColor, -// }, -// .@"background-image" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(Image, 1), -// }, -// .@"background-position-x" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(css_values.position.HorizontalPosition, 1), -// }, -// .@"background-position-y" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(css_values.position.HorizontalPosition, 1), -// }, -// .@"background-position" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(background.BackgroundPosition, 1), -// .shorthand = true, -// }, -// .@"background-size" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(background.BackgroundSize, 1), -// }, -// .@"background-repeat" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(background.BackgroundSize, 1), -// }, -// .@"background-attachment" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(background.BackgroundAttachment, 1), -// }, -// .@"background-clip" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = struct { -// SmallList(background.BackgroundAttachment, 1), -// css.VendorPrefix, -// }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .@"background-origin" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(background.BackgroundOrigin, 1), -// }, -// .background = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = SmallList(background.Background, 1), -// }, - -// .@"box-shadow" = .{ -// // PERF: make this equivalent to SmallVec<[_; 1]> -// .ty = struct { SmallList(box_shadow.BoxShadow, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .opacity = .{ -// .ty = css.css_values.alpha.AlphaValue, -// }, -// .color = .{ -// .ty = CssColor, -// }, -// .display = .{ -// .ty = display.Display, -// }, -// .visibility = .{ -// .ty = display.Visibility, -// }, - -// .width = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.size, .category = PropertyCategory.physical }, -// }, -// .height = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.size, .category = PropertyCategory.physical }, -// }, -// .@"min-width" = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.min_size, .category = PropertyCategory.physical }, -// }, -// .@"min-height" = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.min_size, .category = PropertyCategory.physical }, -// }, -// .@"max-width" = .{ -// .ty = size.MaxSize, -// .logical_group = .{ .ty = LogicalGroup.max_size, .category = PropertyCategory.physical }, -// }, -// .@"max-height" = .{ -// .ty = size.MaxSize, -// .logical_group = .{ .ty = LogicalGroup.max_size, .category = PropertyCategory.physical }, -// }, -// .@"block-size" = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.size, .category = PropertyCategory.logical }, -// }, -// .@"inline-size" = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.size, .category = PropertyCategory.logical }, -// }, -// .min_block_size = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.min_size, .category = PropertyCategory.logical }, -// }, -// .@"min-inline-size" = .{ -// .ty = size.Size, -// .logical_group = .{ .ty = LogicalGroup.min_size, .category = PropertyCategory.logical }, -// }, -// .@"max-block-size" = .{ -// .ty = size.MaxSize, -// .logical_group = .{ .ty = LogicalGroup.max_size, .category = PropertyCategory.logical }, -// }, -// .@"max-inline-size" = .{ -// .ty = size.MaxSize, -// .logical_group = .{ .ty = LogicalGroup.max_size, .category = PropertyCategory.logical }, -// }, -// .@"box-sizing" = .{ -// .ty = struct { size.BoxSizing, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .@"aspect-ratio" = .{ -// .ty = size.AspectRatio, -// }, - -// .overflow = .{ -// .ty = overflow.Overflow, -// .shorthand = true, -// }, -// .@"overflow-x" = .{ -// .ty = overflow.OverflowKeyword, -// }, -// .@"overflow-y" = .{ -// .ty = overflow.OverflowKeyword, -// }, -// .@"text-overflow" = .{ -// .ty = struct { overflow.TextOverflow, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .o = true, -// }, -// }, - -// // https://www.w3.org/TR/2020/WD-css-position-3-20200519 -// .position = .{ -// .ty = position.Position, -// }, -// .top = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.physical }, -// }, -// .bottom = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.physical }, -// }, -// .left = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.physical }, -// }, -// .right = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.physical }, -// }, -// .@"inset-block-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.logical }, -// }, -// .@"inset-block-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.logical }, -// }, -// .@"inset-inline-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.logical }, -// }, -// .@"inset-inline-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.inset, .category = PropertyCategory.logical }, -// }, -// .@"inset-block" = .{ -// .ty = margin_padding.InsetBlock, -// .shorthand = true, -// }, -// .@"inset-inline" = .{ -// .ty = margin_padding.InsetInline, -// .shorthand = true, -// }, -// .inset = .{ -// .ty = margin_padding.Inset, -// .shorthand = true, -// }, - -// .@"border-spacing" = .{ -// .ty = css.css_values.size.Size(Length), -// }, - -// .@"border-top-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.physical }, -// }, -// .@"border-bottom-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.physical }, -// }, -// .@"border-left-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.physical }, -// }, -// .@"border-right-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.physical }, -// }, -// .@"border-block-start-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.logical }, -// }, -// .@"border-block-end-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.logical }, -// }, -// .@"border-inline-start-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.logical }, -// }, -// .@"border-inline-end-color" = .{ -// .ty = CssColor, -// .logical_group = .{ .ty = LogicalGroup.border_color, .category = PropertyCategory.logical }, -// }, - -// .@"border-top-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.physical }, -// }, -// .@"border-bottom-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.physical }, -// }, -// .@"border-left-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.physical }, -// }, -// .@"border-right-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.physical }, -// }, -// .@"border-block-start-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.logical }, -// }, -// .@"border-block-end-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.logical }, -// }, -// .@"border-inline-start-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.logical }, -// }, -// .@"border-inline-end-style" = .{ -// .ty = border.LineStyle, -// .logical_group = .{ .ty = LogicalGroup.border_style, .category = PropertyCategory.logical }, -// }, - -// .@"border-top-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.physical }, -// }, -// .@"border-bottom-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.physical }, -// }, -// .@"border-left-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.physical }, -// }, -// .@"border-right-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.physical }, -// }, -// .@"border-block-start-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.logical }, -// }, -// .@"border-block-end-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.logical }, -// }, -// .@"border-inline-start-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.logical }, -// }, -// .@"border-inline-end-width" = .{ -// .ty = BorderSideWidth, -// .logical_group = .{ .ty = LogicalGroup.border_width, .category = PropertyCategory.logical }, -// }, - -// .@"border-top-left-radius" = .{ -// .ty = struct { Size2D(LengthPercentage), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.physical }, -// }, -// .@"border-top-right-radius" = .{ -// .ty = struct { Size2D(LengthPercentage), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.physical }, -// }, -// .@"border-bottom-left-radius" = .{ -// .ty = struct { Size2D(LengthPercentage), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.physical }, -// }, -// .@"border-bottom-right-radius" = .{ -// .ty = struct { Size2D(LengthPercentage), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.physical }, -// }, -// .@"border-start-start-radius" = .{ -// .ty = Size2D(LengthPercentage), -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.logical }, -// }, -// .@"border-start-end-radius" = .{ -// .ty = Size2D(LengthPercentage), -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.logical }, -// }, -// .@"border-end-start-radius" = .{ -// .ty = Size2D(LengthPercentage), -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.logical }, -// }, -// .@"border-end-end-radius" = .{ -// .ty = Size2D(LengthPercentage), -// .logical_group = .{ .ty = LogicalGroup.border_radius, .category = PropertyCategory.logical }, -// }, -// .@"border-radius" = .{ -// .ty = struct { BorderRadius, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .shorthand = true, -// }, - -// .@"border-image-source" = .{ -// .ty = Image, -// }, -// .@"border-image-outset" = .{ -// .ty = Rect(LengthOrNumber), -// }, -// .@"border-image-repeat" = .{ -// .ty = BorderImageRepeat, -// }, -// .@"border-image-width" = .{ -// .ty = Rect(BorderImageSideWidth), -// }, -// .@"border-image-slice" = .{ -// .ty = BorderImageSlice, -// }, -// .@"border-image" = .{ -// .ty = struct { BorderImage, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// .shorthand = true, -// }, - -// .@"border-color" = .{ -// .ty = BorderColor, -// .shorthand = true, -// }, -// .@"border-style" = .{ -// .ty = BorderStyle, -// .shorthand = true, -// }, -// .@"border-width" = .{ -// .ty = BorderWidth, -// .shorthand = true, -// }, - -// .@"border-block-color" = .{ -// .ty = BorderBlockColor, -// .shorthand = true, -// }, -// .@"border-block-style" = .{ -// .ty = BorderBlockStyle, -// .shorthand = true, -// }, -// .@"border-block-width" = .{ -// .ty = BorderBlockWidth, -// .shorthand = true, -// }, - -// .@"border-inline-color" = .{ -// .ty = BorderInlineColor, -// .shorthand = true, -// }, -// .@"border-inline-style" = .{ -// .ty = BorderInlineStyle, -// .shorthand = true, -// }, -// .@"border-inline-width" = .{ -// .ty = BorderInlineWidth, -// .shorthand = true, -// }, - -// .border = .{ -// .ty = Border, -// .shorthand = true, -// }, -// .@"border-top" = .{ -// .ty = BorderTop, -// .shorthand = true, -// }, -// .@"border-bottom" = .{ -// .ty = BorderBottom, -// .shorthand = true, -// }, -// .@"border-left" = .{ -// .ty = BorderLeft, -// .shorthand = true, -// }, -// .@"border-right" = .{ -// .ty = BorderRight, -// .shorthand = true, -// }, -// .@"border-block" = .{ -// .ty = BorderBlock, -// .shorthand = true, -// }, -// .@"border-block-start" = .{ -// .ty = BorderBlockStart, -// .shorthand = true, -// }, -// .@"border-block-end" = .{ -// .ty = BorderBlockEnd, -// .shorthand = true, -// }, -// .@"border-inline" = .{ -// .ty = BorderInline, -// .shorthand = true, -// }, -// .@"border-inline-start" = .{ -// .ty = BorderInlineStart, -// .shorthand = true, -// }, -// .@"border-inline-end" = .{ -// .ty = BorderInlineEnd, -// .shorthand = true, -// }, - -// .outline = .{ -// .ty = Outline, -// .shorthand = true, -// }, -// .@"outline-color" = .{ -// .ty = CssColor, -// }, -// .@"outline-style" = .{ -// .ty = OutlineStyle, -// }, -// .@"outline-width" = .{ -// .ty = BorderSideWidth, -// }, - -// // Flex properties: https://www.w3.org/TR/2018/CR-css-flexbox-1-20181119 -// .@"flex-direction" = .{ -// .ty = struct { FlexDirection, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .ms = true, -// }, -// }, -// .@"flex-wrap" = .{ -// .ty = struct { FlexWrap, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .ms = true, -// }, -// }, -// .@"flex-flow" = .{ -// .ty = struct { FlexFlow, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .ms = true, -// }, -// .shorthand = true, -// }, -// .@"flex-grow" = .{ -// .ty = struct { CSSNumber, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"flex-shrink" = .{ -// .ty = struct { CSSNumber, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"flex-basis" = .{ -// .ty = struct { LengthPercentageOrAuto, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .flex = .{ -// .ty = struct { Flex, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .ms = true, -// }, -// .shorthand = true, -// }, -// .order = .{ -// .ty = struct { CSSInteger, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, - -// // Align properties: https://www.w3.org/TR/2020/WD-css-align-3-20200421 -// .@"align-content" = .{ -// .ty = struct { AlignContent, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"justify-content" = .{ -// .ty = struct { JustifyContent, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"place-content" = .{ -// .ty = PlaceContent, -// .shorthand = true, -// }, -// .@"align-self" = .{ -// .ty = struct { AlignSelf, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"justify-self" = .{ -// .ty = JustifySelf, -// }, -// .@"place-self" = .{ -// .ty = PlaceSelf, -// .shorthand = true, -// }, -// .@"align-items" = .{ -// .ty = struct { AlignItems, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"justify-items" = .{ -// .ty = JustifyItems, -// }, -// .@"place-items" = .{ -// .ty = PlaceItems, -// .shorthand = true, -// }, -// .@"row-gap" = .{ -// .ty = GapValue, -// }, -// .@"column-gap" = .{ -// .ty = GapValue, -// }, -// .gap = .{ -// .ty = Gap, -// .shorthand = true, -// }, - -// // Old flex (2009): https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/ -// .@"box-orient" = .{ -// .ty = struct { BoxOrient, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .unprefixed = false, -// }, -// .@"box-direction" = .{ -// .ty = struct { BoxDirection, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .unprefixed = false, -// }, -// .@"box-ordinal-group" = .{ -// .ty = struct { CSSInteger, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .unprefixed = false, -// }, -// .@"box-align" = .{ -// .ty = struct { BoxAlign, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .unprefixed = false, -// }, -// .@"box-flex" = .{ -// .ty = struct { CSSNumber, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .unprefixed = false, -// }, -// .@"box-flex-group" = .{ -// .ty = struct { CSSInteger, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, -// .@"box-pack" = .{ -// .ty = struct { BoxPack, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .unprefixed = false, -// }, -// .@"box-lines" = .{ -// .ty = struct { BoxLines, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .unprefixed = false, -// }, - -// // Old flex (2012): https://www.w3.org/TR/2012/WD-css3-flexbox-20120322/ -// .@"flex-pack" = .{ -// .ty = struct { FlexPack, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, -// .@"flex-order" = .{ -// .ty = struct { CSSInteger, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, -// .@"flex-align" = .{ -// .ty = struct { BoxAlign, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, -// .@"flex-item-align" = .{ -// .ty = struct { FlexItemAlign, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, -// .@"flex-line-pack" = .{ -// .ty = struct { FlexLinePack, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, - -// // Microsoft extensions -// .@"flex-positive" = .{ -// .ty = struct { CSSNumber, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, -// .@"flex-negative" = .{ -// .ty = struct { CSSNumber, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, -// .@"flex-preferred-size" = .{ -// .ty = struct { LengthPercentageOrAuto, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .ms = true, -// }, -// .unprefixed = false, -// }, - -// // TODO: the following is enabled with #[cfg(feature = "grid")] -// // .@"grid-template-columns" = .{ -// // .ty = TrackSizing, -// // }, -// // .@"grid-template-rows" = .{ -// // .ty = TrackSizing, -// // }, -// // .@"grid-auto-columns" = .{ -// // .ty = TrackSizeList, -// // }, -// // .@"grid-auto-rows" = .{ -// // .ty = TrackSizeList, -// // }, -// // .@"grid-auto-flow" = .{ -// // .ty = GridAutoFlow, -// // }, -// // .@"grid-template-areas" = .{ -// // .ty = GridTemplateAreas, -// // }, -// // .@"grid-template" = .{ -// // .ty = GridTemplate, -// // .shorthand = true, -// // }, -// // .grid = .{ -// // .ty = Grid, -// // .shorthand = true, -// // }, -// // .@"grid-row-start" = .{ -// // .ty = GridLine, -// // }, -// // .@"grid-row-end" = .{ -// // .ty = GridLine, -// // }, -// // .@"grid-column-start" = .{ -// // .ty = GridLine, -// // }, -// // .@"grid-column-end" = .{ -// // .ty = GridLine, -// // }, -// // .@"grid-row" = .{ -// // .ty = GridRow, -// // .shorthand = true, -// // }, -// // .@"grid-column" = .{ -// // .ty = GridColumn, -// // .shorthand = true, -// // }, -// // .@"grid-area" = .{ -// // .ty = GridArea, -// // .shorthand = true, -// // }, - -// .@"margin-top" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.physical }, -// }, -// .@"margin-bottom" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.physical }, -// }, -// .@"margin-left" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.physical }, -// }, -// .@"margin-right" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.physical }, -// }, -// .@"margin-block-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.logical }, -// }, -// .@"margin-block-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.logical }, -// }, -// .@"margin-inline-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.logical }, -// }, -// .@"margin-inline-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.margin, .category = PropertyCategory.logical }, -// }, -// .@"margin-block" = .{ -// .ty = MarginBlock, -// .shorthand = true, -// }, -// .@"margin-inline" = .{ -// .ty = MarginInline, -// .shorthand = true, -// }, -// .margin = .{ -// .ty = Margin, -// .shorthand = true, -// }, - -// .@"padding-top" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.physical }, -// }, -// .@"padding-bottom" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.physical }, -// }, -// .@"padding-left" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.physical }, -// }, -// .@"padding-right" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.physical }, -// }, -// .@"padding-block-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.logical }, -// }, -// .@"padding-block-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.logical }, -// }, -// .@"padding-inline-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.logical }, -// }, -// .@"padding-inline-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.padding, .category = PropertyCategory.logical }, -// }, -// .@"padding-block" = .{ -// .ty = PaddingBlock, -// .shorthand = true, -// }, -// .@"padding-inline" = .{ -// .ty = PaddingInline, -// .shorthand = true, -// }, -// .padding = .{ -// .ty = Padding, -// .shorthand = true, -// }, - -// .@"scroll-margin-top" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.physical }, -// }, -// .@"scroll-margin-bottom" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.physical }, -// }, -// .@"scroll-margin-left" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.physical }, -// }, -// .@"scroll-margin-right" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.physical }, -// }, -// .@"scroll-margin-block-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.logical }, -// }, -// .@"scroll-margin-block-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.logical }, -// }, -// .@"scroll-margin-inline-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.logical }, -// }, -// .@"scroll-margin-inline-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_margin, .category = PropertyCategory.logical }, -// }, -// .@"scroll-margin-block" = .{ -// .ty = ScrollMarginBlock, -// .shorthand = true, -// }, -// .@"scroll-margin-inline" = .{ -// .ty = ScrollMarginInline, -// .shorthand = true, -// }, -// .@"scroll-margin" = .{ -// .ty = ScrollMargin, -// .shorthand = true, -// }, - -// .@"scroll-padding-top" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.physical }, -// }, -// .@"scroll-padding-bottom" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.physical }, -// }, -// .@"scroll-padding-left" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.physical }, -// }, -// .@"scroll-padding-right" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.physical }, -// }, -// .@"scroll-padding-block-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.logical }, -// }, -// .@"scroll-padding-block-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.logical }, -// }, -// .@"scroll-padding-inline-start" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.logical }, -// }, -// .@"scroll-padding-inline-end" = .{ -// .ty = LengthPercentageOrAuto, -// .logical_group = .{ .ty = LogicalGroup.scroll_padding, .category = PropertyCategory.logical }, -// }, -// .@"scroll-padding-block" = .{ -// .ty = ScrollPaddingBlock, -// .shorthand = true, -// }, -// .@"scroll-padding-inline" = .{ -// .ty = ScrollPaddingInline, -// .shorthand = true, -// }, -// .@"scroll-padding" = .{ -// .ty = ScrollPadding, -// .shorthand = true, -// }, - -// .@"font-weight" = .{ -// .ty = FontWeight, -// }, -// .@"font-size" = .{ -// .ty = FontSize, -// }, -// .@"font-stretch" = .{ -// .ty = FontStretch, -// }, -// .@"font-family" = .{ -// .ty = ArrayList(FontFamily), -// }, -// .@"font-style" = .{ -// .ty = FontStyle, -// }, -// .@"font-variant-caps" = .{ -// .ty = FontVariantCaps, -// }, -// .@"line-height" = .{ -// .ty = LineHeight, -// }, -// .font = .{ -// .ty = Font, -// .shorthand = true, -// }, -// .@"vertical-align" = .{ -// .ty = VerticalAlign, -// }, -// .@"font-palette" = .{ -// .ty = DashedIdentReference, -// }, - -// .@"transition-property" = .{ -// .ty = struct { SmallListPropertyIdPlaceholder, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, -// .@"transition-duration" = .{ -// .ty = struct { SmallList(Time, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, -// .@"transition-delay" = .{ -// .ty = struct { SmallList(Time, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, -// .@"transition-timing-function" = .{ -// .ty = struct { SmallList(EasingFunction, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, -// .transition = .{ -// .ty = struct { SmallList(Transition, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// .shorthand = true, -// }, - -// .@"animation-name" = .{ -// .ty = struct { AnimationNameList, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-duration" = .{ -// .ty = struct { SmallList(Time, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-timing-function" = .{ -// .ty = struct { SmallList(EasingFunction, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-iteration-count" = .{ -// .ty = struct { SmallList(AnimationIterationCount, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-direction" = .{ -// .ty = struct { SmallList(AnimationDirection, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-play-state" = .{ -// .ty = struct { SmallList(AnimationPlayState, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-delay" = .{ -// .ty = struct { SmallList(Time, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-fill-mode" = .{ -// .ty = struct { SmallList(AnimationFillMode, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// }, -// .@"animation-composition" = .{ -// .ty = SmallList(AnimationComposition, 1), -// }, -// .@"animation-timeline" = .{ -// .ty = SmallList(AnimationTimeline, 1), -// }, -// .@"animation-range-start" = .{ -// .ty = SmallList(AnimationRangeStart, 1), -// }, -// .@"animation-range-end" = .{ -// .ty = SmallList(AnimationRangeEnd, 1), -// }, -// .@"animation-range" = .{ -// .ty = SmallList(AnimationRange, 1), -// }, -// .animation = .{ -// .ty = struct { AnimationList, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .o = true, -// }, -// .shorthand = true, -// }, - -// // https://drafts.csswg.org/css-transforms-2/ -// .transform = .{ -// .ty = struct { TransformList, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// .o = true, -// }, -// }, -// .@"transform-origin" = .{ -// .ty = struct { Position, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// .o = true, -// }, -// // TODO: handle z offset syntax -// }, -// .@"transform-style" = .{ -// .ty = struct { TransformStyle, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .@"transform-box" = .{ -// .ty = TransformBox, -// }, -// .@"backface-visibility" = .{ -// .ty = struct { BackfaceVisibility, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .perspective = .{ -// .ty = struct { Perspective, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .@"perspective-origin" = .{ -// .ty = struct { Position, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .translate = .{ -// .ty = Translate, -// }, -// .rotate = .{ -// .ty = Rotate, -// }, -// .scale = .{ -// .ty = Scale, -// }, - -// // https://www.w3.org/TR/2021/CRD-css-text-3-20210422 -// .@"text-transform" = .{ -// .ty = TextTransform, -// }, -// .@"white-space" = .{ -// .ty = WhiteSpace, -// }, -// .@"tab-size" = .{ -// .ty = struct { LengthOrNumber, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .moz = true, -// .o = true, -// }, -// }, -// .@"word-break" = .{ -// .ty = WordBreak, -// }, -// .@"line-break" = .{ -// .ty = LineBreak, -// }, -// .hyphens = .{ -// .ty = struct { Hyphens, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, -// .@"overflow-wrap" = .{ -// .ty = OverflowWrap, -// }, -// .@"word-wrap" = .{ -// .ty = OverflowWrap, -// }, -// .@"text-align" = .{ -// .ty = TextAlign, -// }, -// .@"text-align-last" = .{ -// .ty = struct { TextAlignLast, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .moz = true, -// }, -// }, -// .@"text-justify" = .{ -// .ty = TextJustify, -// }, -// .@"word-spacing" = .{ -// .ty = Spacing, -// }, -// .@"letter-spacing" = .{ -// .ty = Spacing, -// }, -// .@"text-indent" = .{ -// .ty = TextIndent, -// }, - -// // https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506 -// .@"text-decoration-line" = .{ -// .ty = struct { TextDecorationLine, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .@"text-decoration-style" = .{ -// .ty = struct { TextDecorationStyle, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .@"text-decoration-color" = .{ -// .ty = struct { CssColor, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// }, -// .@"text-decoration-thickness" = .{ -// .ty = TextDecorationThickness, -// }, -// .@"text-decoration" = .{ -// .ty = struct { TextDecoration, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// }, -// .shorthand = true, -// }, -// .@"text-decoration-skip-ink" = .{ -// .ty = struct { TextDecorationSkipInk, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"text-emphasis-style" = .{ -// .ty = struct { TextEmphasisStyle, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"text-emphasis-color" = .{ -// .ty = struct { CssColor, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"text-emphasis" = .{ -// .ty = struct { TextEmphasis, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .shorthand = true, -// }, -// .@"text-emphasis-position" = .{ -// .ty = struct { TextEmphasisPosition, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"text-shadow" = .{ -// .ty = SmallList(TextShadow, 1), -// }, - -// // https://w3c.github.io/csswg-drafts/css-size-adjust/ -// .@"text-size-adjust" = .{ -// .ty = struct { TextSizeAdjust, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, - -// // https://drafts.csswg.org/css-writing-modes-3/ -// .direction = .{ -// .ty = Direction, -// }, -// .@"unicode-bidi" = .{ -// .ty = UnicodeBidi, -// }, - -// // https://www.w3.org/TR/css-break-3/ -// .@"box-decoration-break" = .{ -// .ty = struct { BoxDecorationBreak, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, - -// // https://www.w3.org/TR/2021/WD-css-ui-4-20210316 -// .resize = .{ -// .ty = Resize, -// }, -// .cursor = .{ -// .ty = Cursor, -// }, -// .@"caret-color" = .{ -// .ty = ColorOrAuto, -// }, -// .@"caret-shape" = .{ -// .ty = CaretShape, -// }, -// .caret = .{ -// .ty = Caret, -// .shorthand = true, -// }, -// .@"user-select" = .{ -// .ty = struct { UserSelect, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, -// .@"accent-color" = .{ -// .ty = ColorOrAuto, -// }, -// .appearance = .{ -// .ty = struct { Appearance, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// .moz = true, -// .ms = true, -// }, -// }, - -// // https://www.w3.org/TR/2020/WD-css-lists-3-20201117 -// .@"list-style-type" = .{ -// .ty = ListStyleType, -// }, -// .@"list-style-image" = .{ -// .ty = Image, -// }, -// .@"list-style-position" = .{ -// .ty = ListStylePosition, -// }, -// .@"list-style" = .{ -// .ty = ListStyle, -// .shorthand = true, -// }, -// .@"marker-side" = .{ -// .ty = MarkerSide, -// }, - -// // CSS modules -// .composes = .{ -// .ty = Composes, -// .conditional = .{ -// .css_modules = true, -// }, -// }, - -// // https://www.w3.org/TR/SVG2/painting.html -// .fill = .{ -// .ty = SVGPaint, -// }, -// .@"fill-rule" = .{ -// .ty = FillRule, -// }, -// .@"fill-opacity" = .{ -// .ty = AlphaValue, -// }, -// .stroke = .{ -// .ty = SVGPaint, -// }, -// .@"stroke-opacity" = .{ -// .ty = AlphaValue, -// }, -// .@"stroke-width" = .{ -// .ty = LengthPercentage, -// }, -// .@"stroke-linecap" = .{ -// .ty = StrokeLinecap, -// }, -// .@"stroke-linejoin" = .{ -// .ty = StrokeLinejoin, -// }, -// .@"stroke-miterlimit" = .{ -// .ty = CSSNumber, -// }, -// .@"stroke-dasharray" = .{ -// .ty = StrokeDasharray, -// }, -// .@"stroke-dashoffset" = .{ -// .ty = LengthPercentage, -// }, -// .@"marker-start" = .{ -// .ty = Marker, -// }, -// .@"marker-mid" = .{ -// .ty = Marker, -// }, -// .@"marker-end" = .{ -// .ty = Marker, -// }, -// .marker = .{ -// .ty = Marker, -// }, -// .@"color-interpolation" = .{ -// .ty = ColorInterpolation, -// }, -// .@"color-interpolation-filters" = .{ -// .ty = ColorInterpolation, -// }, -// .@"color-rendering" = .{ -// .ty = ColorRendering, -// }, -// .@"shape-rendering" = .{ -// .ty = ShapeRendering, -// }, -// .@"text-rendering" = .{ -// .ty = TextRendering, -// }, -// .@"image-rendering" = .{ -// .ty = ImageRendering, -// }, - -// // https://www.w3.org/TR/css-masking-1/ -// .@"clip-path" = .{ -// .ty = struct { ClipPath, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"clip-rule" = .{ -// .ty = FillRule, -// }, -// .@"mask-image" = .{ -// .ty = struct { SmallList(Image, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"mask-mode" = .{ -// .ty = SmallList(MaskMode, 1), -// }, -// .@"mask-repeat" = .{ -// .ty = struct { SmallList(BackgroundRepeat, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"mask-position-x" = .{ -// .ty = SmallList(HorizontalPosition, 1), -// }, -// .@"mask-position-y" = .{ -// .ty = SmallList(VerticalPosition, 1), -// }, -// .@"mask-position" = .{ -// .ty = struct { SmallList(Position, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"mask-clip" = .{ -// .ty = struct { SmallList(MaskClip, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"mask-origin" = .{ -// .ty = struct { SmallList(GeometryBox, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"mask-size" = .{ -// .ty = struct { SmallList(BackgroundSize, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"mask-composite" = .{ -// .ty = SmallList(MaskComposite, 1), -// }, -// .@"mask-type" = .{ -// .ty = MaskType, -// }, -// .mask = .{ -// .ty = struct { SmallList(Mask, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .shorthand = true, -// }, -// .@"mask-border-source" = .{ -// .ty = Image, -// }, -// .@"mask-border-mode" = .{ -// .ty = MaskBorderMode, -// }, -// .@"mask-border-slice" = .{ -// .ty = BorderImageSlice, -// }, -// .@"mask-border-width" = .{ -// .ty = Rect(BorderImageSideWidth), -// }, -// .@"mask-border-outset" = .{ -// .ty = Rect(LengthOrNumber), -// }, -// .@"mask-border-repeat" = .{ -// .ty = BorderImageRepeat, -// }, -// .@"mask-border" = .{ -// .ty = MaskBorder, -// .shorthand = true, -// }, - -// // WebKit additions -// .@"-webkit-mask-composite" = .{ -// .ty = SmallList(WebKitMaskComposite, 1), -// }, -// .@"mask-source-type" = .{ -// .ty = struct { SmallList(WebKitMaskSourceType, 1), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, -// .@"mask-box-image" = .{ -// .ty = struct { BorderImage, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, -// .@"mask-box-image-source" = .{ -// .ty = struct { Image, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, -// .@"mask-box-image-slice" = .{ -// .ty = struct { BorderImageSlice, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, -// .@"mask-box-image-width" = .{ -// .ty = struct { Rect(BorderImageSideWidth), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, -// .@"mask-box-image-outset" = .{ -// .ty = struct { Rect(LengthOrNumber), css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, -// .@"mask-box-image-repeat" = .{ -// .ty = struct { BorderImageRepeat, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// .unprefixed = false, -// }, - -// // https://drafts.fxtf.org/filter-effects-1/ -// .filter = .{ -// .ty = struct { FilterList, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, -// .@"backdrop-filter" = .{ -// .ty = struct { FilterList, css.VendorPrefix }, -// .valid_prefixes = css.VendorPrefix{ -// .webkit = true, -// }, -// }, - -// // https://drafts.csswg.org/css2/ -// .@"z-index" = .{ -// .ty = position.ZIndex, -// }, - -// // https://drafts.csswg.org/css-contain-3/ -// .@"container-type" = .{ -// .ty = ContainerType, -// }, -// .@"container-name" = .{ -// .ty = ContainerNameList, -// }, -// .container = .{ -// .ty = Container, -// .shorthand = true, -// }, - -// // https://w3c.github.io/csswg-drafts/css-view-transitions-1/ -// .@"view-transition-name" = .{ -// .ty = CustomIdent, -// }, - -// // https://drafts.csswg.org/css-color-adjust/ -// .@"color-scheme" = .{ -// .ty = ColorScheme, -// }, -// }); - -const bun = @import("bun"); -const generated = @import("./properties_generated.zig"); - -const css = @import("../css_parser.zig"); -const Error = css.Error; -const SmallList = css.SmallList; - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/properties/properties_generated.rs b/src/css/properties/properties_generated.rs index 50e80d01d4a2..dd667de4fc7c 100644 --- a/src/css/properties/properties_generated.rs +++ b/src/css/properties/properties_generated.rs @@ -1,5 +1,4 @@ -// Hand-maintained. Note: generate_properties.ts (`bun run css-properties`) -// does not write this file — edits here are safe and will not be clobbered. +// Hand-maintained. // // Type paths below resolve against `super::*` (the leaf property // modules — currently data-only stub bodies in `mod.rs`) and diff --git a/src/css/properties/properties_generated.zig b/src/css/properties/properties_generated.zig deleted file mode 100644 index 0ce9e9b1300e..000000000000 --- a/src/css/properties/properties_generated.zig +++ /dev/null @@ -1,10362 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const VendorPrefix = css.VendorPrefix; - -const CSSWideKeyword = css.css_properties.CSSWideKeyword; -const UnparsedProperty = css.css_properties.custom.UnparsedProperty; -const CustomProperty = css.css_properties.custom.CustomProperty; -const Targets = css.targets.Targets; -const Feature = css.prefixes.Feature; - -const ColorScheme = css.css_properties.ui.ColorScheme; - -const TransformList = css.css_properties.transform.TransformList; -const TransformStyle = css.css_properties.transform.TransformStyle; -const TransformBox = css.css_properties.transform.TransformBox; -const BackfaceVisibility = css.css_properties.transform.BackfaceVisibility; -const Perspective = css.css_properties.transform.Perspective; -const Translate = css.css_properties.transform.Translate; -const Rotate = css.css_properties.transform.Rotate; -const Scale = css.css_properties.transform.Scale; - -const css_values = css.css_values; -const CssColor = css.css_values.color.CssColor; -const Image = css.css_values.image.Image; -const Length = css.css_values.length.Length; -const LengthPercentage = css_values.length.LengthPercentage; -const LengthPercentageOrAuto = css_values.length.LengthPercentageOrAuto; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const CSSInteger = css.css_values.number.CSSInteger; -const CSSIntegerFns = css.css_values.number.CSSIntegerFns; -const Time = css.css_values.time.Time; -const EasingFunction = css.css_values.easing.EasingFunction; -const HorizontalPosition = css.css_values.position.HorizontalPosition; -const VerticalPosition = css.css_values.position.VerticalPosition; - -pub const font = css.css_properties.font; -const border = css.css_properties.border; -const border_radius = css.css_properties.border_radius; -const border_image = css.css_properties.border_image; -const outline = css.css_properties.outline; -const flex = css.css_properties.flex; -const @"align" = css.css_properties.@"align"; -const margin_padding = css.css_properties.margin_padding; -const transition = css.css_properties.transition; -const animation = css.css_properties.animation; -const transform = css.css_properties.transform; -const text = css.css_properties.text; -const ui = css.css_properties.ui; -const list = css.css_properties.list; -const css_modules = css.css_properties.css_modules; -const svg = css.css_properties.svg; -const shape = css.css_properties.shape; -const masking = css.css_properties.masking; -const background = css.css_properties.background; -const effects = css.css_properties.effects; -const contain = css.css_properties.contain; -const custom = css.css_properties.custom; -const position = css.css_properties.position; -const box_shadow = css.css_properties.box_shadow; -const size = css.css_properties.size; -const overflow = css.css_properties.overflow; - -const BorderSideWidth = border.BorderSideWidth; -const Size2D = css_values.size.Size2D; -const BorderRadius = border_radius.BorderRadius; -const Rect = css_values.rect.Rect; -const LengthOrNumber = css_values.length.LengthOrNumber; -const BorderImageRepeat = border_image.BorderImageRepeat; -const BorderImageSideWidth = border_image.BorderImageSideWidth; -const BorderImageSlice = border_image.BorderImageSlice; -const BorderImage = border_image.BorderImage; -const BorderColor = border.BorderColor; -const BorderStyle = border.BorderStyle; -const BorderWidth = border.BorderWidth; -const BorderBlockColor = border.BorderBlockColor; -const BorderBlockStyle = border.BorderBlockStyle; -const BorderBlockWidth = border.BorderBlockWidth; -const BorderInlineColor = border.BorderInlineColor; -const BorderInlineStyle = border.BorderInlineStyle; -const BorderInlineWidth = border.BorderInlineWidth; -const Border = border.Border; -const BorderTop = border.BorderTop; -const BorderRight = border.BorderRight; -const BorderLeft = border.BorderLeft; -const BorderBottom = border.BorderBottom; -const BorderBlockStart = border.BorderBlockStart; -const BorderBlockEnd = border.BorderBlockEnd; -const BorderInlineStart = border.BorderInlineStart; -const BorderInlineEnd = border.BorderInlineEnd; -const BorderBlock = border.BorderBlock; -const BorderInline = border.BorderInline; -const Outline = outline.Outline; -const OutlineStyle = outline.OutlineStyle; -const FlexDirection = flex.FlexDirection; -const FlexWrap = flex.FlexWrap; -const FlexFlow = flex.FlexFlow; -const Flex = flex.Flex; -const BoxOrient = flex.BoxOrient; -const BoxDirection = flex.BoxDirection; -const BoxAlign = flex.BoxAlign; -const BoxPack = flex.BoxPack; -const BoxLines = flex.BoxLines; -const FlexPack = flex.FlexPack; -const FlexItemAlign = flex.FlexItemAlign; -const FlexLinePack = flex.FlexLinePack; -const AlignContent = @"align".AlignContent; -const JustifyContent = @"align".JustifyContent; -const PlaceContent = @"align".PlaceContent; -const AlignSelf = @"align".AlignSelf; -const JustifySelf = @"align".JustifySelf; -const PlaceSelf = @"align".PlaceSelf; -const AlignItems = @"align".AlignItems; -const JustifyItems = @"align".JustifyItems; -const PlaceItems = @"align".PlaceItems; -const GapValue = @"align".GapValue; -const Gap = @"align".Gap; -const MarginBlock = margin_padding.MarginBlock; -const Margin = margin_padding.Margin; -const MarginInline = margin_padding.MarginInline; -const PaddingBlock = margin_padding.PaddingBlock; -const PaddingInline = margin_padding.PaddingInline; -const Padding = margin_padding.Padding; -const ScrollMarginBlock = margin_padding.ScrollMarginBlock; -const ScrollMarginInline = margin_padding.ScrollMarginInline; -const ScrollMargin = margin_padding.ScrollMargin; -const ScrollPaddingBlock = margin_padding.ScrollPaddingBlock; -const ScrollPaddingInline = margin_padding.ScrollPaddingInline; -const ScrollPadding = margin_padding.ScrollPadding; -const FontWeight = font.FontWeight; -const FontSize = font.FontSize; -const FontStretch = font.FontStretch; -const FontFamily = font.FontFamily; -const FontStyle = font.FontStyle; -const FontVariantCaps = font.FontVariantCaps; -const LineHeight = font.LineHeight; -const Font = font.Font; -// const VerticalAlign = font.VerticalAlign; -const Transition = transition.Transition; -// const AnimationNameList = animation.AnimationNameList; -// const AnimationList = animation.AnimationList; -// const AnimationIterationCount = animation.AnimationIterationCount; -// const AnimationDirection = animation.AnimationDirection; -// const AnimationPlayState = animation.AnimationPlayState; -// const AnimationFillMode = animation.AnimationFillMode; -// const AnimationComposition = animation.AnimationComposition; -// const AnimationTimeline = animation.AnimationTimeline; -// const AnimationRangeStart = animation.AnimationRangeStart; -// const AnimationRangeEnd = animation.AnimationRangeEnd; -// const AnimationRange = animation.AnimationRange; -// const TransformList = transform.TransformList; -// const TransformStyle = transform.TransformStyle; -// const TransformBox = transform.TransformBox; -// const BackfaceVisibility = transform.BackfaceVisibility; -// const Perspective = transform.Perspective; -// const Translate = transform.Translate; -// const Rotate = transform.Rotate; -// const Scale = transform.Scale; -// const TextTransform = text.TextTransform; -// const WhiteSpace = text.WhiteSpace; -// const WordBreak = text.WordBreak; -// const LineBreak = text.LineBreak; -// const Hyphens = text.Hyphens; -// const OverflowWrap = text.OverflowWrap; -// const TextAlign = text.TextAlign; -// const TextIndent = text.TextIndent; -// const Spacing = text.Spacing; -// const TextJustify = text.TextJustify; -// const TextAlignLast = text.TextAlignLast; -// const TextDecorationLine = text.TextDecorationLine; -// const TextDecorationStyle = text.TextDecorationStyle; -// const TextDecorationThickness = text.TextDecorationThickness; -// const TextDecoration = text.TextDecoration; -// const TextDecorationSkipInk = text.TextDecorationSkipInk; -// const TextEmphasisStyle = text.TextEmphasisStyle; -// const TextEmphasis = text.TextEmphasis; -// const TextEmphasisPositionVertical = text.TextEmphasisPositionVertical; -// const TextEmphasisPositionHorizontal = text.TextEmphasisPositionHorizontal; -// const TextEmphasisPosition = text.TextEmphasisPosition; -const TextShadow = text.TextShadow; -// const TextSizeAdjust = text.TextSizeAdjust; -const Direction = text.Direction; -// const UnicodeBidi = text.UnicodeBidi; -// const BoxDecorationBreak = text.BoxDecorationBreak; -// const Resize = ui.Resize; -// const Cursor = ui.Cursor; -// const ColorOrAuto = ui.ColorOrAuto; -// const CaretShape = ui.CaretShape; -// const Caret = ui.Caret; -// const UserSelect = ui.UserSelect; -// const Appearance = ui.Appearance; -// const ColorScheme = ui.ColorScheme; -// const ListStyleType = list.ListStyleType; -// const ListStylePosition = list.ListStylePosition; -// const ListStyle = list.ListStyle; -// const MarkerSide = list.MarkerSide; -const Composes = css_modules.Composes; -// const SVGPaint = svg.SVGPaint; -// const FillRule = shape.FillRule; -// const AlphaValue = shape.AlphaValue; -// const StrokeLinecap = svg.StrokeLinecap; -// const StrokeLinejoin = svg.StrokeLinejoin; -// const StrokeDasharray = svg.StrokeDasharray; -// const Marker = svg.Marker; -// const ColorInterpolation = svg.ColorInterpolation; -// const ColorRendering = svg.ColorRendering; -// const ShapeRendering = svg.ShapeRendering; -// const TextRendering = svg.TextRendering; -// const ImageRendering = svg.ImageRendering; -const MaskMode = masking.MaskMode; -const MaskClip = masking.MaskClip; -const GeometryBox = masking.GeometryBox; -const MaskComposite = masking.MaskComposite; -const MaskType = masking.MaskType; -const Mask = masking.Mask; -const MaskBorderMode = masking.MaskBorderMode; -const MaskBorder = masking.MaskBorder; -const WebKitMaskComposite = masking.WebKitMaskComposite; -const WebKitMaskSourceType = masking.WebKitMaskSourceType; -const BackgroundRepeat = background.BackgroundRepeat; -const BackgroundSize = background.BackgroundSize; -// const FilterList = effects.FilterList; -// const ContainerType = contain.ContainerType; -// const Container = contain.Container; -// const ContainerNameList = contain.ContainerNameList; -const CustomPropertyName = custom.CustomPropertyName; -const display = css.css_properties.display; - -const Position = position.Position; - -const Result = css.Result; - -const SmallList = css.SmallList; -pub const Property = union(PropertyIdTag) { - @"background-color": CssColor, - @"background-image": SmallList(Image, 1), - @"background-position-x": SmallList(css_values.position.HorizontalPosition, 1), - @"background-position-y": SmallList(css_values.position.VerticalPosition, 1), - @"background-position": SmallList(background.BackgroundPosition, 1), - @"background-size": SmallList(background.BackgroundSize, 1), - @"background-repeat": SmallList(background.BackgroundRepeat, 1), - @"background-attachment": SmallList(background.BackgroundAttachment, 1), - @"background-clip": struct { SmallList(background.BackgroundClip, 1), VendorPrefix }, - @"background-origin": SmallList(background.BackgroundOrigin, 1), - background: SmallList(background.Background, 1), - @"box-shadow": struct { SmallList(box_shadow.BoxShadow, 1), VendorPrefix }, - opacity: css.css_values.alpha.AlphaValue, - color: CssColor, - display: display.Display, - visibility: display.Visibility, - width: size.Size, - height: size.Size, - @"min-width": size.Size, - @"min-height": size.Size, - @"max-width": size.MaxSize, - @"max-height": size.MaxSize, - @"block-size": size.Size, - @"inline-size": size.Size, - @"min-block-size": size.Size, - @"min-inline-size": size.Size, - @"max-block-size": size.MaxSize, - @"max-inline-size": size.MaxSize, - @"box-sizing": struct { size.BoxSizing, VendorPrefix }, - @"aspect-ratio": size.AspectRatio, - overflow: overflow.Overflow, - @"overflow-x": overflow.OverflowKeyword, - @"overflow-y": overflow.OverflowKeyword, - @"text-overflow": struct { overflow.TextOverflow, VendorPrefix }, - position: position.Position, - top: LengthPercentageOrAuto, - bottom: LengthPercentageOrAuto, - left: LengthPercentageOrAuto, - right: LengthPercentageOrAuto, - @"inset-block-start": LengthPercentageOrAuto, - @"inset-block-end": LengthPercentageOrAuto, - @"inset-inline-start": LengthPercentageOrAuto, - @"inset-inline-end": LengthPercentageOrAuto, - @"inset-block": margin_padding.InsetBlock, - @"inset-inline": margin_padding.InsetInline, - inset: margin_padding.Inset, - @"border-spacing": css.css_values.size.Size2D(Length), - @"border-top-color": CssColor, - @"border-bottom-color": CssColor, - @"border-left-color": CssColor, - @"border-right-color": CssColor, - @"border-block-start-color": CssColor, - @"border-block-end-color": CssColor, - @"border-inline-start-color": CssColor, - @"border-inline-end-color": CssColor, - @"border-top-style": border.LineStyle, - @"border-bottom-style": border.LineStyle, - @"border-left-style": border.LineStyle, - @"border-right-style": border.LineStyle, - @"border-block-start-style": border.LineStyle, - @"border-block-end-style": border.LineStyle, - @"border-inline-start-style": border.LineStyle, - @"border-inline-end-style": border.LineStyle, - @"border-top-width": BorderSideWidth, - @"border-bottom-width": BorderSideWidth, - @"border-left-width": BorderSideWidth, - @"border-right-width": BorderSideWidth, - @"border-block-start-width": BorderSideWidth, - @"border-block-end-width": BorderSideWidth, - @"border-inline-start-width": BorderSideWidth, - @"border-inline-end-width": BorderSideWidth, - @"border-top-left-radius": struct { Size2D(LengthPercentage), VendorPrefix }, - @"border-top-right-radius": struct { Size2D(LengthPercentage), VendorPrefix }, - @"border-bottom-left-radius": struct { Size2D(LengthPercentage), VendorPrefix }, - @"border-bottom-right-radius": struct { Size2D(LengthPercentage), VendorPrefix }, - @"border-start-start-radius": Size2D(LengthPercentage), - @"border-start-end-radius": Size2D(LengthPercentage), - @"border-end-start-radius": Size2D(LengthPercentage), - @"border-end-end-radius": Size2D(LengthPercentage), - @"border-radius": struct { BorderRadius, VendorPrefix }, - @"border-image-source": Image, - @"border-image-outset": Rect(LengthOrNumber), - @"border-image-repeat": BorderImageRepeat, - @"border-image-width": Rect(BorderImageSideWidth), - @"border-image-slice": BorderImageSlice, - @"border-image": struct { BorderImage, VendorPrefix }, - @"border-color": BorderColor, - @"border-style": BorderStyle, - @"border-width": BorderWidth, - @"border-block-color": BorderBlockColor, - @"border-block-style": BorderBlockStyle, - @"border-block-width": BorderBlockWidth, - @"border-inline-color": BorderInlineColor, - @"border-inline-style": BorderInlineStyle, - @"border-inline-width": BorderInlineWidth, - border: Border, - @"border-top": BorderTop, - @"border-bottom": BorderBottom, - @"border-left": BorderLeft, - @"border-right": BorderRight, - @"border-block": BorderBlock, - @"border-block-start": BorderBlockStart, - @"border-block-end": BorderBlockEnd, - @"border-inline": BorderInline, - @"border-inline-start": BorderInlineStart, - @"border-inline-end": BorderInlineEnd, - outline: Outline, - @"outline-color": CssColor, - @"outline-style": OutlineStyle, - @"outline-width": BorderSideWidth, - @"flex-direction": struct { FlexDirection, VendorPrefix }, - @"flex-wrap": struct { FlexWrap, VendorPrefix }, - @"flex-flow": struct { FlexFlow, VendorPrefix }, - @"flex-grow": struct { CSSNumber, VendorPrefix }, - @"flex-shrink": struct { CSSNumber, VendorPrefix }, - @"flex-basis": struct { LengthPercentageOrAuto, VendorPrefix }, - flex: struct { Flex, VendorPrefix }, - order: struct { CSSInteger, VendorPrefix }, - @"align-content": struct { AlignContent, VendorPrefix }, - @"justify-content": struct { JustifyContent, VendorPrefix }, - @"place-content": PlaceContent, - @"align-self": struct { AlignSelf, VendorPrefix }, - @"justify-self": JustifySelf, - @"place-self": PlaceSelf, - @"align-items": struct { AlignItems, VendorPrefix }, - @"justify-items": JustifyItems, - @"place-items": PlaceItems, - @"row-gap": GapValue, - @"column-gap": GapValue, - gap: Gap, - @"box-orient": struct { BoxOrient, VendorPrefix }, - @"box-direction": struct { BoxDirection, VendorPrefix }, - @"box-ordinal-group": struct { CSSInteger, VendorPrefix }, - @"box-align": struct { BoxAlign, VendorPrefix }, - @"box-flex": struct { CSSNumber, VendorPrefix }, - @"box-flex-group": struct { CSSInteger, VendorPrefix }, - @"box-pack": struct { BoxPack, VendorPrefix }, - @"box-lines": struct { BoxLines, VendorPrefix }, - @"flex-pack": struct { FlexPack, VendorPrefix }, - @"flex-order": struct { CSSInteger, VendorPrefix }, - @"flex-align": struct { BoxAlign, VendorPrefix }, - @"flex-item-align": struct { FlexItemAlign, VendorPrefix }, - @"flex-line-pack": struct { FlexLinePack, VendorPrefix }, - @"flex-positive": struct { CSSNumber, VendorPrefix }, - @"flex-negative": struct { CSSNumber, VendorPrefix }, - @"flex-preferred-size": struct { LengthPercentageOrAuto, VendorPrefix }, - @"margin-top": LengthPercentageOrAuto, - @"margin-bottom": LengthPercentageOrAuto, - @"margin-left": LengthPercentageOrAuto, - @"margin-right": LengthPercentageOrAuto, - @"margin-block-start": LengthPercentageOrAuto, - @"margin-block-end": LengthPercentageOrAuto, - @"margin-inline-start": LengthPercentageOrAuto, - @"margin-inline-end": LengthPercentageOrAuto, - @"margin-block": MarginBlock, - @"margin-inline": MarginInline, - margin: Margin, - @"padding-top": LengthPercentageOrAuto, - @"padding-bottom": LengthPercentageOrAuto, - @"padding-left": LengthPercentageOrAuto, - @"padding-right": LengthPercentageOrAuto, - @"padding-block-start": LengthPercentageOrAuto, - @"padding-block-end": LengthPercentageOrAuto, - @"padding-inline-start": LengthPercentageOrAuto, - @"padding-inline-end": LengthPercentageOrAuto, - @"padding-block": PaddingBlock, - @"padding-inline": PaddingInline, - padding: Padding, - @"scroll-margin-top": LengthPercentageOrAuto, - @"scroll-margin-bottom": LengthPercentageOrAuto, - @"scroll-margin-left": LengthPercentageOrAuto, - @"scroll-margin-right": LengthPercentageOrAuto, - @"scroll-margin-block-start": LengthPercentageOrAuto, - @"scroll-margin-block-end": LengthPercentageOrAuto, - @"scroll-margin-inline-start": LengthPercentageOrAuto, - @"scroll-margin-inline-end": LengthPercentageOrAuto, - @"scroll-margin-block": ScrollMarginBlock, - @"scroll-margin-inline": ScrollMarginInline, - @"scroll-margin": ScrollMargin, - @"scroll-padding-top": LengthPercentageOrAuto, - @"scroll-padding-bottom": LengthPercentageOrAuto, - @"scroll-padding-left": LengthPercentageOrAuto, - @"scroll-padding-right": LengthPercentageOrAuto, - @"scroll-padding-block-start": LengthPercentageOrAuto, - @"scroll-padding-block-end": LengthPercentageOrAuto, - @"scroll-padding-inline-start": LengthPercentageOrAuto, - @"scroll-padding-inline-end": LengthPercentageOrAuto, - @"scroll-padding-block": ScrollPaddingBlock, - @"scroll-padding-inline": ScrollPaddingInline, - @"scroll-padding": ScrollPadding, - @"font-weight": FontWeight, - @"font-size": FontSize, - @"font-stretch": FontStretch, - @"font-family": BabyList(FontFamily), - @"font-style": FontStyle, - @"font-variant-caps": FontVariantCaps, - @"line-height": LineHeight, - font: Font, - @"transition-property": struct { SmallList(PropertyId, 1), VendorPrefix }, - @"transition-duration": struct { SmallList(Time, 1), VendorPrefix }, - @"transition-delay": struct { SmallList(Time, 1), VendorPrefix }, - @"transition-timing-function": struct { SmallList(EasingFunction, 1), VendorPrefix }, - transition: struct { SmallList(Transition, 1), VendorPrefix }, - transform: struct { TransformList, VendorPrefix }, - @"transform-origin": struct { Position, VendorPrefix }, - @"transform-style": struct { TransformStyle, VendorPrefix }, - @"transform-box": TransformBox, - @"backface-visibility": struct { BackfaceVisibility, VendorPrefix }, - perspective: struct { Perspective, VendorPrefix }, - @"perspective-origin": struct { Position, VendorPrefix }, - translate: Translate, - rotate: Rotate, - scale: Scale, - @"text-decoration-color": struct { CssColor, VendorPrefix }, - @"text-emphasis-color": struct { CssColor, VendorPrefix }, - @"text-shadow": SmallList(TextShadow, 1), - direction: Direction, - composes: Composes, - @"mask-image": struct { SmallList(Image, 1), VendorPrefix }, - @"mask-mode": SmallList(MaskMode, 1), - @"mask-repeat": struct { SmallList(BackgroundRepeat, 1), VendorPrefix }, - @"mask-position-x": SmallList(HorizontalPosition, 1), - @"mask-position-y": SmallList(VerticalPosition, 1), - @"mask-position": struct { SmallList(Position, 1), VendorPrefix }, - @"mask-clip": struct { SmallList(MaskClip, 1), VendorPrefix }, - @"mask-origin": struct { SmallList(GeometryBox, 1), VendorPrefix }, - @"mask-size": struct { SmallList(BackgroundSize, 1), VendorPrefix }, - @"mask-composite": SmallList(MaskComposite, 1), - @"mask-type": MaskType, - mask: struct { SmallList(Mask, 1), VendorPrefix }, - @"mask-border-source": Image, - @"mask-border-mode": MaskBorderMode, - @"mask-border-slice": BorderImageSlice, - @"mask-border-width": Rect(BorderImageSideWidth), - @"mask-border-outset": Rect(LengthOrNumber), - @"mask-border-repeat": BorderImageRepeat, - @"mask-border": MaskBorder, - @"-webkit-mask-composite": SmallList(WebKitMaskComposite, 1), - @"mask-source-type": struct { SmallList(WebKitMaskSourceType, 1), VendorPrefix }, - @"mask-box-image": struct { BorderImage, VendorPrefix }, - @"mask-box-image-source": struct { Image, VendorPrefix }, - @"mask-box-image-slice": struct { BorderImageSlice, VendorPrefix }, - @"mask-box-image-width": struct { Rect(BorderImageSideWidth), VendorPrefix }, - @"mask-box-image-outset": struct { Rect(LengthOrNumber), VendorPrefix }, - @"mask-box-image-repeat": struct { BorderImageRepeat, VendorPrefix }, - @"color-scheme": ColorScheme, - all: CSSWideKeyword, - unparsed: UnparsedProperty, - custom: CustomProperty, - - pub const toCss = properties_impl.property_mixin.toCss; - - // Sanity check to make sure all types have the following functions: - // - deepClone() - // - eql() - // - parse() - // - toCss() - // - // We do this string concatenation thing so we get all the errors at once, - // instead of relying on Zig semantic analysis which usualy stops at the first error. - comptime { - const compile_error: []const u8 = compile_error: { - var compile_error: []const u8 = ""; - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.HorizontalPosition, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.HorizontalPosition, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.HorizontalPosition, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.HorizontalPosition, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.HorizontalPosition, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.HorizontalPosition, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.HorizontalPosition, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.HorizontalPosition, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.VerticalPosition, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.VerticalPosition, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.VerticalPosition, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.VerticalPosition, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.VerticalPosition, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.VerticalPosition, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(css_values.position.VerticalPosition, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(css_values.position.VerticalPosition, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundPosition, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundPosition, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundPosition, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundPosition, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundPosition, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundPosition, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundPosition, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundPosition, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundSize, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundSize, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundSize, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundSize, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundSize, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundSize, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundSize, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundSize, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundRepeat, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundRepeat, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundRepeat, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundRepeat, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundRepeat, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundRepeat, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundRepeat, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundRepeat, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundAttachment, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundAttachment, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundAttachment, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundAttachment, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundAttachment, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundAttachment, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundAttachment, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundAttachment, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundClip, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundClip, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundClip, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundClip, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundClip, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundClip, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundClip, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundClip, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundOrigin, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundOrigin, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundOrigin, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundOrigin, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundOrigin, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundOrigin, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(background.BackgroundOrigin, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(background.BackgroundOrigin, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(background.Background, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(background.Background, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(background.Background, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(background.Background, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(background.Background, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(background.Background, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(background.Background, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(background.Background, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(box_shadow.BoxShadow, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(box_shadow.BoxShadow, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(box_shadow.BoxShadow, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(box_shadow.BoxShadow, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(box_shadow.BoxShadow, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(box_shadow.BoxShadow, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(box_shadow.BoxShadow, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(box_shadow.BoxShadow, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(css.css_values.alpha.AlphaValue, "deepClone")) { - compile_error = compile_error ++ @typeName(css.css_values.alpha.AlphaValue) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(css.css_values.alpha.AlphaValue, "parse")) { - compile_error = compile_error ++ @typeName(css.css_values.alpha.AlphaValue) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(css.css_values.alpha.AlphaValue, "toCss")) { - compile_error = compile_error ++ @typeName(css.css_values.alpha.AlphaValue) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(css.css_values.alpha.AlphaValue, "eql")) { - compile_error = compile_error ++ @typeName(css.css_values.alpha.AlphaValue) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(display.Display, "deepClone")) { - compile_error = compile_error ++ @typeName(display.Display) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(display.Display, "parse")) { - compile_error = compile_error ++ @typeName(display.Display) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(display.Display, "toCss")) { - compile_error = compile_error ++ @typeName(display.Display) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(display.Display, "eql")) { - compile_error = compile_error ++ @typeName(display.Display) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(display.Visibility, "deepClone")) { - compile_error = compile_error ++ @typeName(display.Visibility) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(display.Visibility, "parse")) { - compile_error = compile_error ++ @typeName(display.Visibility) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(display.Visibility, "toCss")) { - compile_error = compile_error ++ @typeName(display.Visibility) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(display.Visibility, "eql")) { - compile_error = compile_error ++ @typeName(display.Visibility) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "deepClone")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "parse")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "toCss")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "eql")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "deepClone")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "parse")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "toCss")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "eql")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.Size, "deepClone")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.Size, "parse")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.Size, "toCss")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.Size, "eql")) { - compile_error = compile_error ++ @typeName(size.Size) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "deepClone")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "parse")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "toCss")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "eql")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "deepClone")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "parse")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "toCss")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.MaxSize, "eql")) { - compile_error = compile_error ++ @typeName(size.MaxSize) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.BoxSizing, "deepClone")) { - compile_error = compile_error ++ @typeName(size.BoxSizing) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.BoxSizing, "parse")) { - compile_error = compile_error ++ @typeName(size.BoxSizing) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.BoxSizing, "toCss")) { - compile_error = compile_error ++ @typeName(size.BoxSizing) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.BoxSizing, "eql")) { - compile_error = compile_error ++ @typeName(size.BoxSizing) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(size.AspectRatio, "deepClone")) { - compile_error = compile_error ++ @typeName(size.AspectRatio) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(size.AspectRatio, "parse")) { - compile_error = compile_error ++ @typeName(size.AspectRatio) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(size.AspectRatio, "toCss")) { - compile_error = compile_error ++ @typeName(size.AspectRatio) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(size.AspectRatio, "eql")) { - compile_error = compile_error ++ @typeName(size.AspectRatio) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(overflow.Overflow, "deepClone")) { - compile_error = compile_error ++ @typeName(overflow.Overflow) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(overflow.Overflow, "parse")) { - compile_error = compile_error ++ @typeName(overflow.Overflow) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(overflow.Overflow, "toCss")) { - compile_error = compile_error ++ @typeName(overflow.Overflow) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(overflow.Overflow, "eql")) { - compile_error = compile_error ++ @typeName(overflow.Overflow) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "deepClone")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "parse")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "toCss")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "eql")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "deepClone")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "parse")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "toCss")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(overflow.OverflowKeyword, "eql")) { - compile_error = compile_error ++ @typeName(overflow.OverflowKeyword) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(overflow.TextOverflow, "deepClone")) { - compile_error = compile_error ++ @typeName(overflow.TextOverflow) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(overflow.TextOverflow, "parse")) { - compile_error = compile_error ++ @typeName(overflow.TextOverflow) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(overflow.TextOverflow, "toCss")) { - compile_error = compile_error ++ @typeName(overflow.TextOverflow) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(overflow.TextOverflow, "eql")) { - compile_error = compile_error ++ @typeName(overflow.TextOverflow) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(position.Position, "deepClone")) { - compile_error = compile_error ++ @typeName(position.Position) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(position.Position, "parse")) { - compile_error = compile_error ++ @typeName(position.Position) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(position.Position, "toCss")) { - compile_error = compile_error ++ @typeName(position.Position) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(position.Position, "eql")) { - compile_error = compile_error ++ @typeName(position.Position) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetBlock, "deepClone")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetBlock) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetBlock, "parse")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetBlock) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetBlock, "toCss")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetBlock) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetBlock, "eql")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetBlock) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetInline, "deepClone")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetInline) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetInline, "parse")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetInline) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetInline, "toCss")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetInline) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(margin_padding.InsetInline, "eql")) { - compile_error = compile_error ++ @typeName(margin_padding.InsetInline) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(margin_padding.Inset, "deepClone")) { - compile_error = compile_error ++ @typeName(margin_padding.Inset) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(margin_padding.Inset, "parse")) { - compile_error = compile_error ++ @typeName(margin_padding.Inset) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(margin_padding.Inset, "toCss")) { - compile_error = compile_error ++ @typeName(margin_padding.Inset) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(margin_padding.Inset, "eql")) { - compile_error = compile_error ++ @typeName(margin_padding.Inset) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(css.css_values.size.Size2D(Length), "deepClone")) { - compile_error = compile_error ++ @typeName(css.css_values.size.Size2D(Length)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(css.css_values.size.Size2D(Length), "parse")) { - compile_error = compile_error ++ @typeName(css.css_values.size.Size2D(Length)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(css.css_values.size.Size2D(Length), "toCss")) { - compile_error = compile_error ++ @typeName(css.css_values.size.Size2D(Length)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(css.css_values.size.Size2D(Length), "eql")) { - compile_error = compile_error ++ @typeName(css.css_values.size.Size2D(Length)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "parse")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(border.LineStyle, "eql")) { - compile_error = compile_error ++ @typeName(border.LineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "deepClone")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "parse")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "toCss")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Size2D(LengthPercentage), "eql")) { - compile_error = compile_error ++ @typeName(Size2D(LengthPercentage)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderRadius, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderRadius) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderRadius, "parse")) { - compile_error = compile_error ++ @typeName(BorderRadius) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderRadius, "toCss")) { - compile_error = compile_error ++ @typeName(BorderRadius) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderRadius, "eql")) { - compile_error = compile_error ++ @typeName(BorderRadius) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Image, "deepClone")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Image, "parse")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Image, "toCss")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Image, "eql")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "deepClone")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "parse")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "toCss")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "eql")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "parse")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "eql")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "deepClone")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "parse")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "toCss")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "eql")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "parse")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "eql")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImage, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImage, "parse")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImage, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImage, "eql")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderColor, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderColor, "parse")) { - compile_error = compile_error ++ @typeName(BorderColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderColor, "toCss")) { - compile_error = compile_error ++ @typeName(BorderColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderColor, "eql")) { - compile_error = compile_error ++ @typeName(BorderColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderStyle, "parse")) { - compile_error = compile_error ++ @typeName(BorderStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderStyle, "toCss")) { - compile_error = compile_error ++ @typeName(BorderStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderStyle, "eql")) { - compile_error = compile_error ++ @typeName(BorderStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderBlockColor, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderBlockColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderBlockColor, "parse")) { - compile_error = compile_error ++ @typeName(BorderBlockColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderBlockColor, "toCss")) { - compile_error = compile_error ++ @typeName(BorderBlockColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderBlockColor, "eql")) { - compile_error = compile_error ++ @typeName(BorderBlockColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderBlockStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderBlockStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderBlockStyle, "parse")) { - compile_error = compile_error ++ @typeName(BorderBlockStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderBlockStyle, "toCss")) { - compile_error = compile_error ++ @typeName(BorderBlockStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderBlockStyle, "eql")) { - compile_error = compile_error ++ @typeName(BorderBlockStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderBlockWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderBlockWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderBlockWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderBlockWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderBlockWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderBlockWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderBlockWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderBlockWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderInlineColor, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderInlineColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderInlineColor, "parse")) { - compile_error = compile_error ++ @typeName(BorderInlineColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderInlineColor, "toCss")) { - compile_error = compile_error ++ @typeName(BorderInlineColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderInlineColor, "eql")) { - compile_error = compile_error ++ @typeName(BorderInlineColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderInlineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderInlineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderInlineStyle, "parse")) { - compile_error = compile_error ++ @typeName(BorderInlineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderInlineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(BorderInlineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderInlineStyle, "eql")) { - compile_error = compile_error ++ @typeName(BorderInlineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderInlineWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderInlineWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderInlineWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderInlineWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderInlineWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderInlineWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderInlineWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderInlineWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Border, "deepClone")) { - compile_error = compile_error ++ @typeName(Border) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Border, "parse")) { - compile_error = compile_error ++ @typeName(Border) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Border, "toCss")) { - compile_error = compile_error ++ @typeName(Border) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Border, "eql")) { - compile_error = compile_error ++ @typeName(Border) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderTop, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderTop) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderTop, "parse")) { - compile_error = compile_error ++ @typeName(BorderTop) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderTop, "toCss")) { - compile_error = compile_error ++ @typeName(BorderTop) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderTop, "eql")) { - compile_error = compile_error ++ @typeName(BorderTop) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderBottom, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderBottom) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderBottom, "parse")) { - compile_error = compile_error ++ @typeName(BorderBottom) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderBottom, "toCss")) { - compile_error = compile_error ++ @typeName(BorderBottom) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderBottom, "eql")) { - compile_error = compile_error ++ @typeName(BorderBottom) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderLeft, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderLeft) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderLeft, "parse")) { - compile_error = compile_error ++ @typeName(BorderLeft) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderLeft, "toCss")) { - compile_error = compile_error ++ @typeName(BorderLeft) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderLeft, "eql")) { - compile_error = compile_error ++ @typeName(BorderLeft) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderRight, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderRight) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderRight, "parse")) { - compile_error = compile_error ++ @typeName(BorderRight) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderRight, "toCss")) { - compile_error = compile_error ++ @typeName(BorderRight) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderRight, "eql")) { - compile_error = compile_error ++ @typeName(BorderRight) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderBlock, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderBlock) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderBlock, "parse")) { - compile_error = compile_error ++ @typeName(BorderBlock) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderBlock, "toCss")) { - compile_error = compile_error ++ @typeName(BorderBlock) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderBlock, "eql")) { - compile_error = compile_error ++ @typeName(BorderBlock) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderBlockStart, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderBlockStart) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderBlockStart, "parse")) { - compile_error = compile_error ++ @typeName(BorderBlockStart) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderBlockStart, "toCss")) { - compile_error = compile_error ++ @typeName(BorderBlockStart) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderBlockStart, "eql")) { - compile_error = compile_error ++ @typeName(BorderBlockStart) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderBlockEnd, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderBlockEnd) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderBlockEnd, "parse")) { - compile_error = compile_error ++ @typeName(BorderBlockEnd) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderBlockEnd, "toCss")) { - compile_error = compile_error ++ @typeName(BorderBlockEnd) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderBlockEnd, "eql")) { - compile_error = compile_error ++ @typeName(BorderBlockEnd) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderInline, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderInline) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderInline, "parse")) { - compile_error = compile_error ++ @typeName(BorderInline) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderInline, "toCss")) { - compile_error = compile_error ++ @typeName(BorderInline) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderInline, "eql")) { - compile_error = compile_error ++ @typeName(BorderInline) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderInlineStart, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderInlineStart) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderInlineStart, "parse")) { - compile_error = compile_error ++ @typeName(BorderInlineStart) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderInlineStart, "toCss")) { - compile_error = compile_error ++ @typeName(BorderInlineStart) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderInlineStart, "eql")) { - compile_error = compile_error ++ @typeName(BorderInlineStart) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderInlineEnd, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderInlineEnd) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderInlineEnd, "parse")) { - compile_error = compile_error ++ @typeName(BorderInlineEnd) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderInlineEnd, "toCss")) { - compile_error = compile_error ++ @typeName(BorderInlineEnd) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderInlineEnd, "eql")) { - compile_error = compile_error ++ @typeName(BorderInlineEnd) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Outline, "deepClone")) { - compile_error = compile_error ++ @typeName(Outline) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Outline, "parse")) { - compile_error = compile_error ++ @typeName(Outline) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Outline, "toCss")) { - compile_error = compile_error ++ @typeName(Outline) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Outline, "eql")) { - compile_error = compile_error ++ @typeName(Outline) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(OutlineStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(OutlineStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(OutlineStyle, "parse")) { - compile_error = compile_error ++ @typeName(OutlineStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(OutlineStyle, "toCss")) { - compile_error = compile_error ++ @typeName(OutlineStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(OutlineStyle, "eql")) { - compile_error = compile_error ++ @typeName(OutlineStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "parse")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "toCss")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderSideWidth, "eql")) { - compile_error = compile_error ++ @typeName(BorderSideWidth) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FlexDirection, "deepClone")) { - compile_error = compile_error ++ @typeName(FlexDirection) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FlexDirection, "parse")) { - compile_error = compile_error ++ @typeName(FlexDirection) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FlexDirection, "toCss")) { - compile_error = compile_error ++ @typeName(FlexDirection) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FlexDirection, "eql")) { - compile_error = compile_error ++ @typeName(FlexDirection) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FlexWrap, "deepClone")) { - compile_error = compile_error ++ @typeName(FlexWrap) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FlexWrap, "parse")) { - compile_error = compile_error ++ @typeName(FlexWrap) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FlexWrap, "toCss")) { - compile_error = compile_error ++ @typeName(FlexWrap) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FlexWrap, "eql")) { - compile_error = compile_error ++ @typeName(FlexWrap) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FlexFlow, "deepClone")) { - compile_error = compile_error ++ @typeName(FlexFlow) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FlexFlow, "parse")) { - compile_error = compile_error ++ @typeName(FlexFlow) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FlexFlow, "toCss")) { - compile_error = compile_error ++ @typeName(FlexFlow) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FlexFlow, "eql")) { - compile_error = compile_error ++ @typeName(FlexFlow) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Flex, "deepClone")) { - compile_error = compile_error ++ @typeName(Flex) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Flex, "parse")) { - compile_error = compile_error ++ @typeName(Flex) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Flex, "toCss")) { - compile_error = compile_error ++ @typeName(Flex) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Flex, "eql")) { - compile_error = compile_error ++ @typeName(Flex) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(AlignContent, "deepClone")) { - compile_error = compile_error ++ @typeName(AlignContent) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(AlignContent, "parse")) { - compile_error = compile_error ++ @typeName(AlignContent) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(AlignContent, "toCss")) { - compile_error = compile_error ++ @typeName(AlignContent) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(AlignContent, "eql")) { - compile_error = compile_error ++ @typeName(AlignContent) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(JustifyContent, "deepClone")) { - compile_error = compile_error ++ @typeName(JustifyContent) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(JustifyContent, "parse")) { - compile_error = compile_error ++ @typeName(JustifyContent) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(JustifyContent, "toCss")) { - compile_error = compile_error ++ @typeName(JustifyContent) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(JustifyContent, "eql")) { - compile_error = compile_error ++ @typeName(JustifyContent) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(PlaceContent, "deepClone")) { - compile_error = compile_error ++ @typeName(PlaceContent) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(PlaceContent, "parse")) { - compile_error = compile_error ++ @typeName(PlaceContent) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(PlaceContent, "toCss")) { - compile_error = compile_error ++ @typeName(PlaceContent) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(PlaceContent, "eql")) { - compile_error = compile_error ++ @typeName(PlaceContent) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(AlignSelf, "deepClone")) { - compile_error = compile_error ++ @typeName(AlignSelf) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(AlignSelf, "parse")) { - compile_error = compile_error ++ @typeName(AlignSelf) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(AlignSelf, "toCss")) { - compile_error = compile_error ++ @typeName(AlignSelf) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(AlignSelf, "eql")) { - compile_error = compile_error ++ @typeName(AlignSelf) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(JustifySelf, "deepClone")) { - compile_error = compile_error ++ @typeName(JustifySelf) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(JustifySelf, "parse")) { - compile_error = compile_error ++ @typeName(JustifySelf) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(JustifySelf, "toCss")) { - compile_error = compile_error ++ @typeName(JustifySelf) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(JustifySelf, "eql")) { - compile_error = compile_error ++ @typeName(JustifySelf) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(PlaceSelf, "deepClone")) { - compile_error = compile_error ++ @typeName(PlaceSelf) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(PlaceSelf, "parse")) { - compile_error = compile_error ++ @typeName(PlaceSelf) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(PlaceSelf, "toCss")) { - compile_error = compile_error ++ @typeName(PlaceSelf) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(PlaceSelf, "eql")) { - compile_error = compile_error ++ @typeName(PlaceSelf) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(AlignItems, "deepClone")) { - compile_error = compile_error ++ @typeName(AlignItems) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(AlignItems, "parse")) { - compile_error = compile_error ++ @typeName(AlignItems) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(AlignItems, "toCss")) { - compile_error = compile_error ++ @typeName(AlignItems) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(AlignItems, "eql")) { - compile_error = compile_error ++ @typeName(AlignItems) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(JustifyItems, "deepClone")) { - compile_error = compile_error ++ @typeName(JustifyItems) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(JustifyItems, "parse")) { - compile_error = compile_error ++ @typeName(JustifyItems) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(JustifyItems, "toCss")) { - compile_error = compile_error ++ @typeName(JustifyItems) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(JustifyItems, "eql")) { - compile_error = compile_error ++ @typeName(JustifyItems) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(PlaceItems, "deepClone")) { - compile_error = compile_error ++ @typeName(PlaceItems) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(PlaceItems, "parse")) { - compile_error = compile_error ++ @typeName(PlaceItems) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(PlaceItems, "toCss")) { - compile_error = compile_error ++ @typeName(PlaceItems) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(PlaceItems, "eql")) { - compile_error = compile_error ++ @typeName(PlaceItems) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(GapValue, "deepClone")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(GapValue, "parse")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(GapValue, "toCss")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(GapValue, "eql")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(GapValue, "deepClone")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(GapValue, "parse")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(GapValue, "toCss")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(GapValue, "eql")) { - compile_error = compile_error ++ @typeName(GapValue) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Gap, "deepClone")) { - compile_error = compile_error ++ @typeName(Gap) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Gap, "parse")) { - compile_error = compile_error ++ @typeName(Gap) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Gap, "toCss")) { - compile_error = compile_error ++ @typeName(Gap) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Gap, "eql")) { - compile_error = compile_error ++ @typeName(Gap) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BoxOrient, "deepClone")) { - compile_error = compile_error ++ @typeName(BoxOrient) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BoxOrient, "parse")) { - compile_error = compile_error ++ @typeName(BoxOrient) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BoxOrient, "toCss")) { - compile_error = compile_error ++ @typeName(BoxOrient) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BoxOrient, "eql")) { - compile_error = compile_error ++ @typeName(BoxOrient) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BoxDirection, "deepClone")) { - compile_error = compile_error ++ @typeName(BoxDirection) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BoxDirection, "parse")) { - compile_error = compile_error ++ @typeName(BoxDirection) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BoxDirection, "toCss")) { - compile_error = compile_error ++ @typeName(BoxDirection) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BoxDirection, "eql")) { - compile_error = compile_error ++ @typeName(BoxDirection) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BoxAlign, "deepClone")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BoxAlign, "parse")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BoxAlign, "toCss")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BoxAlign, "eql")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BoxPack, "deepClone")) { - compile_error = compile_error ++ @typeName(BoxPack) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BoxPack, "parse")) { - compile_error = compile_error ++ @typeName(BoxPack) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BoxPack, "toCss")) { - compile_error = compile_error ++ @typeName(BoxPack) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BoxPack, "eql")) { - compile_error = compile_error ++ @typeName(BoxPack) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BoxLines, "deepClone")) { - compile_error = compile_error ++ @typeName(BoxLines) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BoxLines, "parse")) { - compile_error = compile_error ++ @typeName(BoxLines) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BoxLines, "toCss")) { - compile_error = compile_error ++ @typeName(BoxLines) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BoxLines, "eql")) { - compile_error = compile_error ++ @typeName(BoxLines) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FlexPack, "deepClone")) { - compile_error = compile_error ++ @typeName(FlexPack) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FlexPack, "parse")) { - compile_error = compile_error ++ @typeName(FlexPack) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FlexPack, "toCss")) { - compile_error = compile_error ++ @typeName(FlexPack) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FlexPack, "eql")) { - compile_error = compile_error ++ @typeName(FlexPack) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BoxAlign, "deepClone")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BoxAlign, "parse")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BoxAlign, "toCss")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BoxAlign, "eql")) { - compile_error = compile_error ++ @typeName(BoxAlign) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FlexItemAlign, "deepClone")) { - compile_error = compile_error ++ @typeName(FlexItemAlign) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FlexItemAlign, "parse")) { - compile_error = compile_error ++ @typeName(FlexItemAlign) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FlexItemAlign, "toCss")) { - compile_error = compile_error ++ @typeName(FlexItemAlign) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FlexItemAlign, "eql")) { - compile_error = compile_error ++ @typeName(FlexItemAlign) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FlexLinePack, "deepClone")) { - compile_error = compile_error ++ @typeName(FlexLinePack) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FlexLinePack, "parse")) { - compile_error = compile_error ++ @typeName(FlexLinePack) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FlexLinePack, "toCss")) { - compile_error = compile_error ++ @typeName(FlexLinePack) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FlexLinePack, "eql")) { - compile_error = compile_error ++ @typeName(FlexLinePack) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(MarginBlock, "deepClone")) { - compile_error = compile_error ++ @typeName(MarginBlock) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(MarginBlock, "parse")) { - compile_error = compile_error ++ @typeName(MarginBlock) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(MarginBlock, "toCss")) { - compile_error = compile_error ++ @typeName(MarginBlock) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(MarginBlock, "eql")) { - compile_error = compile_error ++ @typeName(MarginBlock) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(MarginInline, "deepClone")) { - compile_error = compile_error ++ @typeName(MarginInline) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(MarginInline, "parse")) { - compile_error = compile_error ++ @typeName(MarginInline) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(MarginInline, "toCss")) { - compile_error = compile_error ++ @typeName(MarginInline) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(MarginInline, "eql")) { - compile_error = compile_error ++ @typeName(MarginInline) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Margin, "deepClone")) { - compile_error = compile_error ++ @typeName(Margin) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Margin, "parse")) { - compile_error = compile_error ++ @typeName(Margin) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Margin, "toCss")) { - compile_error = compile_error ++ @typeName(Margin) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Margin, "eql")) { - compile_error = compile_error ++ @typeName(Margin) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(PaddingBlock, "deepClone")) { - compile_error = compile_error ++ @typeName(PaddingBlock) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(PaddingBlock, "parse")) { - compile_error = compile_error ++ @typeName(PaddingBlock) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(PaddingBlock, "toCss")) { - compile_error = compile_error ++ @typeName(PaddingBlock) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(PaddingBlock, "eql")) { - compile_error = compile_error ++ @typeName(PaddingBlock) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(PaddingInline, "deepClone")) { - compile_error = compile_error ++ @typeName(PaddingInline) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(PaddingInline, "parse")) { - compile_error = compile_error ++ @typeName(PaddingInline) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(PaddingInline, "toCss")) { - compile_error = compile_error ++ @typeName(PaddingInline) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(PaddingInline, "eql")) { - compile_error = compile_error ++ @typeName(PaddingInline) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Padding, "deepClone")) { - compile_error = compile_error ++ @typeName(Padding) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Padding, "parse")) { - compile_error = compile_error ++ @typeName(Padding) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Padding, "toCss")) { - compile_error = compile_error ++ @typeName(Padding) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Padding, "eql")) { - compile_error = compile_error ++ @typeName(Padding) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(ScrollMarginBlock, "deepClone")) { - compile_error = compile_error ++ @typeName(ScrollMarginBlock) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(ScrollMarginBlock, "parse")) { - compile_error = compile_error ++ @typeName(ScrollMarginBlock) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(ScrollMarginBlock, "toCss")) { - compile_error = compile_error ++ @typeName(ScrollMarginBlock) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(ScrollMarginBlock, "eql")) { - compile_error = compile_error ++ @typeName(ScrollMarginBlock) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(ScrollMarginInline, "deepClone")) { - compile_error = compile_error ++ @typeName(ScrollMarginInline) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(ScrollMarginInline, "parse")) { - compile_error = compile_error ++ @typeName(ScrollMarginInline) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(ScrollMarginInline, "toCss")) { - compile_error = compile_error ++ @typeName(ScrollMarginInline) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(ScrollMarginInline, "eql")) { - compile_error = compile_error ++ @typeName(ScrollMarginInline) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(ScrollMargin, "deepClone")) { - compile_error = compile_error ++ @typeName(ScrollMargin) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(ScrollMargin, "parse")) { - compile_error = compile_error ++ @typeName(ScrollMargin) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(ScrollMargin, "toCss")) { - compile_error = compile_error ++ @typeName(ScrollMargin) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(ScrollMargin, "eql")) { - compile_error = compile_error ++ @typeName(ScrollMargin) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "deepClone")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "parse")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "toCss")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LengthPercentageOrAuto, "eql")) { - compile_error = compile_error ++ @typeName(LengthPercentageOrAuto) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(ScrollPaddingBlock, "deepClone")) { - compile_error = compile_error ++ @typeName(ScrollPaddingBlock) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(ScrollPaddingBlock, "parse")) { - compile_error = compile_error ++ @typeName(ScrollPaddingBlock) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(ScrollPaddingBlock, "toCss")) { - compile_error = compile_error ++ @typeName(ScrollPaddingBlock) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(ScrollPaddingBlock, "eql")) { - compile_error = compile_error ++ @typeName(ScrollPaddingBlock) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(ScrollPaddingInline, "deepClone")) { - compile_error = compile_error ++ @typeName(ScrollPaddingInline) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(ScrollPaddingInline, "parse")) { - compile_error = compile_error ++ @typeName(ScrollPaddingInline) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(ScrollPaddingInline, "toCss")) { - compile_error = compile_error ++ @typeName(ScrollPaddingInline) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(ScrollPaddingInline, "eql")) { - compile_error = compile_error ++ @typeName(ScrollPaddingInline) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(ScrollPadding, "deepClone")) { - compile_error = compile_error ++ @typeName(ScrollPadding) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(ScrollPadding, "parse")) { - compile_error = compile_error ++ @typeName(ScrollPadding) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(ScrollPadding, "toCss")) { - compile_error = compile_error ++ @typeName(ScrollPadding) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(ScrollPadding, "eql")) { - compile_error = compile_error ++ @typeName(ScrollPadding) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FontWeight, "deepClone")) { - compile_error = compile_error ++ @typeName(FontWeight) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FontWeight, "parse")) { - compile_error = compile_error ++ @typeName(FontWeight) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FontWeight, "toCss")) { - compile_error = compile_error ++ @typeName(FontWeight) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FontWeight, "eql")) { - compile_error = compile_error ++ @typeName(FontWeight) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FontSize, "deepClone")) { - compile_error = compile_error ++ @typeName(FontSize) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FontSize, "parse")) { - compile_error = compile_error ++ @typeName(FontSize) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FontSize, "toCss")) { - compile_error = compile_error ++ @typeName(FontSize) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FontSize, "eql")) { - compile_error = compile_error ++ @typeName(FontSize) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FontStretch, "deepClone")) { - compile_error = compile_error ++ @typeName(FontStretch) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FontStretch, "parse")) { - compile_error = compile_error ++ @typeName(FontStretch) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FontStretch, "toCss")) { - compile_error = compile_error ++ @typeName(FontStretch) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FontStretch, "eql")) { - compile_error = compile_error ++ @typeName(FontStretch) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BabyList(FontFamily), "deepClone")) { - compile_error = compile_error ++ @typeName(BabyList(FontFamily)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BabyList(FontFamily), "parse")) { - compile_error = compile_error ++ @typeName(BabyList(FontFamily)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BabyList(FontFamily), "toCss")) { - compile_error = compile_error ++ @typeName(BabyList(FontFamily)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BabyList(FontFamily), "eql")) { - compile_error = compile_error ++ @typeName(BabyList(FontFamily)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FontStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(FontStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FontStyle, "parse")) { - compile_error = compile_error ++ @typeName(FontStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FontStyle, "toCss")) { - compile_error = compile_error ++ @typeName(FontStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FontStyle, "eql")) { - compile_error = compile_error ++ @typeName(FontStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(FontVariantCaps, "deepClone")) { - compile_error = compile_error ++ @typeName(FontVariantCaps) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(FontVariantCaps, "parse")) { - compile_error = compile_error ++ @typeName(FontVariantCaps) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(FontVariantCaps, "toCss")) { - compile_error = compile_error ++ @typeName(FontVariantCaps) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(FontVariantCaps, "eql")) { - compile_error = compile_error ++ @typeName(FontVariantCaps) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(LineHeight, "deepClone")) { - compile_error = compile_error ++ @typeName(LineHeight) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(LineHeight, "parse")) { - compile_error = compile_error ++ @typeName(LineHeight) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(LineHeight, "toCss")) { - compile_error = compile_error ++ @typeName(LineHeight) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(LineHeight, "eql")) { - compile_error = compile_error ++ @typeName(LineHeight) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Font, "deepClone")) { - compile_error = compile_error ++ @typeName(Font) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Font, "parse")) { - compile_error = compile_error ++ @typeName(Font) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Font, "toCss")) { - compile_error = compile_error ++ @typeName(Font) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Font, "eql")) { - compile_error = compile_error ++ @typeName(Font) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(PropertyId, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(PropertyId, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(PropertyId, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(PropertyId, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(PropertyId, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(PropertyId, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(PropertyId, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(PropertyId, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(Time, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(Time, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(EasingFunction, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(EasingFunction, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(EasingFunction, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(EasingFunction, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(EasingFunction, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(EasingFunction, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(EasingFunction, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(EasingFunction, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(Transition, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(Transition, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(Transition, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(Transition, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(Transition, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(Transition, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(Transition, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(Transition, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(TransformList, "deepClone")) { - compile_error = compile_error ++ @typeName(TransformList) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(TransformList, "parse")) { - compile_error = compile_error ++ @typeName(TransformList) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(TransformList, "toCss")) { - compile_error = compile_error ++ @typeName(TransformList) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(TransformList, "eql")) { - compile_error = compile_error ++ @typeName(TransformList) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Position, "deepClone")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Position, "parse")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Position, "toCss")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Position, "eql")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(TransformStyle, "deepClone")) { - compile_error = compile_error ++ @typeName(TransformStyle) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(TransformStyle, "parse")) { - compile_error = compile_error ++ @typeName(TransformStyle) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(TransformStyle, "toCss")) { - compile_error = compile_error ++ @typeName(TransformStyle) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(TransformStyle, "eql")) { - compile_error = compile_error ++ @typeName(TransformStyle) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(TransformBox, "deepClone")) { - compile_error = compile_error ++ @typeName(TransformBox) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(TransformBox, "parse")) { - compile_error = compile_error ++ @typeName(TransformBox) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(TransformBox, "toCss")) { - compile_error = compile_error ++ @typeName(TransformBox) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(TransformBox, "eql")) { - compile_error = compile_error ++ @typeName(TransformBox) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BackfaceVisibility, "deepClone")) { - compile_error = compile_error ++ @typeName(BackfaceVisibility) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BackfaceVisibility, "parse")) { - compile_error = compile_error ++ @typeName(BackfaceVisibility) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BackfaceVisibility, "toCss")) { - compile_error = compile_error ++ @typeName(BackfaceVisibility) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BackfaceVisibility, "eql")) { - compile_error = compile_error ++ @typeName(BackfaceVisibility) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Perspective, "deepClone")) { - compile_error = compile_error ++ @typeName(Perspective) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Perspective, "parse")) { - compile_error = compile_error ++ @typeName(Perspective) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Perspective, "toCss")) { - compile_error = compile_error ++ @typeName(Perspective) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Perspective, "eql")) { - compile_error = compile_error ++ @typeName(Perspective) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Position, "deepClone")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Position, "parse")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Position, "toCss")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Position, "eql")) { - compile_error = compile_error ++ @typeName(Position) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Translate, "deepClone")) { - compile_error = compile_error ++ @typeName(Translate) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Translate, "parse")) { - compile_error = compile_error ++ @typeName(Translate) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Translate, "toCss")) { - compile_error = compile_error ++ @typeName(Translate) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Translate, "eql")) { - compile_error = compile_error ++ @typeName(Translate) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Rotate, "deepClone")) { - compile_error = compile_error ++ @typeName(Rotate) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Rotate, "parse")) { - compile_error = compile_error ++ @typeName(Rotate) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Rotate, "toCss")) { - compile_error = compile_error ++ @typeName(Rotate) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Rotate, "eql")) { - compile_error = compile_error ++ @typeName(Rotate) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Scale, "deepClone")) { - compile_error = compile_error ++ @typeName(Scale) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Scale, "parse")) { - compile_error = compile_error ++ @typeName(Scale) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Scale, "toCss")) { - compile_error = compile_error ++ @typeName(Scale) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Scale, "eql")) { - compile_error = compile_error ++ @typeName(Scale) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(CssColor, "deepClone")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(CssColor, "parse")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(CssColor, "toCss")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(CssColor, "eql")) { - compile_error = compile_error ++ @typeName(CssColor) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(TextShadow, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(TextShadow, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(TextShadow, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(TextShadow, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(TextShadow, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(TextShadow, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(TextShadow, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(TextShadow, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Direction, "deepClone")) { - compile_error = compile_error ++ @typeName(Direction) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Direction, "parse")) { - compile_error = compile_error ++ @typeName(Direction) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Direction, "toCss")) { - compile_error = compile_error ++ @typeName(Direction) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Direction, "eql")) { - compile_error = compile_error ++ @typeName(Direction) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Composes, "deepClone")) { - compile_error = compile_error ++ @typeName(Composes) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Composes, "parse")) { - compile_error = compile_error ++ @typeName(Composes) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Composes, "toCss")) { - compile_error = compile_error ++ @typeName(Composes) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Composes, "eql")) { - compile_error = compile_error ++ @typeName(Composes) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(Image, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(Image, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(MaskMode, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(MaskMode, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(MaskMode, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(MaskMode, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(MaskMode, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(MaskMode, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(MaskMode, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(MaskMode, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundRepeat, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundRepeat, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundRepeat, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundRepeat, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundRepeat, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundRepeat, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundRepeat, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundRepeat, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(HorizontalPosition, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(HorizontalPosition, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(HorizontalPosition, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(HorizontalPosition, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(HorizontalPosition, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(HorizontalPosition, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(HorizontalPosition, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(HorizontalPosition, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(VerticalPosition, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(VerticalPosition, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(VerticalPosition, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(VerticalPosition, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(VerticalPosition, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(VerticalPosition, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(VerticalPosition, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(VerticalPosition, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(Position, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(Position, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(Position, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(Position, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(Position, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(Position, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(Position, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(Position, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(MaskClip, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(MaskClip, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(MaskClip, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(MaskClip, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(MaskClip, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(MaskClip, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(MaskClip, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(MaskClip, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(GeometryBox, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(GeometryBox, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(GeometryBox, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(GeometryBox, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(GeometryBox, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(GeometryBox, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(GeometryBox, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(GeometryBox, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundSize, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundSize, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundSize, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundSize, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundSize, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundSize, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(BackgroundSize, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(BackgroundSize, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(MaskComposite, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(MaskComposite, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(MaskComposite, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(MaskComposite, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(MaskComposite, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(MaskComposite, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(MaskComposite, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(MaskComposite, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(MaskType, "deepClone")) { - compile_error = compile_error ++ @typeName(MaskType) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(MaskType, "parse")) { - compile_error = compile_error ++ @typeName(MaskType) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(MaskType, "toCss")) { - compile_error = compile_error ++ @typeName(MaskType) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(MaskType, "eql")) { - compile_error = compile_error ++ @typeName(MaskType) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(Mask, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(Mask, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(Mask, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(Mask, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(Mask, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(Mask, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(Mask, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(Mask, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Image, "deepClone")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Image, "parse")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Image, "toCss")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Image, "eql")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(MaskBorderMode, "deepClone")) { - compile_error = compile_error ++ @typeName(MaskBorderMode) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(MaskBorderMode, "parse")) { - compile_error = compile_error ++ @typeName(MaskBorderMode) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(MaskBorderMode, "toCss")) { - compile_error = compile_error ++ @typeName(MaskBorderMode) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(MaskBorderMode, "eql")) { - compile_error = compile_error ++ @typeName(MaskBorderMode) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "parse")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "eql")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "deepClone")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "parse")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "toCss")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "eql")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "deepClone")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "parse")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "toCss")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "eql")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "parse")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "eql")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(MaskBorder, "deepClone")) { - compile_error = compile_error ++ @typeName(MaskBorder) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(MaskBorder, "parse")) { - compile_error = compile_error ++ @typeName(MaskBorder) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(MaskBorder, "toCss")) { - compile_error = compile_error ++ @typeName(MaskBorder) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(MaskBorder, "eql")) { - compile_error = compile_error ++ @typeName(MaskBorder) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskComposite, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskComposite, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskComposite, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskComposite, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskComposite, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskComposite, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskComposite, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskComposite, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskSourceType, 1), "deepClone")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskSourceType, 1)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskSourceType, 1), "parse")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskSourceType, 1)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskSourceType, 1), "toCss")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskSourceType, 1)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(SmallList(WebKitMaskSourceType, 1), "eql")) { - compile_error = compile_error ++ @typeName(SmallList(WebKitMaskSourceType, 1)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImage, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImage, "parse")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImage, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImage, "eql")) { - compile_error = compile_error ++ @typeName(BorderImage) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Image, "deepClone")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Image, "parse")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Image, "toCss")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Image, "eql")) { - compile_error = compile_error ++ @typeName(Image) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "parse")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImageSlice, "eql")) { - compile_error = compile_error ++ @typeName(BorderImageSlice) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "deepClone")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "parse")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "toCss")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Rect(BorderImageSideWidth), "eql")) { - compile_error = compile_error ++ @typeName(Rect(BorderImageSideWidth)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "deepClone")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "parse")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "toCss")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(Rect(LengthOrNumber), "eql")) { - compile_error = compile_error ++ @typeName(Rect(LengthOrNumber)) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "deepClone")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "parse")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "toCss")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(BorderImageRepeat, "eql")) { - compile_error = compile_error ++ @typeName(BorderImageRepeat) ++ ": does not have a eql() function.\n"; - } - - if (!@hasDecl(ColorScheme, "deepClone")) { - compile_error = compile_error ++ @typeName(ColorScheme) ++ ": does not have a deepClone() function.\n"; - } - - if (!@hasDecl(ColorScheme, "parse")) { - compile_error = compile_error ++ @typeName(ColorScheme) ++ ": does not have a parse() function.\n"; - } - - if (!@hasDecl(ColorScheme, "toCss")) { - compile_error = compile_error ++ @typeName(ColorScheme) ++ ": does not have a toCss() function.\n"; - } - - if (!@hasDecl(ColorScheme, "eql")) { - compile_error = compile_error ++ @typeName(ColorScheme) ++ ": does not have a eql() function.\n"; - } - - const final_compile_error = compile_error; - break :compile_error final_compile_error; - }; - if (compile_error.len > 0) { - @compileError(compile_error); - } - } - - /// Parses a CSS property by name. - pub fn parse(property_id: PropertyId, input: *css.Parser, options: *const css.ParserOptions) Result(Property) { - const state = input.state(); - - switch (property_id) { - .@"background-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-color" = c } }; - } - } - }, - .@"background-image" => { - if (css.generic.parseWithOptions(SmallList(Image, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-image" = c } }; - } - } - }, - .@"background-position-x" => { - if (css.generic.parseWithOptions(SmallList(css_values.position.HorizontalPosition, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-position-x" = c } }; - } - } - }, - .@"background-position-y" => { - if (css.generic.parseWithOptions(SmallList(css_values.position.VerticalPosition, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-position-y" = c } }; - } - } - }, - .@"background-position" => { - if (css.generic.parseWithOptions(SmallList(background.BackgroundPosition, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-position" = c } }; - } - } - }, - .@"background-size" => { - if (css.generic.parseWithOptions(SmallList(background.BackgroundSize, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-size" = c } }; - } - } - }, - .@"background-repeat" => { - if (css.generic.parseWithOptions(SmallList(background.BackgroundRepeat, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-repeat" = c } }; - } - } - }, - .@"background-attachment" => { - if (css.generic.parseWithOptions(SmallList(background.BackgroundAttachment, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-attachment" = c } }; - } - } - }, - .@"background-clip" => |pre| { - if (css.generic.parseWithOptions(SmallList(background.BackgroundClip, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-clip" = .{ c, pre } } }; - } - } - }, - .@"background-origin" => { - if (css.generic.parseWithOptions(SmallList(background.BackgroundOrigin, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"background-origin" = c } }; - } - } - }, - .background => { - if (css.generic.parseWithOptions(SmallList(background.Background, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .background = c } }; - } - } - }, - .@"box-shadow" => |pre| { - if (css.generic.parseWithOptions(SmallList(box_shadow.BoxShadow, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-shadow" = .{ c, pre } } }; - } - } - }, - .opacity => { - if (css.generic.parseWithOptions(css.css_values.alpha.AlphaValue, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .opacity = c } }; - } - } - }, - .color => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .color = c } }; - } - } - }, - .display => { - if (css.generic.parseWithOptions(display.Display, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .display = c } }; - } - } - }, - .visibility => { - if (css.generic.parseWithOptions(display.Visibility, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .visibility = c } }; - } - } - }, - .width => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .width = c } }; - } - } - }, - .height => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .height = c } }; - } - } - }, - .@"min-width" => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"min-width" = c } }; - } - } - }, - .@"min-height" => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"min-height" = c } }; - } - } - }, - .@"max-width" => { - if (css.generic.parseWithOptions(size.MaxSize, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"max-width" = c } }; - } - } - }, - .@"max-height" => { - if (css.generic.parseWithOptions(size.MaxSize, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"max-height" = c } }; - } - } - }, - .@"block-size" => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"block-size" = c } }; - } - } - }, - .@"inline-size" => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"inline-size" = c } }; - } - } - }, - .@"min-block-size" => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"min-block-size" = c } }; - } - } - }, - .@"min-inline-size" => { - if (css.generic.parseWithOptions(size.Size, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"min-inline-size" = c } }; - } - } - }, - .@"max-block-size" => { - if (css.generic.parseWithOptions(size.MaxSize, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"max-block-size" = c } }; - } - } - }, - .@"max-inline-size" => { - if (css.generic.parseWithOptions(size.MaxSize, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"max-inline-size" = c } }; - } - } - }, - .@"box-sizing" => |pre| { - if (css.generic.parseWithOptions(size.BoxSizing, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-sizing" = .{ c, pre } } }; - } - } - }, - .@"aspect-ratio" => { - if (css.generic.parseWithOptions(size.AspectRatio, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"aspect-ratio" = c } }; - } - } - }, - .overflow => { - if (css.generic.parseWithOptions(overflow.Overflow, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .overflow = c } }; - } - } - }, - .@"overflow-x" => { - if (css.generic.parseWithOptions(overflow.OverflowKeyword, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"overflow-x" = c } }; - } - } - }, - .@"overflow-y" => { - if (css.generic.parseWithOptions(overflow.OverflowKeyword, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"overflow-y" = c } }; - } - } - }, - .@"text-overflow" => |pre| { - if (css.generic.parseWithOptions(overflow.TextOverflow, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"text-overflow" = .{ c, pre } } }; - } - } - }, - .position => { - if (css.generic.parseWithOptions(position.Position, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .position = c } }; - } - } - }, - .top => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .top = c } }; - } - } - }, - .bottom => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .bottom = c } }; - } - } - }, - .left => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .left = c } }; - } - } - }, - .right => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .right = c } }; - } - } - }, - .@"inset-block-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"inset-block-start" = c } }; - } - } - }, - .@"inset-block-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"inset-block-end" = c } }; - } - } - }, - .@"inset-inline-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"inset-inline-start" = c } }; - } - } - }, - .@"inset-inline-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"inset-inline-end" = c } }; - } - } - }, - .@"inset-block" => { - if (css.generic.parseWithOptions(margin_padding.InsetBlock, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"inset-block" = c } }; - } - } - }, - .@"inset-inline" => { - if (css.generic.parseWithOptions(margin_padding.InsetInline, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"inset-inline" = c } }; - } - } - }, - .inset => { - if (css.generic.parseWithOptions(margin_padding.Inset, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .inset = c } }; - } - } - }, - .@"border-spacing" => { - if (css.generic.parseWithOptions(css.css_values.size.Size2D(Length), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-spacing" = c } }; - } - } - }, - .@"border-top-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-top-color" = c } }; - } - } - }, - .@"border-bottom-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-bottom-color" = c } }; - } - } - }, - .@"border-left-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-left-color" = c } }; - } - } - }, - .@"border-right-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-right-color" = c } }; - } - } - }, - .@"border-block-start-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-start-color" = c } }; - } - } - }, - .@"border-block-end-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-end-color" = c } }; - } - } - }, - .@"border-inline-start-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-start-color" = c } }; - } - } - }, - .@"border-inline-end-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-end-color" = c } }; - } - } - }, - .@"border-top-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-top-style" = c } }; - } - } - }, - .@"border-bottom-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-bottom-style" = c } }; - } - } - }, - .@"border-left-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-left-style" = c } }; - } - } - }, - .@"border-right-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-right-style" = c } }; - } - } - }, - .@"border-block-start-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-start-style" = c } }; - } - } - }, - .@"border-block-end-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-end-style" = c } }; - } - } - }, - .@"border-inline-start-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-start-style" = c } }; - } - } - }, - .@"border-inline-end-style" => { - if (css.generic.parseWithOptions(border.LineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-end-style" = c } }; - } - } - }, - .@"border-top-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-top-width" = c } }; - } - } - }, - .@"border-bottom-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-bottom-width" = c } }; - } - } - }, - .@"border-left-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-left-width" = c } }; - } - } - }, - .@"border-right-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-right-width" = c } }; - } - } - }, - .@"border-block-start-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-start-width" = c } }; - } - } - }, - .@"border-block-end-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-end-width" = c } }; - } - } - }, - .@"border-inline-start-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-start-width" = c } }; - } - } - }, - .@"border-inline-end-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-end-width" = c } }; - } - } - }, - .@"border-top-left-radius" => |pre| { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-top-left-radius" = .{ c, pre } } }; - } - } - }, - .@"border-top-right-radius" => |pre| { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-top-right-radius" = .{ c, pre } } }; - } - } - }, - .@"border-bottom-left-radius" => |pre| { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-bottom-left-radius" = .{ c, pre } } }; - } - } - }, - .@"border-bottom-right-radius" => |pre| { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-bottom-right-radius" = .{ c, pre } } }; - } - } - }, - .@"border-start-start-radius" => { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-start-start-radius" = c } }; - } - } - }, - .@"border-start-end-radius" => { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-start-end-radius" = c } }; - } - } - }, - .@"border-end-start-radius" => { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-end-start-radius" = c } }; - } - } - }, - .@"border-end-end-radius" => { - if (css.generic.parseWithOptions(Size2D(LengthPercentage), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-end-end-radius" = c } }; - } - } - }, - .@"border-radius" => |pre| { - if (css.generic.parseWithOptions(BorderRadius, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-radius" = .{ c, pre } } }; - } - } - }, - .@"border-image-source" => { - if (css.generic.parseWithOptions(Image, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-image-source" = c } }; - } - } - }, - .@"border-image-outset" => { - if (css.generic.parseWithOptions(Rect(LengthOrNumber), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-image-outset" = c } }; - } - } - }, - .@"border-image-repeat" => { - if (css.generic.parseWithOptions(BorderImageRepeat, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-image-repeat" = c } }; - } - } - }, - .@"border-image-width" => { - if (css.generic.parseWithOptions(Rect(BorderImageSideWidth), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-image-width" = c } }; - } - } - }, - .@"border-image-slice" => { - if (css.generic.parseWithOptions(BorderImageSlice, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-image-slice" = c } }; - } - } - }, - .@"border-image" => |pre| { - if (css.generic.parseWithOptions(BorderImage, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-image" = .{ c, pre } } }; - } - } - }, - .@"border-color" => { - if (css.generic.parseWithOptions(BorderColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-color" = c } }; - } - } - }, - .@"border-style" => { - if (css.generic.parseWithOptions(BorderStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-style" = c } }; - } - } - }, - .@"border-width" => { - if (css.generic.parseWithOptions(BorderWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-width" = c } }; - } - } - }, - .@"border-block-color" => { - if (css.generic.parseWithOptions(BorderBlockColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-color" = c } }; - } - } - }, - .@"border-block-style" => { - if (css.generic.parseWithOptions(BorderBlockStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-style" = c } }; - } - } - }, - .@"border-block-width" => { - if (css.generic.parseWithOptions(BorderBlockWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-width" = c } }; - } - } - }, - .@"border-inline-color" => { - if (css.generic.parseWithOptions(BorderInlineColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-color" = c } }; - } - } - }, - .@"border-inline-style" => { - if (css.generic.parseWithOptions(BorderInlineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-style" = c } }; - } - } - }, - .@"border-inline-width" => { - if (css.generic.parseWithOptions(BorderInlineWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-width" = c } }; - } - } - }, - .border => { - if (css.generic.parseWithOptions(Border, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .border = c } }; - } - } - }, - .@"border-top" => { - if (css.generic.parseWithOptions(BorderTop, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-top" = c } }; - } - } - }, - .@"border-bottom" => { - if (css.generic.parseWithOptions(BorderBottom, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-bottom" = c } }; - } - } - }, - .@"border-left" => { - if (css.generic.parseWithOptions(BorderLeft, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-left" = c } }; - } - } - }, - .@"border-right" => { - if (css.generic.parseWithOptions(BorderRight, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-right" = c } }; - } - } - }, - .@"border-block" => { - if (css.generic.parseWithOptions(BorderBlock, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block" = c } }; - } - } - }, - .@"border-block-start" => { - if (css.generic.parseWithOptions(BorderBlockStart, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-start" = c } }; - } - } - }, - .@"border-block-end" => { - if (css.generic.parseWithOptions(BorderBlockEnd, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-block-end" = c } }; - } - } - }, - .@"border-inline" => { - if (css.generic.parseWithOptions(BorderInline, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline" = c } }; - } - } - }, - .@"border-inline-start" => { - if (css.generic.parseWithOptions(BorderInlineStart, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-start" = c } }; - } - } - }, - .@"border-inline-end" => { - if (css.generic.parseWithOptions(BorderInlineEnd, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"border-inline-end" = c } }; - } - } - }, - .outline => { - if (css.generic.parseWithOptions(Outline, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .outline = c } }; - } - } - }, - .@"outline-color" => { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"outline-color" = c } }; - } - } - }, - .@"outline-style" => { - if (css.generic.parseWithOptions(OutlineStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"outline-style" = c } }; - } - } - }, - .@"outline-width" => { - if (css.generic.parseWithOptions(BorderSideWidth, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"outline-width" = c } }; - } - } - }, - .@"flex-direction" => |pre| { - if (css.generic.parseWithOptions(FlexDirection, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-direction" = .{ c, pre } } }; - } - } - }, - .@"flex-wrap" => |pre| { - if (css.generic.parseWithOptions(FlexWrap, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-wrap" = .{ c, pre } } }; - } - } - }, - .@"flex-flow" => |pre| { - if (css.generic.parseWithOptions(FlexFlow, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-flow" = .{ c, pre } } }; - } - } - }, - .@"flex-grow" => |pre| { - if (css.generic.parseWithOptions(CSSNumber, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-grow" = .{ c, pre } } }; - } - } - }, - .@"flex-shrink" => |pre| { - if (css.generic.parseWithOptions(CSSNumber, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-shrink" = .{ c, pre } } }; - } - } - }, - .@"flex-basis" => |pre| { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-basis" = .{ c, pre } } }; - } - } - }, - .flex => |pre| { - if (css.generic.parseWithOptions(Flex, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .flex = .{ c, pre } } }; - } - } - }, - .order => |pre| { - if (css.generic.parseWithOptions(CSSInteger, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .order = .{ c, pre } } }; - } - } - }, - .@"align-content" => |pre| { - if (css.generic.parseWithOptions(AlignContent, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"align-content" = .{ c, pre } } }; - } - } - }, - .@"justify-content" => |pre| { - if (css.generic.parseWithOptions(JustifyContent, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"justify-content" = .{ c, pre } } }; - } - } - }, - .@"place-content" => { - if (css.generic.parseWithOptions(PlaceContent, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"place-content" = c } }; - } - } - }, - .@"align-self" => |pre| { - if (css.generic.parseWithOptions(AlignSelf, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"align-self" = .{ c, pre } } }; - } - } - }, - .@"justify-self" => { - if (css.generic.parseWithOptions(JustifySelf, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"justify-self" = c } }; - } - } - }, - .@"place-self" => { - if (css.generic.parseWithOptions(PlaceSelf, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"place-self" = c } }; - } - } - }, - .@"align-items" => |pre| { - if (css.generic.parseWithOptions(AlignItems, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"align-items" = .{ c, pre } } }; - } - } - }, - .@"justify-items" => { - if (css.generic.parseWithOptions(JustifyItems, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"justify-items" = c } }; - } - } - }, - .@"place-items" => { - if (css.generic.parseWithOptions(PlaceItems, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"place-items" = c } }; - } - } - }, - .@"row-gap" => { - if (css.generic.parseWithOptions(GapValue, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"row-gap" = c } }; - } - } - }, - .@"column-gap" => { - if (css.generic.parseWithOptions(GapValue, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"column-gap" = c } }; - } - } - }, - .gap => { - if (css.generic.parseWithOptions(Gap, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .gap = c } }; - } - } - }, - .@"box-orient" => |pre| { - if (css.generic.parseWithOptions(BoxOrient, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-orient" = .{ c, pre } } }; - } - } - }, - .@"box-direction" => |pre| { - if (css.generic.parseWithOptions(BoxDirection, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-direction" = .{ c, pre } } }; - } - } - }, - .@"box-ordinal-group" => |pre| { - if (css.generic.parseWithOptions(CSSInteger, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-ordinal-group" = .{ c, pre } } }; - } - } - }, - .@"box-align" => |pre| { - if (css.generic.parseWithOptions(BoxAlign, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-align" = .{ c, pre } } }; - } - } - }, - .@"box-flex" => |pre| { - if (css.generic.parseWithOptions(CSSNumber, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-flex" = .{ c, pre } } }; - } - } - }, - .@"box-flex-group" => |pre| { - if (css.generic.parseWithOptions(CSSInteger, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-flex-group" = .{ c, pre } } }; - } - } - }, - .@"box-pack" => |pre| { - if (css.generic.parseWithOptions(BoxPack, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-pack" = .{ c, pre } } }; - } - } - }, - .@"box-lines" => |pre| { - if (css.generic.parseWithOptions(BoxLines, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"box-lines" = .{ c, pre } } }; - } - } - }, - .@"flex-pack" => |pre| { - if (css.generic.parseWithOptions(FlexPack, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-pack" = .{ c, pre } } }; - } - } - }, - .@"flex-order" => |pre| { - if (css.generic.parseWithOptions(CSSInteger, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-order" = .{ c, pre } } }; - } - } - }, - .@"flex-align" => |pre| { - if (css.generic.parseWithOptions(BoxAlign, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-align" = .{ c, pre } } }; - } - } - }, - .@"flex-item-align" => |pre| { - if (css.generic.parseWithOptions(FlexItemAlign, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-item-align" = .{ c, pre } } }; - } - } - }, - .@"flex-line-pack" => |pre| { - if (css.generic.parseWithOptions(FlexLinePack, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-line-pack" = .{ c, pre } } }; - } - } - }, - .@"flex-positive" => |pre| { - if (css.generic.parseWithOptions(CSSNumber, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-positive" = .{ c, pre } } }; - } - } - }, - .@"flex-negative" => |pre| { - if (css.generic.parseWithOptions(CSSNumber, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-negative" = .{ c, pre } } }; - } - } - }, - .@"flex-preferred-size" => |pre| { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"flex-preferred-size" = .{ c, pre } } }; - } - } - }, - .@"margin-top" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-top" = c } }; - } - } - }, - .@"margin-bottom" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-bottom" = c } }; - } - } - }, - .@"margin-left" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-left" = c } }; - } - } - }, - .@"margin-right" => { - @setEvalBranchQuota(5000); - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-right" = c } }; - } - } - }, - .@"margin-block-start" => { - @setEvalBranchQuota(5000); - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-block-start" = c } }; - } - } - }, - .@"margin-block-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-block-end" = c } }; - } - } - }, - .@"margin-inline-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-inline-start" = c } }; - } - } - }, - .@"margin-inline-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-inline-end" = c } }; - } - } - }, - .@"margin-block" => { - if (css.generic.parseWithOptions(MarginBlock, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-block" = c } }; - } - } - }, - .@"margin-inline" => { - if (css.generic.parseWithOptions(MarginInline, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"margin-inline" = c } }; - } - } - }, - .margin => { - @setEvalBranchQuota(5000); - if (css.generic.parseWithOptions(Margin, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .margin = c } }; - } - } - }, - .@"padding-top" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-top" = c } }; - } - } - }, - .@"padding-bottom" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-bottom" = c } }; - } - } - }, - .@"padding-left" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-left" = c } }; - } - } - }, - .@"padding-right" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-right" = c } }; - } - } - }, - .@"padding-block-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-block-start" = c } }; - } - } - }, - .@"padding-block-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-block-end" = c } }; - } - } - }, - .@"padding-inline-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-inline-start" = c } }; - } - } - }, - .@"padding-inline-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-inline-end" = c } }; - } - } - }, - .@"padding-block" => { - if (css.generic.parseWithOptions(PaddingBlock, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-block" = c } }; - } - } - }, - .@"padding-inline" => { - if (css.generic.parseWithOptions(PaddingInline, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"padding-inline" = c } }; - } - } - }, - .padding => { - if (css.generic.parseWithOptions(Padding, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .padding = c } }; - } - } - }, - .@"scroll-margin-top" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-top" = c } }; - } - } - }, - .@"scroll-margin-bottom" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-bottom" = c } }; - } - } - }, - .@"scroll-margin-left" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-left" = c } }; - } - } - }, - .@"scroll-margin-right" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-right" = c } }; - } - } - }, - .@"scroll-margin-block-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-block-start" = c } }; - } - } - }, - .@"scroll-margin-block-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-block-end" = c } }; - } - } - }, - .@"scroll-margin-inline-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-inline-start" = c } }; - } - } - }, - .@"scroll-margin-inline-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-inline-end" = c } }; - } - } - }, - .@"scroll-margin-block" => { - if (css.generic.parseWithOptions(ScrollMarginBlock, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-block" = c } }; - } - } - }, - .@"scroll-margin-inline" => { - if (css.generic.parseWithOptions(ScrollMarginInline, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin-inline" = c } }; - } - } - }, - .@"scroll-margin" => { - if (css.generic.parseWithOptions(ScrollMargin, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-margin" = c } }; - } - } - }, - .@"scroll-padding-top" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-top" = c } }; - } - } - }, - .@"scroll-padding-bottom" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-bottom" = c } }; - } - } - }, - .@"scroll-padding-left" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-left" = c } }; - } - } - }, - .@"scroll-padding-right" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-right" = c } }; - } - } - }, - .@"scroll-padding-block-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-block-start" = c } }; - } - } - }, - .@"scroll-padding-block-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-block-end" = c } }; - } - } - }, - .@"scroll-padding-inline-start" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-inline-start" = c } }; - } - } - }, - .@"scroll-padding-inline-end" => { - if (css.generic.parseWithOptions(LengthPercentageOrAuto, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-inline-end" = c } }; - } - } - }, - .@"scroll-padding-block" => { - if (css.generic.parseWithOptions(ScrollPaddingBlock, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-block" = c } }; - } - } - }, - .@"scroll-padding-inline" => { - if (css.generic.parseWithOptions(ScrollPaddingInline, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding-inline" = c } }; - } - } - }, - .@"scroll-padding" => { - if (css.generic.parseWithOptions(ScrollPadding, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"scroll-padding" = c } }; - } - } - }, - .@"font-weight" => { - if (css.generic.parseWithOptions(FontWeight, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"font-weight" = c } }; - } - } - }, - .@"font-size" => { - if (css.generic.parseWithOptions(FontSize, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"font-size" = c } }; - } - } - }, - .@"font-stretch" => { - if (css.generic.parseWithOptions(FontStretch, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"font-stretch" = c } }; - } - } - }, - .@"font-family" => { - if (css.generic.parseWithOptions(BabyList(FontFamily), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"font-family" = c } }; - } - } - }, - .@"font-style" => { - if (css.generic.parseWithOptions(FontStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"font-style" = c } }; - } - } - }, - .@"font-variant-caps" => { - if (css.generic.parseWithOptions(FontVariantCaps, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"font-variant-caps" = c } }; - } - } - }, - .@"line-height" => { - if (css.generic.parseWithOptions(LineHeight, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"line-height" = c } }; - } - } - }, - .font => { - if (css.generic.parseWithOptions(Font, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .font = c } }; - } - } - }, - .@"transition-property" => |pre| { - if (css.generic.parseWithOptions(SmallList(PropertyId, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"transition-property" = .{ c, pre } } }; - } - } - }, - .@"transition-duration" => |pre| { - if (css.generic.parseWithOptions(SmallList(Time, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"transition-duration" = .{ c, pre } } }; - } - } - }, - .@"transition-delay" => |pre| { - if (css.generic.parseWithOptions(SmallList(Time, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"transition-delay" = .{ c, pre } } }; - } - } - }, - .@"transition-timing-function" => |pre| { - if (css.generic.parseWithOptions(SmallList(EasingFunction, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"transition-timing-function" = .{ c, pre } } }; - } - } - }, - .transition => |pre| { - if (css.generic.parseWithOptions(SmallList(Transition, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .transition = .{ c, pre } } }; - } - } - }, - .transform => |pre| { - if (css.generic.parseWithOptions(TransformList, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .transform = .{ c, pre } } }; - } - } - }, - .@"transform-origin" => |pre| { - if (css.generic.parseWithOptions(Position, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"transform-origin" = .{ c, pre } } }; - } - } - }, - .@"transform-style" => |pre| { - if (css.generic.parseWithOptions(TransformStyle, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"transform-style" = .{ c, pre } } }; - } - } - }, - .@"transform-box" => { - if (css.generic.parseWithOptions(TransformBox, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"transform-box" = c } }; - } - } - }, - .@"backface-visibility" => |pre| { - if (css.generic.parseWithOptions(BackfaceVisibility, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"backface-visibility" = .{ c, pre } } }; - } - } - }, - .perspective => |pre| { - if (css.generic.parseWithOptions(Perspective, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .perspective = .{ c, pre } } }; - } - } - }, - .@"perspective-origin" => |pre| { - if (css.generic.parseWithOptions(Position, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"perspective-origin" = .{ c, pre } } }; - } - } - }, - .translate => { - if (css.generic.parseWithOptions(Translate, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .translate = c } }; - } - } - }, - .rotate => { - if (css.generic.parseWithOptions(Rotate, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .rotate = c } }; - } - } - }, - .scale => { - if (css.generic.parseWithOptions(Scale, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .scale = c } }; - } - } - }, - .@"text-decoration-color" => |pre| { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"text-decoration-color" = .{ c, pre } } }; - } - } - }, - .@"text-emphasis-color" => |pre| { - if (css.generic.parseWithOptions(CssColor, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"text-emphasis-color" = .{ c, pre } } }; - } - } - }, - .@"text-shadow" => { - if (css.generic.parseWithOptions(SmallList(TextShadow, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"text-shadow" = c } }; - } - } - }, - .direction => { - if (css.generic.parseWithOptions(Direction, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .direction = c } }; - } - } - }, - .composes => { - return switch (css.generic.parseWithOptions(Composes, input, options)) { - .result => |c| return .{ .result = .{ .composes = c } }, - .err => |e| return .{ .err = e }, - }; - }, - .@"mask-image" => |pre| { - if (css.generic.parseWithOptions(SmallList(Image, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-image" = .{ c, pre } } }; - } - } - }, - .@"mask-mode" => { - if (css.generic.parseWithOptions(SmallList(MaskMode, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-mode" = c } }; - } - } - }, - .@"mask-repeat" => |pre| { - if (css.generic.parseWithOptions(SmallList(BackgroundRepeat, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-repeat" = .{ c, pre } } }; - } - } - }, - .@"mask-position-x" => { - if (css.generic.parseWithOptions(SmallList(HorizontalPosition, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-position-x" = c } }; - } - } - }, - .@"mask-position-y" => { - if (css.generic.parseWithOptions(SmallList(VerticalPosition, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-position-y" = c } }; - } - } - }, - .@"mask-position" => |pre| { - if (css.generic.parseWithOptions(SmallList(Position, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-position" = .{ c, pre } } }; - } - } - }, - .@"mask-clip" => |pre| { - @setEvalBranchQuota(5000); - if (css.generic.parseWithOptions(SmallList(MaskClip, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-clip" = .{ c, pre } } }; - } - } - }, - .@"mask-origin" => |pre| { - if (css.generic.parseWithOptions(SmallList(GeometryBox, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-origin" = .{ c, pre } } }; - } - } - }, - .@"mask-size" => |pre| { - if (css.generic.parseWithOptions(SmallList(BackgroundSize, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-size" = .{ c, pre } } }; - } - } - }, - .@"mask-composite" => { - if (css.generic.parseWithOptions(SmallList(MaskComposite, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-composite" = c } }; - } - } - }, - .@"mask-type" => { - if (css.generic.parseWithOptions(MaskType, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-type" = c } }; - } - } - }, - .mask => |pre| { - if (css.generic.parseWithOptions(SmallList(Mask, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .mask = .{ c, pre } } }; - } - } - }, - .@"mask-border-source" => { - if (css.generic.parseWithOptions(Image, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-border-source" = c } }; - } - } - }, - .@"mask-border-mode" => { - if (css.generic.parseWithOptions(MaskBorderMode, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-border-mode" = c } }; - } - } - }, - .@"mask-border-slice" => { - if (css.generic.parseWithOptions(BorderImageSlice, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-border-slice" = c } }; - } - } - }, - .@"mask-border-width" => { - if (css.generic.parseWithOptions(Rect(BorderImageSideWidth), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-border-width" = c } }; - } - } - }, - .@"mask-border-outset" => { - if (css.generic.parseWithOptions(Rect(LengthOrNumber), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-border-outset" = c } }; - } - } - }, - .@"mask-border-repeat" => { - if (css.generic.parseWithOptions(BorderImageRepeat, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-border-repeat" = c } }; - } - } - }, - .@"mask-border" => { - if (css.generic.parseWithOptions(MaskBorder, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-border" = c } }; - } - } - }, - .@"-webkit-mask-composite" => { - if (css.generic.parseWithOptions(SmallList(WebKitMaskComposite, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"-webkit-mask-composite" = c } }; - } - } - }, - .@"mask-source-type" => |pre| { - if (css.generic.parseWithOptions(SmallList(WebKitMaskSourceType, 1), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-source-type" = .{ c, pre } } }; - } - } - }, - .@"mask-box-image" => |pre| { - if (css.generic.parseWithOptions(BorderImage, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-box-image" = .{ c, pre } } }; - } - } - }, - .@"mask-box-image-source" => |pre| { - if (css.generic.parseWithOptions(Image, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-box-image-source" = .{ c, pre } } }; - } - } - }, - .@"mask-box-image-slice" => |pre| { - if (css.generic.parseWithOptions(BorderImageSlice, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-box-image-slice" = .{ c, pre } } }; - } - } - }, - .@"mask-box-image-width" => |pre| { - if (css.generic.parseWithOptions(Rect(BorderImageSideWidth), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-box-image-width" = .{ c, pre } } }; - } - } - }, - .@"mask-box-image-outset" => |pre| { - if (css.generic.parseWithOptions(Rect(LengthOrNumber), input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-box-image-outset" = .{ c, pre } } }; - } - } - }, - .@"mask-box-image-repeat" => |pre| { - if (css.generic.parseWithOptions(BorderImageRepeat, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"mask-box-image-repeat" = .{ c, pre } } }; - } - } - }, - .@"color-scheme" => { - if (css.generic.parseWithOptions(ColorScheme, input, options).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .@"color-scheme" = c } }; - } - } - }, - .all => return .{ .result = .{ .all = switch (CSSWideKeyword.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }, - .custom => |name| return .{ .result = .{ .custom = switch (CustomProperty.parse(name, input, options)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }, - else => {}, - } - - // If a value was unable to be parsed, treat as an unparsed property. - // This is different from a custom property, handled below, in that the property name is known - // and stored as an enum rather than a string. This lets property handlers more easily deal with it. - // Ideally we'd only do this if var() or env() references were seen, but err on the safe side for now. - input.reset(&state); - return .{ .result = .{ .unparsed = switch (UnparsedProperty.parse(property_id, input, options)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }; - } - - pub fn propertyId(this: *const Property) PropertyId { - return switch (this.*) { - .@"background-color" => .@"background-color", - .@"background-image" => .@"background-image", - .@"background-position-x" => .@"background-position-x", - .@"background-position-y" => .@"background-position-y", - .@"background-position" => .@"background-position", - .@"background-size" => .@"background-size", - .@"background-repeat" => .@"background-repeat", - .@"background-attachment" => .@"background-attachment", - .@"background-clip" => |*v| PropertyId{ .@"background-clip" = v[1] }, - .@"background-origin" => .@"background-origin", - .background => .background, - .@"box-shadow" => |*v| PropertyId{ .@"box-shadow" = v[1] }, - .opacity => .opacity, - .color => .color, - .display => .display, - .visibility => .visibility, - .width => .width, - .height => .height, - .@"min-width" => .@"min-width", - .@"min-height" => .@"min-height", - .@"max-width" => .@"max-width", - .@"max-height" => .@"max-height", - .@"block-size" => .@"block-size", - .@"inline-size" => .@"inline-size", - .@"min-block-size" => .@"min-block-size", - .@"min-inline-size" => .@"min-inline-size", - .@"max-block-size" => .@"max-block-size", - .@"max-inline-size" => .@"max-inline-size", - .@"box-sizing" => |*v| PropertyId{ .@"box-sizing" = v[1] }, - .@"aspect-ratio" => .@"aspect-ratio", - .overflow => .overflow, - .@"overflow-x" => .@"overflow-x", - .@"overflow-y" => .@"overflow-y", - .@"text-overflow" => |*v| PropertyId{ .@"text-overflow" = v[1] }, - .position => .position, - .top => .top, - .bottom => .bottom, - .left => .left, - .right => .right, - .@"inset-block-start" => .@"inset-block-start", - .@"inset-block-end" => .@"inset-block-end", - .@"inset-inline-start" => .@"inset-inline-start", - .@"inset-inline-end" => .@"inset-inline-end", - .@"inset-block" => .@"inset-block", - .@"inset-inline" => .@"inset-inline", - .inset => .inset, - .@"border-spacing" => .@"border-spacing", - .@"border-top-color" => .@"border-top-color", - .@"border-bottom-color" => .@"border-bottom-color", - .@"border-left-color" => .@"border-left-color", - .@"border-right-color" => .@"border-right-color", - .@"border-block-start-color" => .@"border-block-start-color", - .@"border-block-end-color" => .@"border-block-end-color", - .@"border-inline-start-color" => .@"border-inline-start-color", - .@"border-inline-end-color" => .@"border-inline-end-color", - .@"border-top-style" => .@"border-top-style", - .@"border-bottom-style" => .@"border-bottom-style", - .@"border-left-style" => .@"border-left-style", - .@"border-right-style" => .@"border-right-style", - .@"border-block-start-style" => .@"border-block-start-style", - .@"border-block-end-style" => .@"border-block-end-style", - .@"border-inline-start-style" => .@"border-inline-start-style", - .@"border-inline-end-style" => .@"border-inline-end-style", - .@"border-top-width" => .@"border-top-width", - .@"border-bottom-width" => .@"border-bottom-width", - .@"border-left-width" => .@"border-left-width", - .@"border-right-width" => .@"border-right-width", - .@"border-block-start-width" => .@"border-block-start-width", - .@"border-block-end-width" => .@"border-block-end-width", - .@"border-inline-start-width" => .@"border-inline-start-width", - .@"border-inline-end-width" => .@"border-inline-end-width", - .@"border-top-left-radius" => |*v| PropertyId{ .@"border-top-left-radius" = v[1] }, - .@"border-top-right-radius" => |*v| PropertyId{ .@"border-top-right-radius" = v[1] }, - .@"border-bottom-left-radius" => |*v| PropertyId{ .@"border-bottom-left-radius" = v[1] }, - .@"border-bottom-right-radius" => |*v| PropertyId{ .@"border-bottom-right-radius" = v[1] }, - .@"border-start-start-radius" => .@"border-start-start-radius", - .@"border-start-end-radius" => .@"border-start-end-radius", - .@"border-end-start-radius" => .@"border-end-start-radius", - .@"border-end-end-radius" => .@"border-end-end-radius", - .@"border-radius" => |*v| PropertyId{ .@"border-radius" = v[1] }, - .@"border-image-source" => .@"border-image-source", - .@"border-image-outset" => .@"border-image-outset", - .@"border-image-repeat" => .@"border-image-repeat", - .@"border-image-width" => .@"border-image-width", - .@"border-image-slice" => .@"border-image-slice", - .@"border-image" => |*v| PropertyId{ .@"border-image" = v[1] }, - .@"border-color" => .@"border-color", - .@"border-style" => .@"border-style", - .@"border-width" => .@"border-width", - .@"border-block-color" => .@"border-block-color", - .@"border-block-style" => .@"border-block-style", - .@"border-block-width" => .@"border-block-width", - .@"border-inline-color" => .@"border-inline-color", - .@"border-inline-style" => .@"border-inline-style", - .@"border-inline-width" => .@"border-inline-width", - .border => .border, - .@"border-top" => .@"border-top", - .@"border-bottom" => .@"border-bottom", - .@"border-left" => .@"border-left", - .@"border-right" => .@"border-right", - .@"border-block" => .@"border-block", - .@"border-block-start" => .@"border-block-start", - .@"border-block-end" => .@"border-block-end", - .@"border-inline" => .@"border-inline", - .@"border-inline-start" => .@"border-inline-start", - .@"border-inline-end" => .@"border-inline-end", - .outline => .outline, - .@"outline-color" => .@"outline-color", - .@"outline-style" => .@"outline-style", - .@"outline-width" => .@"outline-width", - .@"flex-direction" => |*v| PropertyId{ .@"flex-direction" = v[1] }, - .@"flex-wrap" => |*v| PropertyId{ .@"flex-wrap" = v[1] }, - .@"flex-flow" => |*v| PropertyId{ .@"flex-flow" = v[1] }, - .@"flex-grow" => |*v| PropertyId{ .@"flex-grow" = v[1] }, - .@"flex-shrink" => |*v| PropertyId{ .@"flex-shrink" = v[1] }, - .@"flex-basis" => |*v| PropertyId{ .@"flex-basis" = v[1] }, - .flex => |*v| PropertyId{ .flex = v[1] }, - .order => |*v| PropertyId{ .order = v[1] }, - .@"align-content" => |*v| PropertyId{ .@"align-content" = v[1] }, - .@"justify-content" => |*v| PropertyId{ .@"justify-content" = v[1] }, - .@"place-content" => .@"place-content", - .@"align-self" => |*v| PropertyId{ .@"align-self" = v[1] }, - .@"justify-self" => .@"justify-self", - .@"place-self" => .@"place-self", - .@"align-items" => |*v| PropertyId{ .@"align-items" = v[1] }, - .@"justify-items" => .@"justify-items", - .@"place-items" => .@"place-items", - .@"row-gap" => .@"row-gap", - .@"column-gap" => .@"column-gap", - .gap => .gap, - .@"box-orient" => |*v| PropertyId{ .@"box-orient" = v[1] }, - .@"box-direction" => |*v| PropertyId{ .@"box-direction" = v[1] }, - .@"box-ordinal-group" => |*v| PropertyId{ .@"box-ordinal-group" = v[1] }, - .@"box-align" => |*v| PropertyId{ .@"box-align" = v[1] }, - .@"box-flex" => |*v| PropertyId{ .@"box-flex" = v[1] }, - .@"box-flex-group" => |*v| PropertyId{ .@"box-flex-group" = v[1] }, - .@"box-pack" => |*v| PropertyId{ .@"box-pack" = v[1] }, - .@"box-lines" => |*v| PropertyId{ .@"box-lines" = v[1] }, - .@"flex-pack" => |*v| PropertyId{ .@"flex-pack" = v[1] }, - .@"flex-order" => |*v| PropertyId{ .@"flex-order" = v[1] }, - .@"flex-align" => |*v| PropertyId{ .@"flex-align" = v[1] }, - .@"flex-item-align" => |*v| PropertyId{ .@"flex-item-align" = v[1] }, - .@"flex-line-pack" => |*v| PropertyId{ .@"flex-line-pack" = v[1] }, - .@"flex-positive" => |*v| PropertyId{ .@"flex-positive" = v[1] }, - .@"flex-negative" => |*v| PropertyId{ .@"flex-negative" = v[1] }, - .@"flex-preferred-size" => |*v| PropertyId{ .@"flex-preferred-size" = v[1] }, - .@"margin-top" => .@"margin-top", - .@"margin-bottom" => .@"margin-bottom", - .@"margin-left" => .@"margin-left", - .@"margin-right" => .@"margin-right", - .@"margin-block-start" => .@"margin-block-start", - .@"margin-block-end" => .@"margin-block-end", - .@"margin-inline-start" => .@"margin-inline-start", - .@"margin-inline-end" => .@"margin-inline-end", - .@"margin-block" => .@"margin-block", - .@"margin-inline" => .@"margin-inline", - .margin => .margin, - .@"padding-top" => .@"padding-top", - .@"padding-bottom" => .@"padding-bottom", - .@"padding-left" => .@"padding-left", - .@"padding-right" => .@"padding-right", - .@"padding-block-start" => .@"padding-block-start", - .@"padding-block-end" => .@"padding-block-end", - .@"padding-inline-start" => .@"padding-inline-start", - .@"padding-inline-end" => .@"padding-inline-end", - .@"padding-block" => .@"padding-block", - .@"padding-inline" => .@"padding-inline", - .padding => .padding, - .@"scroll-margin-top" => .@"scroll-margin-top", - .@"scroll-margin-bottom" => .@"scroll-margin-bottom", - .@"scroll-margin-left" => .@"scroll-margin-left", - .@"scroll-margin-right" => .@"scroll-margin-right", - .@"scroll-margin-block-start" => .@"scroll-margin-block-start", - .@"scroll-margin-block-end" => .@"scroll-margin-block-end", - .@"scroll-margin-inline-start" => .@"scroll-margin-inline-start", - .@"scroll-margin-inline-end" => .@"scroll-margin-inline-end", - .@"scroll-margin-block" => .@"scroll-margin-block", - .@"scroll-margin-inline" => .@"scroll-margin-inline", - .@"scroll-margin" => .@"scroll-margin", - .@"scroll-padding-top" => .@"scroll-padding-top", - .@"scroll-padding-bottom" => .@"scroll-padding-bottom", - .@"scroll-padding-left" => .@"scroll-padding-left", - .@"scroll-padding-right" => .@"scroll-padding-right", - .@"scroll-padding-block-start" => .@"scroll-padding-block-start", - .@"scroll-padding-block-end" => .@"scroll-padding-block-end", - .@"scroll-padding-inline-start" => .@"scroll-padding-inline-start", - .@"scroll-padding-inline-end" => .@"scroll-padding-inline-end", - .@"scroll-padding-block" => .@"scroll-padding-block", - .@"scroll-padding-inline" => .@"scroll-padding-inline", - .@"scroll-padding" => .@"scroll-padding", - .@"font-weight" => .@"font-weight", - .@"font-size" => .@"font-size", - .@"font-stretch" => .@"font-stretch", - .@"font-family" => .@"font-family", - .@"font-style" => .@"font-style", - .@"font-variant-caps" => .@"font-variant-caps", - .@"line-height" => .@"line-height", - .font => .font, - .@"transition-property" => |*v| PropertyId{ .@"transition-property" = v[1] }, - .@"transition-duration" => |*v| PropertyId{ .@"transition-duration" = v[1] }, - .@"transition-delay" => |*v| PropertyId{ .@"transition-delay" = v[1] }, - .@"transition-timing-function" => |*v| PropertyId{ .@"transition-timing-function" = v[1] }, - .transition => |*v| PropertyId{ .transition = v[1] }, - .transform => |*v| PropertyId{ .transform = v[1] }, - .@"transform-origin" => |*v| PropertyId{ .@"transform-origin" = v[1] }, - .@"transform-style" => |*v| PropertyId{ .@"transform-style" = v[1] }, - .@"transform-box" => .@"transform-box", - .@"backface-visibility" => |*v| PropertyId{ .@"backface-visibility" = v[1] }, - .perspective => |*v| PropertyId{ .perspective = v[1] }, - .@"perspective-origin" => |*v| PropertyId{ .@"perspective-origin" = v[1] }, - .translate => .translate, - .rotate => .rotate, - .scale => .scale, - .@"text-decoration-color" => |*v| PropertyId{ .@"text-decoration-color" = v[1] }, - .@"text-emphasis-color" => |*v| PropertyId{ .@"text-emphasis-color" = v[1] }, - .@"text-shadow" => .@"text-shadow", - .direction => .direction, - .composes => .composes, - .@"mask-image" => |*v| PropertyId{ .@"mask-image" = v[1] }, - .@"mask-mode" => .@"mask-mode", - .@"mask-repeat" => |*v| PropertyId{ .@"mask-repeat" = v[1] }, - .@"mask-position-x" => .@"mask-position-x", - .@"mask-position-y" => .@"mask-position-y", - .@"mask-position" => |*v| PropertyId{ .@"mask-position" = v[1] }, - .@"mask-clip" => |*v| PropertyId{ .@"mask-clip" = v[1] }, - .@"mask-origin" => |*v| PropertyId{ .@"mask-origin" = v[1] }, - .@"mask-size" => |*v| PropertyId{ .@"mask-size" = v[1] }, - .@"mask-composite" => .@"mask-composite", - .@"mask-type" => .@"mask-type", - .mask => |*v| PropertyId{ .mask = v[1] }, - .@"mask-border-source" => .@"mask-border-source", - .@"mask-border-mode" => .@"mask-border-mode", - .@"mask-border-slice" => .@"mask-border-slice", - .@"mask-border-width" => .@"mask-border-width", - .@"mask-border-outset" => .@"mask-border-outset", - .@"mask-border-repeat" => .@"mask-border-repeat", - .@"mask-border" => .@"mask-border", - .@"-webkit-mask-composite" => .@"-webkit-mask-composite", - .@"mask-source-type" => |*v| PropertyId{ .@"mask-source-type" = v[1] }, - .@"mask-box-image" => |*v| PropertyId{ .@"mask-box-image" = v[1] }, - .@"mask-box-image-source" => |*v| PropertyId{ .@"mask-box-image-source" = v[1] }, - .@"mask-box-image-slice" => |*v| PropertyId{ .@"mask-box-image-slice" = v[1] }, - .@"mask-box-image-width" => |*v| PropertyId{ .@"mask-box-image-width" = v[1] }, - .@"mask-box-image-outset" => |*v| PropertyId{ .@"mask-box-image-outset" = v[1] }, - .@"mask-box-image-repeat" => |*v| PropertyId{ .@"mask-box-image-repeat" = v[1] }, - .@"color-scheme" => .@"color-scheme", - .all => PropertyId.all, - .unparsed => |unparsed| unparsed.property_id, - .custom => |c| .{ .custom = c.name }, - }; - } - - pub fn deepClone(this: *const Property, allocator: std.mem.Allocator) Property { - return switch (this.*) { - .@"background-color" => |*v| .{ .@"background-color" = v.deepClone(allocator) }, - .@"background-image" => |*v| .{ .@"background-image" = v.deepClone(allocator) }, - .@"background-position-x" => |*v| .{ .@"background-position-x" = v.deepClone(allocator) }, - .@"background-position-y" => |*v| .{ .@"background-position-y" = v.deepClone(allocator) }, - .@"background-position" => |*v| .{ .@"background-position" = v.deepClone(allocator) }, - .@"background-size" => |*v| .{ .@"background-size" = v.deepClone(allocator) }, - .@"background-repeat" => |*v| .{ .@"background-repeat" = v.deepClone(allocator) }, - .@"background-attachment" => |*v| .{ .@"background-attachment" = v.deepClone(allocator) }, - .@"background-clip" => |*v| .{ .@"background-clip" = .{ v[0].deepClone(allocator), v[1] } }, - .@"background-origin" => |*v| .{ .@"background-origin" = v.deepClone(allocator) }, - .background => |*v| .{ .background = v.deepClone(allocator) }, - .@"box-shadow" => |*v| .{ .@"box-shadow" = .{ v[0].deepClone(allocator), v[1] } }, - .opacity => |*v| .{ .opacity = v.deepClone(allocator) }, - .color => |*v| .{ .color = v.deepClone(allocator) }, - .display => |*v| .{ .display = v.deepClone(allocator) }, - .visibility => |*v| .{ .visibility = v.deepClone(allocator) }, - .width => |*v| .{ .width = v.deepClone(allocator) }, - .height => |*v| .{ .height = v.deepClone(allocator) }, - .@"min-width" => |*v| .{ .@"min-width" = v.deepClone(allocator) }, - .@"min-height" => |*v| .{ .@"min-height" = v.deepClone(allocator) }, - .@"max-width" => |*v| .{ .@"max-width" = v.deepClone(allocator) }, - .@"max-height" => |*v| .{ .@"max-height" = v.deepClone(allocator) }, - .@"block-size" => |*v| .{ .@"block-size" = v.deepClone(allocator) }, - .@"inline-size" => |*v| .{ .@"inline-size" = v.deepClone(allocator) }, - .@"min-block-size" => |*v| .{ .@"min-block-size" = v.deepClone(allocator) }, - .@"min-inline-size" => |*v| .{ .@"min-inline-size" = v.deepClone(allocator) }, - .@"max-block-size" => |*v| .{ .@"max-block-size" = v.deepClone(allocator) }, - .@"max-inline-size" => |*v| .{ .@"max-inline-size" = v.deepClone(allocator) }, - .@"box-sizing" => |*v| .{ .@"box-sizing" = .{ v[0].deepClone(allocator), v[1] } }, - .@"aspect-ratio" => |*v| .{ .@"aspect-ratio" = v.deepClone(allocator) }, - .overflow => |*v| .{ .overflow = v.deepClone(allocator) }, - .@"overflow-x" => |*v| .{ .@"overflow-x" = v.deepClone(allocator) }, - .@"overflow-y" => |*v| .{ .@"overflow-y" = v.deepClone(allocator) }, - .@"text-overflow" => |*v| .{ .@"text-overflow" = .{ v[0].deepClone(allocator), v[1] } }, - .position => |*v| .{ .position = v.deepClone(allocator) }, - .top => |*v| .{ .top = v.deepClone(allocator) }, - .bottom => |*v| .{ .bottom = v.deepClone(allocator) }, - .left => |*v| .{ .left = v.deepClone(allocator) }, - .right => |*v| .{ .right = v.deepClone(allocator) }, - .@"inset-block-start" => |*v| .{ .@"inset-block-start" = v.deepClone(allocator) }, - .@"inset-block-end" => |*v| .{ .@"inset-block-end" = v.deepClone(allocator) }, - .@"inset-inline-start" => |*v| .{ .@"inset-inline-start" = v.deepClone(allocator) }, - .@"inset-inline-end" => |*v| .{ .@"inset-inline-end" = v.deepClone(allocator) }, - .@"inset-block" => |*v| .{ .@"inset-block" = v.deepClone(allocator) }, - .@"inset-inline" => |*v| .{ .@"inset-inline" = v.deepClone(allocator) }, - .inset => |*v| .{ .inset = v.deepClone(allocator) }, - .@"border-spacing" => |*v| .{ .@"border-spacing" = v.deepClone(allocator) }, - .@"border-top-color" => |*v| .{ .@"border-top-color" = v.deepClone(allocator) }, - .@"border-bottom-color" => |*v| .{ .@"border-bottom-color" = v.deepClone(allocator) }, - .@"border-left-color" => |*v| .{ .@"border-left-color" = v.deepClone(allocator) }, - .@"border-right-color" => |*v| .{ .@"border-right-color" = v.deepClone(allocator) }, - .@"border-block-start-color" => |*v| .{ .@"border-block-start-color" = v.deepClone(allocator) }, - .@"border-block-end-color" => |*v| .{ .@"border-block-end-color" = v.deepClone(allocator) }, - .@"border-inline-start-color" => |*v| .{ .@"border-inline-start-color" = v.deepClone(allocator) }, - .@"border-inline-end-color" => |*v| .{ .@"border-inline-end-color" = v.deepClone(allocator) }, - .@"border-top-style" => |*v| .{ .@"border-top-style" = v.deepClone(allocator) }, - .@"border-bottom-style" => |*v| .{ .@"border-bottom-style" = v.deepClone(allocator) }, - .@"border-left-style" => |*v| .{ .@"border-left-style" = v.deepClone(allocator) }, - .@"border-right-style" => |*v| .{ .@"border-right-style" = v.deepClone(allocator) }, - .@"border-block-start-style" => |*v| .{ .@"border-block-start-style" = v.deepClone(allocator) }, - .@"border-block-end-style" => |*v| .{ .@"border-block-end-style" = v.deepClone(allocator) }, - .@"border-inline-start-style" => |*v| .{ .@"border-inline-start-style" = v.deepClone(allocator) }, - .@"border-inline-end-style" => |*v| .{ .@"border-inline-end-style" = v.deepClone(allocator) }, - .@"border-top-width" => |*v| .{ .@"border-top-width" = v.deepClone(allocator) }, - .@"border-bottom-width" => |*v| .{ .@"border-bottom-width" = v.deepClone(allocator) }, - .@"border-left-width" => |*v| .{ .@"border-left-width" = v.deepClone(allocator) }, - .@"border-right-width" => |*v| .{ .@"border-right-width" = v.deepClone(allocator) }, - .@"border-block-start-width" => |*v| .{ .@"border-block-start-width" = v.deepClone(allocator) }, - .@"border-block-end-width" => |*v| .{ .@"border-block-end-width" = v.deepClone(allocator) }, - .@"border-inline-start-width" => |*v| .{ .@"border-inline-start-width" = v.deepClone(allocator) }, - .@"border-inline-end-width" => |*v| .{ .@"border-inline-end-width" = v.deepClone(allocator) }, - .@"border-top-left-radius" => |*v| .{ .@"border-top-left-radius" = .{ v[0].deepClone(allocator), v[1] } }, - .@"border-top-right-radius" => |*v| .{ .@"border-top-right-radius" = .{ v[0].deepClone(allocator), v[1] } }, - .@"border-bottom-left-radius" => |*v| .{ .@"border-bottom-left-radius" = .{ v[0].deepClone(allocator), v[1] } }, - .@"border-bottom-right-radius" => |*v| .{ .@"border-bottom-right-radius" = .{ v[0].deepClone(allocator), v[1] } }, - .@"border-start-start-radius" => |*v| .{ .@"border-start-start-radius" = v.deepClone(allocator) }, - .@"border-start-end-radius" => |*v| .{ .@"border-start-end-radius" = v.deepClone(allocator) }, - .@"border-end-start-radius" => |*v| .{ .@"border-end-start-radius" = v.deepClone(allocator) }, - .@"border-end-end-radius" => |*v| .{ .@"border-end-end-radius" = v.deepClone(allocator) }, - .@"border-radius" => |*v| .{ .@"border-radius" = .{ v[0].deepClone(allocator), v[1] } }, - .@"border-image-source" => |*v| .{ .@"border-image-source" = v.deepClone(allocator) }, - .@"border-image-outset" => |*v| .{ .@"border-image-outset" = v.deepClone(allocator) }, - .@"border-image-repeat" => |*v| .{ .@"border-image-repeat" = v.deepClone(allocator) }, - .@"border-image-width" => |*v| .{ .@"border-image-width" = v.deepClone(allocator) }, - .@"border-image-slice" => |*v| .{ .@"border-image-slice" = v.deepClone(allocator) }, - .@"border-image" => |*v| .{ .@"border-image" = .{ v[0].deepClone(allocator), v[1] } }, - .@"border-color" => |*v| .{ .@"border-color" = v.deepClone(allocator) }, - .@"border-style" => |*v| .{ .@"border-style" = v.deepClone(allocator) }, - .@"border-width" => |*v| .{ .@"border-width" = v.deepClone(allocator) }, - .@"border-block-color" => |*v| .{ .@"border-block-color" = v.deepClone(allocator) }, - .@"border-block-style" => |*v| .{ .@"border-block-style" = v.deepClone(allocator) }, - .@"border-block-width" => |*v| .{ .@"border-block-width" = v.deepClone(allocator) }, - .@"border-inline-color" => |*v| .{ .@"border-inline-color" = v.deepClone(allocator) }, - .@"border-inline-style" => |*v| .{ .@"border-inline-style" = v.deepClone(allocator) }, - .@"border-inline-width" => |*v| .{ .@"border-inline-width" = v.deepClone(allocator) }, - .border => |*v| .{ .border = v.deepClone(allocator) }, - .@"border-top" => |*v| .{ .@"border-top" = v.deepClone(allocator) }, - .@"border-bottom" => |*v| .{ .@"border-bottom" = v.deepClone(allocator) }, - .@"border-left" => |*v| .{ .@"border-left" = v.deepClone(allocator) }, - .@"border-right" => |*v| .{ .@"border-right" = v.deepClone(allocator) }, - .@"border-block" => |*v| .{ .@"border-block" = v.deepClone(allocator) }, - .@"border-block-start" => |*v| .{ .@"border-block-start" = v.deepClone(allocator) }, - .@"border-block-end" => |*v| .{ .@"border-block-end" = v.deepClone(allocator) }, - .@"border-inline" => |*v| .{ .@"border-inline" = v.deepClone(allocator) }, - .@"border-inline-start" => |*v| .{ .@"border-inline-start" = v.deepClone(allocator) }, - .@"border-inline-end" => |*v| .{ .@"border-inline-end" = v.deepClone(allocator) }, - .outline => |*v| .{ .outline = v.deepClone(allocator) }, - .@"outline-color" => |*v| .{ .@"outline-color" = v.deepClone(allocator) }, - .@"outline-style" => |*v| .{ .@"outline-style" = v.deepClone(allocator) }, - .@"outline-width" => |*v| .{ .@"outline-width" = v.deepClone(allocator) }, - .@"flex-direction" => |*v| .{ .@"flex-direction" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-wrap" => |*v| .{ .@"flex-wrap" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-flow" => |*v| .{ .@"flex-flow" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-grow" => |*v| .{ .@"flex-grow" = .{ v[0], v[1] } }, - .@"flex-shrink" => |*v| .{ .@"flex-shrink" = .{ v[0], v[1] } }, - .@"flex-basis" => |*v| .{ .@"flex-basis" = .{ v[0].deepClone(allocator), v[1] } }, - .flex => |*v| .{ .flex = .{ v[0].deepClone(allocator), v[1] } }, - .order => |*v| .{ .order = .{ v[0], v[1] } }, - .@"align-content" => |*v| .{ .@"align-content" = .{ v[0].deepClone(allocator), v[1] } }, - .@"justify-content" => |*v| .{ .@"justify-content" = .{ v[0].deepClone(allocator), v[1] } }, - .@"place-content" => |*v| .{ .@"place-content" = v.deepClone(allocator) }, - .@"align-self" => |*v| .{ .@"align-self" = .{ v[0].deepClone(allocator), v[1] } }, - .@"justify-self" => |*v| .{ .@"justify-self" = v.deepClone(allocator) }, - .@"place-self" => |*v| .{ .@"place-self" = v.deepClone(allocator) }, - .@"align-items" => |*v| .{ .@"align-items" = .{ v[0].deepClone(allocator), v[1] } }, - .@"justify-items" => |*v| .{ .@"justify-items" = v.deepClone(allocator) }, - .@"place-items" => |*v| .{ .@"place-items" = v.deepClone(allocator) }, - .@"row-gap" => |*v| .{ .@"row-gap" = v.deepClone(allocator) }, - .@"column-gap" => |*v| .{ .@"column-gap" = v.deepClone(allocator) }, - .gap => |*v| .{ .gap = v.deepClone(allocator) }, - .@"box-orient" => |*v| .{ .@"box-orient" = .{ v[0].deepClone(allocator), v[1] } }, - .@"box-direction" => |*v| .{ .@"box-direction" = .{ v[0].deepClone(allocator), v[1] } }, - .@"box-ordinal-group" => |*v| .{ .@"box-ordinal-group" = .{ v[0], v[1] } }, - .@"box-align" => |*v| .{ .@"box-align" = .{ v[0].deepClone(allocator), v[1] } }, - .@"box-flex" => |*v| .{ .@"box-flex" = .{ v[0], v[1] } }, - .@"box-flex-group" => |*v| .{ .@"box-flex-group" = .{ v[0], v[1] } }, - .@"box-pack" => |*v| .{ .@"box-pack" = .{ v[0].deepClone(allocator), v[1] } }, - .@"box-lines" => |*v| .{ .@"box-lines" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-pack" => |*v| .{ .@"flex-pack" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-order" => |*v| .{ .@"flex-order" = .{ v[0], v[1] } }, - .@"flex-align" => |*v| .{ .@"flex-align" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-item-align" => |*v| .{ .@"flex-item-align" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-line-pack" => |*v| .{ .@"flex-line-pack" = .{ v[0].deepClone(allocator), v[1] } }, - .@"flex-positive" => |*v| .{ .@"flex-positive" = .{ v[0], v[1] } }, - .@"flex-negative" => |*v| .{ .@"flex-negative" = .{ v[0], v[1] } }, - .@"flex-preferred-size" => |*v| .{ .@"flex-preferred-size" = .{ v[0].deepClone(allocator), v[1] } }, - .@"margin-top" => |*v| .{ .@"margin-top" = v.deepClone(allocator) }, - .@"margin-bottom" => |*v| .{ .@"margin-bottom" = v.deepClone(allocator) }, - .@"margin-left" => |*v| .{ .@"margin-left" = v.deepClone(allocator) }, - .@"margin-right" => |*v| .{ .@"margin-right" = v.deepClone(allocator) }, - .@"margin-block-start" => |*v| .{ .@"margin-block-start" = v.deepClone(allocator) }, - .@"margin-block-end" => |*v| .{ .@"margin-block-end" = v.deepClone(allocator) }, - .@"margin-inline-start" => |*v| .{ .@"margin-inline-start" = v.deepClone(allocator) }, - .@"margin-inline-end" => |*v| .{ .@"margin-inline-end" = v.deepClone(allocator) }, - .@"margin-block" => |*v| .{ .@"margin-block" = v.deepClone(allocator) }, - .@"margin-inline" => |*v| .{ .@"margin-inline" = v.deepClone(allocator) }, - .margin => |*v| .{ .margin = v.deepClone(allocator) }, - .@"padding-top" => |*v| .{ .@"padding-top" = v.deepClone(allocator) }, - .@"padding-bottom" => |*v| .{ .@"padding-bottom" = v.deepClone(allocator) }, - .@"padding-left" => |*v| .{ .@"padding-left" = v.deepClone(allocator) }, - .@"padding-right" => |*v| .{ .@"padding-right" = v.deepClone(allocator) }, - .@"padding-block-start" => |*v| .{ .@"padding-block-start" = v.deepClone(allocator) }, - .@"padding-block-end" => |*v| .{ .@"padding-block-end" = v.deepClone(allocator) }, - .@"padding-inline-start" => |*v| .{ .@"padding-inline-start" = v.deepClone(allocator) }, - .@"padding-inline-end" => |*v| .{ .@"padding-inline-end" = v.deepClone(allocator) }, - .@"padding-block" => |*v| .{ .@"padding-block" = v.deepClone(allocator) }, - .@"padding-inline" => |*v| .{ .@"padding-inline" = v.deepClone(allocator) }, - .padding => |*v| .{ .padding = v.deepClone(allocator) }, - .@"scroll-margin-top" => |*v| .{ .@"scroll-margin-top" = v.deepClone(allocator) }, - .@"scroll-margin-bottom" => |*v| .{ .@"scroll-margin-bottom" = v.deepClone(allocator) }, - .@"scroll-margin-left" => |*v| .{ .@"scroll-margin-left" = v.deepClone(allocator) }, - .@"scroll-margin-right" => |*v| .{ .@"scroll-margin-right" = v.deepClone(allocator) }, - .@"scroll-margin-block-start" => |*v| .{ .@"scroll-margin-block-start" = v.deepClone(allocator) }, - .@"scroll-margin-block-end" => |*v| .{ .@"scroll-margin-block-end" = v.deepClone(allocator) }, - .@"scroll-margin-inline-start" => |*v| .{ .@"scroll-margin-inline-start" = v.deepClone(allocator) }, - .@"scroll-margin-inline-end" => |*v| .{ .@"scroll-margin-inline-end" = v.deepClone(allocator) }, - .@"scroll-margin-block" => |*v| .{ .@"scroll-margin-block" = v.deepClone(allocator) }, - .@"scroll-margin-inline" => |*v| .{ .@"scroll-margin-inline" = v.deepClone(allocator) }, - .@"scroll-margin" => |*v| .{ .@"scroll-margin" = v.deepClone(allocator) }, - .@"scroll-padding-top" => |*v| .{ .@"scroll-padding-top" = v.deepClone(allocator) }, - .@"scroll-padding-bottom" => |*v| .{ .@"scroll-padding-bottom" = v.deepClone(allocator) }, - .@"scroll-padding-left" => |*v| .{ .@"scroll-padding-left" = v.deepClone(allocator) }, - .@"scroll-padding-right" => |*v| .{ .@"scroll-padding-right" = v.deepClone(allocator) }, - .@"scroll-padding-block-start" => |*v| .{ .@"scroll-padding-block-start" = v.deepClone(allocator) }, - .@"scroll-padding-block-end" => |*v| .{ .@"scroll-padding-block-end" = v.deepClone(allocator) }, - .@"scroll-padding-inline-start" => |*v| .{ .@"scroll-padding-inline-start" = v.deepClone(allocator) }, - .@"scroll-padding-inline-end" => |*v| .{ .@"scroll-padding-inline-end" = v.deepClone(allocator) }, - .@"scroll-padding-block" => |*v| .{ .@"scroll-padding-block" = v.deepClone(allocator) }, - .@"scroll-padding-inline" => |*v| .{ .@"scroll-padding-inline" = v.deepClone(allocator) }, - .@"scroll-padding" => |*v| .{ .@"scroll-padding" = v.deepClone(allocator) }, - .@"font-weight" => |*v| .{ .@"font-weight" = v.deepClone(allocator) }, - .@"font-size" => |*v| .{ .@"font-size" = v.deepClone(allocator) }, - .@"font-stretch" => |*v| .{ .@"font-stretch" = v.deepClone(allocator) }, - .@"font-family" => |*v| .{ .@"font-family" = css.generic.deepClone(BabyList(FontFamily), v, allocator) }, - .@"font-style" => |*v| .{ .@"font-style" = v.deepClone(allocator) }, - .@"font-variant-caps" => |*v| .{ .@"font-variant-caps" = v.deepClone(allocator) }, - .@"line-height" => |*v| .{ .@"line-height" = v.deepClone(allocator) }, - .font => |*v| .{ .font = v.deepClone(allocator) }, - .@"transition-property" => |*v| .{ .@"transition-property" = .{ v[0].deepClone(allocator), v[1] } }, - .@"transition-duration" => |*v| .{ .@"transition-duration" = .{ v[0].deepClone(allocator), v[1] } }, - .@"transition-delay" => |*v| .{ .@"transition-delay" = .{ v[0].deepClone(allocator), v[1] } }, - .@"transition-timing-function" => |*v| .{ .@"transition-timing-function" = .{ v[0].deepClone(allocator), v[1] } }, - .transition => |*v| .{ .transition = .{ v[0].deepClone(allocator), v[1] } }, - .transform => |*v| .{ .transform = .{ v[0].deepClone(allocator), v[1] } }, - .@"transform-origin" => |*v| .{ .@"transform-origin" = .{ v[0].deepClone(allocator), v[1] } }, - .@"transform-style" => |*v| .{ .@"transform-style" = .{ v[0].deepClone(allocator), v[1] } }, - .@"transform-box" => |*v| .{ .@"transform-box" = v.deepClone(allocator) }, - .@"backface-visibility" => |*v| .{ .@"backface-visibility" = .{ v[0].deepClone(allocator), v[1] } }, - .perspective => |*v| .{ .perspective = .{ v[0].deepClone(allocator), v[1] } }, - .@"perspective-origin" => |*v| .{ .@"perspective-origin" = .{ v[0].deepClone(allocator), v[1] } }, - .translate => |*v| .{ .translate = v.deepClone(allocator) }, - .rotate => |*v| .{ .rotate = v.deepClone(allocator) }, - .scale => |*v| .{ .scale = v.deepClone(allocator) }, - .@"text-decoration-color" => |*v| .{ .@"text-decoration-color" = .{ v[0].deepClone(allocator), v[1] } }, - .@"text-emphasis-color" => |*v| .{ .@"text-emphasis-color" = .{ v[0].deepClone(allocator), v[1] } }, - .@"text-shadow" => |*v| .{ .@"text-shadow" = v.deepClone(allocator) }, - .direction => |*v| .{ .direction = v.deepClone(allocator) }, - .composes => |*v| .{ .composes = v.deepClone(allocator) }, - .@"mask-image" => |*v| .{ .@"mask-image" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-mode" => |*v| .{ .@"mask-mode" = v.deepClone(allocator) }, - .@"mask-repeat" => |*v| .{ .@"mask-repeat" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-position-x" => |*v| .{ .@"mask-position-x" = v.deepClone(allocator) }, - .@"mask-position-y" => |*v| .{ .@"mask-position-y" = v.deepClone(allocator) }, - .@"mask-position" => |*v| .{ .@"mask-position" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-clip" => |*v| .{ .@"mask-clip" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-origin" => |*v| .{ .@"mask-origin" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-size" => |*v| .{ .@"mask-size" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-composite" => |*v| .{ .@"mask-composite" = v.deepClone(allocator) }, - .@"mask-type" => |*v| .{ .@"mask-type" = v.deepClone(allocator) }, - .mask => |*v| .{ .mask = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-border-source" => |*v| .{ .@"mask-border-source" = v.deepClone(allocator) }, - .@"mask-border-mode" => |*v| .{ .@"mask-border-mode" = v.deepClone(allocator) }, - .@"mask-border-slice" => |*v| .{ .@"mask-border-slice" = v.deepClone(allocator) }, - .@"mask-border-width" => |*v| .{ .@"mask-border-width" = v.deepClone(allocator) }, - .@"mask-border-outset" => |*v| .{ .@"mask-border-outset" = v.deepClone(allocator) }, - .@"mask-border-repeat" => |*v| .{ .@"mask-border-repeat" = v.deepClone(allocator) }, - .@"mask-border" => |*v| .{ .@"mask-border" = v.deepClone(allocator) }, - .@"-webkit-mask-composite" => |*v| .{ .@"-webkit-mask-composite" = v.deepClone(allocator) }, - .@"mask-source-type" => |*v| .{ .@"mask-source-type" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-box-image" => |*v| .{ .@"mask-box-image" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-box-image-source" => |*v| .{ .@"mask-box-image-source" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-box-image-slice" => |*v| .{ .@"mask-box-image-slice" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-box-image-width" => |*v| .{ .@"mask-box-image-width" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-box-image-outset" => |*v| .{ .@"mask-box-image-outset" = .{ v[0].deepClone(allocator), v[1] } }, - .@"mask-box-image-repeat" => |*v| .{ .@"mask-box-image-repeat" = .{ v[0].deepClone(allocator), v[1] } }, - .@"color-scheme" => |*v| .{ .@"color-scheme" = v.deepClone(allocator) }, - .all => |*a| return .{ .all = a.deepClone(allocator) }, - .unparsed => |*u| return .{ .unparsed = u.deepClone(allocator) }, - .custom => |*c| return .{ .custom = c.deepClone(allocator) }, - }; - } - - /// We're going to have this empty for now since not every property has a deinit function. - /// It's not strictly necessary since all allocations are into an arena. - /// It's mostly intended as a performance optimization in the case where mimalloc arena is used, - /// since it can reclaim the memory and use it for subsequent allocations. - /// I haven't benchmarked that though, so I don't actually know how much faster it would actually make it. - pub fn deinit(this: *@This(), allocator: std.mem.Allocator) void { - _ = this; - _ = allocator; - } - - pub inline fn __toCssHelper(this: *const Property) struct { []const u8, VendorPrefix } { - return switch (this.*) { - .@"background-color" => .{ "background-color", VendorPrefix{ .none = true } }, - .@"background-image" => .{ "background-image", VendorPrefix{ .none = true } }, - .@"background-position-x" => .{ "background-position-x", VendorPrefix{ .none = true } }, - .@"background-position-y" => .{ "background-position-y", VendorPrefix{ .none = true } }, - .@"background-position" => .{ "background-position", VendorPrefix{ .none = true } }, - .@"background-size" => .{ "background-size", VendorPrefix{ .none = true } }, - .@"background-repeat" => .{ "background-repeat", VendorPrefix{ .none = true } }, - .@"background-attachment" => .{ "background-attachment", VendorPrefix{ .none = true } }, - .@"background-clip" => |*x| .{ "background-clip", x.@"1" }, - .@"background-origin" => .{ "background-origin", VendorPrefix{ .none = true } }, - .background => .{ "background", VendorPrefix{ .none = true } }, - .@"box-shadow" => |*x| .{ "box-shadow", x.@"1" }, - .opacity => .{ "opacity", VendorPrefix{ .none = true } }, - .color => .{ "color", VendorPrefix{ .none = true } }, - .display => .{ "display", VendorPrefix{ .none = true } }, - .visibility => .{ "visibility", VendorPrefix{ .none = true } }, - .width => .{ "width", VendorPrefix{ .none = true } }, - .height => .{ "height", VendorPrefix{ .none = true } }, - .@"min-width" => .{ "min-width", VendorPrefix{ .none = true } }, - .@"min-height" => .{ "min-height", VendorPrefix{ .none = true } }, - .@"max-width" => .{ "max-width", VendorPrefix{ .none = true } }, - .@"max-height" => .{ "max-height", VendorPrefix{ .none = true } }, - .@"block-size" => .{ "block-size", VendorPrefix{ .none = true } }, - .@"inline-size" => .{ "inline-size", VendorPrefix{ .none = true } }, - .@"min-block-size" => .{ "min-block-size", VendorPrefix{ .none = true } }, - .@"min-inline-size" => .{ "min-inline-size", VendorPrefix{ .none = true } }, - .@"max-block-size" => .{ "max-block-size", VendorPrefix{ .none = true } }, - .@"max-inline-size" => .{ "max-inline-size", VendorPrefix{ .none = true } }, - .@"box-sizing" => |*x| .{ "box-sizing", x.@"1" }, - .@"aspect-ratio" => .{ "aspect-ratio", VendorPrefix{ .none = true } }, - .overflow => .{ "overflow", VendorPrefix{ .none = true } }, - .@"overflow-x" => .{ "overflow-x", VendorPrefix{ .none = true } }, - .@"overflow-y" => .{ "overflow-y", VendorPrefix{ .none = true } }, - .@"text-overflow" => |*x| .{ "text-overflow", x.@"1" }, - .position => .{ "position", VendorPrefix{ .none = true } }, - .top => .{ "top", VendorPrefix{ .none = true } }, - .bottom => .{ "bottom", VendorPrefix{ .none = true } }, - .left => .{ "left", VendorPrefix{ .none = true } }, - .right => .{ "right", VendorPrefix{ .none = true } }, - .@"inset-block-start" => .{ "inset-block-start", VendorPrefix{ .none = true } }, - .@"inset-block-end" => .{ "inset-block-end", VendorPrefix{ .none = true } }, - .@"inset-inline-start" => .{ "inset-inline-start", VendorPrefix{ .none = true } }, - .@"inset-inline-end" => .{ "inset-inline-end", VendorPrefix{ .none = true } }, - .@"inset-block" => .{ "inset-block", VendorPrefix{ .none = true } }, - .@"inset-inline" => .{ "inset-inline", VendorPrefix{ .none = true } }, - .inset => .{ "inset", VendorPrefix{ .none = true } }, - .@"border-spacing" => .{ "border-spacing", VendorPrefix{ .none = true } }, - .@"border-top-color" => .{ "border-top-color", VendorPrefix{ .none = true } }, - .@"border-bottom-color" => .{ "border-bottom-color", VendorPrefix{ .none = true } }, - .@"border-left-color" => .{ "border-left-color", VendorPrefix{ .none = true } }, - .@"border-right-color" => .{ "border-right-color", VendorPrefix{ .none = true } }, - .@"border-block-start-color" => .{ "border-block-start-color", VendorPrefix{ .none = true } }, - .@"border-block-end-color" => .{ "border-block-end-color", VendorPrefix{ .none = true } }, - .@"border-inline-start-color" => .{ "border-inline-start-color", VendorPrefix{ .none = true } }, - .@"border-inline-end-color" => .{ "border-inline-end-color", VendorPrefix{ .none = true } }, - .@"border-top-style" => .{ "border-top-style", VendorPrefix{ .none = true } }, - .@"border-bottom-style" => .{ "border-bottom-style", VendorPrefix{ .none = true } }, - .@"border-left-style" => .{ "border-left-style", VendorPrefix{ .none = true } }, - .@"border-right-style" => .{ "border-right-style", VendorPrefix{ .none = true } }, - .@"border-block-start-style" => .{ "border-block-start-style", VendorPrefix{ .none = true } }, - .@"border-block-end-style" => .{ "border-block-end-style", VendorPrefix{ .none = true } }, - .@"border-inline-start-style" => .{ "border-inline-start-style", VendorPrefix{ .none = true } }, - .@"border-inline-end-style" => .{ "border-inline-end-style", VendorPrefix{ .none = true } }, - .@"border-top-width" => .{ "border-top-width", VendorPrefix{ .none = true } }, - .@"border-bottom-width" => .{ "border-bottom-width", VendorPrefix{ .none = true } }, - .@"border-left-width" => .{ "border-left-width", VendorPrefix{ .none = true } }, - .@"border-right-width" => .{ "border-right-width", VendorPrefix{ .none = true } }, - .@"border-block-start-width" => .{ "border-block-start-width", VendorPrefix{ .none = true } }, - .@"border-block-end-width" => .{ "border-block-end-width", VendorPrefix{ .none = true } }, - .@"border-inline-start-width" => .{ "border-inline-start-width", VendorPrefix{ .none = true } }, - .@"border-inline-end-width" => .{ "border-inline-end-width", VendorPrefix{ .none = true } }, - .@"border-top-left-radius" => |*x| .{ "border-top-left-radius", x.@"1" }, - .@"border-top-right-radius" => |*x| .{ "border-top-right-radius", x.@"1" }, - .@"border-bottom-left-radius" => |*x| .{ "border-bottom-left-radius", x.@"1" }, - .@"border-bottom-right-radius" => |*x| .{ "border-bottom-right-radius", x.@"1" }, - .@"border-start-start-radius" => .{ "border-start-start-radius", VendorPrefix{ .none = true } }, - .@"border-start-end-radius" => .{ "border-start-end-radius", VendorPrefix{ .none = true } }, - .@"border-end-start-radius" => .{ "border-end-start-radius", VendorPrefix{ .none = true } }, - .@"border-end-end-radius" => .{ "border-end-end-radius", VendorPrefix{ .none = true } }, - .@"border-radius" => |*x| .{ "border-radius", x.@"1" }, - .@"border-image-source" => .{ "border-image-source", VendorPrefix{ .none = true } }, - .@"border-image-outset" => .{ "border-image-outset", VendorPrefix{ .none = true } }, - .@"border-image-repeat" => .{ "border-image-repeat", VendorPrefix{ .none = true } }, - .@"border-image-width" => .{ "border-image-width", VendorPrefix{ .none = true } }, - .@"border-image-slice" => .{ "border-image-slice", VendorPrefix{ .none = true } }, - .@"border-image" => |*x| .{ "border-image", x.@"1" }, - .@"border-color" => .{ "border-color", VendorPrefix{ .none = true } }, - .@"border-style" => .{ "border-style", VendorPrefix{ .none = true } }, - .@"border-width" => .{ "border-width", VendorPrefix{ .none = true } }, - .@"border-block-color" => .{ "border-block-color", VendorPrefix{ .none = true } }, - .@"border-block-style" => .{ "border-block-style", VendorPrefix{ .none = true } }, - .@"border-block-width" => .{ "border-block-width", VendorPrefix{ .none = true } }, - .@"border-inline-color" => .{ "border-inline-color", VendorPrefix{ .none = true } }, - .@"border-inline-style" => .{ "border-inline-style", VendorPrefix{ .none = true } }, - .@"border-inline-width" => .{ "border-inline-width", VendorPrefix{ .none = true } }, - .border => .{ "border", VendorPrefix{ .none = true } }, - .@"border-top" => .{ "border-top", VendorPrefix{ .none = true } }, - .@"border-bottom" => .{ "border-bottom", VendorPrefix{ .none = true } }, - .@"border-left" => .{ "border-left", VendorPrefix{ .none = true } }, - .@"border-right" => .{ "border-right", VendorPrefix{ .none = true } }, - .@"border-block" => .{ "border-block", VendorPrefix{ .none = true } }, - .@"border-block-start" => .{ "border-block-start", VendorPrefix{ .none = true } }, - .@"border-block-end" => .{ "border-block-end", VendorPrefix{ .none = true } }, - .@"border-inline" => .{ "border-inline", VendorPrefix{ .none = true } }, - .@"border-inline-start" => .{ "border-inline-start", VendorPrefix{ .none = true } }, - .@"border-inline-end" => .{ "border-inline-end", VendorPrefix{ .none = true } }, - .outline => .{ "outline", VendorPrefix{ .none = true } }, - .@"outline-color" => .{ "outline-color", VendorPrefix{ .none = true } }, - .@"outline-style" => .{ "outline-style", VendorPrefix{ .none = true } }, - .@"outline-width" => .{ "outline-width", VendorPrefix{ .none = true } }, - .@"flex-direction" => |*x| .{ "flex-direction", x.@"1" }, - .@"flex-wrap" => |*x| .{ "flex-wrap", x.@"1" }, - .@"flex-flow" => |*x| .{ "flex-flow", x.@"1" }, - .@"flex-grow" => |*x| .{ "flex-grow", x.@"1" }, - .@"flex-shrink" => |*x| .{ "flex-shrink", x.@"1" }, - .@"flex-basis" => |*x| .{ "flex-basis", x.@"1" }, - .flex => |*x| .{ "flex", x.@"1" }, - .order => |*x| .{ "order", x.@"1" }, - .@"align-content" => |*x| .{ "align-content", x.@"1" }, - .@"justify-content" => |*x| .{ "justify-content", x.@"1" }, - .@"place-content" => .{ "place-content", VendorPrefix{ .none = true } }, - .@"align-self" => |*x| .{ "align-self", x.@"1" }, - .@"justify-self" => .{ "justify-self", VendorPrefix{ .none = true } }, - .@"place-self" => .{ "place-self", VendorPrefix{ .none = true } }, - .@"align-items" => |*x| .{ "align-items", x.@"1" }, - .@"justify-items" => .{ "justify-items", VendorPrefix{ .none = true } }, - .@"place-items" => .{ "place-items", VendorPrefix{ .none = true } }, - .@"row-gap" => .{ "row-gap", VendorPrefix{ .none = true } }, - .@"column-gap" => .{ "column-gap", VendorPrefix{ .none = true } }, - .gap => .{ "gap", VendorPrefix{ .none = true } }, - .@"box-orient" => |*x| .{ "box-orient", x.@"1" }, - .@"box-direction" => |*x| .{ "box-direction", x.@"1" }, - .@"box-ordinal-group" => |*x| .{ "box-ordinal-group", x.@"1" }, - .@"box-align" => |*x| .{ "box-align", x.@"1" }, - .@"box-flex" => |*x| .{ "box-flex", x.@"1" }, - .@"box-flex-group" => |*x| .{ "box-flex-group", x.@"1" }, - .@"box-pack" => |*x| .{ "box-pack", x.@"1" }, - .@"box-lines" => |*x| .{ "box-lines", x.@"1" }, - .@"flex-pack" => |*x| .{ "flex-pack", x.@"1" }, - .@"flex-order" => |*x| .{ "flex-order", x.@"1" }, - .@"flex-align" => |*x| .{ "flex-align", x.@"1" }, - .@"flex-item-align" => |*x| .{ "flex-item-align", x.@"1" }, - .@"flex-line-pack" => |*x| .{ "flex-line-pack", x.@"1" }, - .@"flex-positive" => |*x| .{ "flex-positive", x.@"1" }, - .@"flex-negative" => |*x| .{ "flex-negative", x.@"1" }, - .@"flex-preferred-size" => |*x| .{ "flex-preferred-size", x.@"1" }, - .@"margin-top" => .{ "margin-top", VendorPrefix{ .none = true } }, - .@"margin-bottom" => .{ "margin-bottom", VendorPrefix{ .none = true } }, - .@"margin-left" => .{ "margin-left", VendorPrefix{ .none = true } }, - .@"margin-right" => .{ "margin-right", VendorPrefix{ .none = true } }, - .@"margin-block-start" => .{ "margin-block-start", VendorPrefix{ .none = true } }, - .@"margin-block-end" => .{ "margin-block-end", VendorPrefix{ .none = true } }, - .@"margin-inline-start" => .{ "margin-inline-start", VendorPrefix{ .none = true } }, - .@"margin-inline-end" => .{ "margin-inline-end", VendorPrefix{ .none = true } }, - .@"margin-block" => .{ "margin-block", VendorPrefix{ .none = true } }, - .@"margin-inline" => .{ "margin-inline", VendorPrefix{ .none = true } }, - .margin => .{ "margin", VendorPrefix{ .none = true } }, - .@"padding-top" => .{ "padding-top", VendorPrefix{ .none = true } }, - .@"padding-bottom" => .{ "padding-bottom", VendorPrefix{ .none = true } }, - .@"padding-left" => .{ "padding-left", VendorPrefix{ .none = true } }, - .@"padding-right" => .{ "padding-right", VendorPrefix{ .none = true } }, - .@"padding-block-start" => .{ "padding-block-start", VendorPrefix{ .none = true } }, - .@"padding-block-end" => .{ "padding-block-end", VendorPrefix{ .none = true } }, - .@"padding-inline-start" => .{ "padding-inline-start", VendorPrefix{ .none = true } }, - .@"padding-inline-end" => .{ "padding-inline-end", VendorPrefix{ .none = true } }, - .@"padding-block" => .{ "padding-block", VendorPrefix{ .none = true } }, - .@"padding-inline" => .{ "padding-inline", VendorPrefix{ .none = true } }, - .padding => .{ "padding", VendorPrefix{ .none = true } }, - .@"scroll-margin-top" => .{ "scroll-margin-top", VendorPrefix{ .none = true } }, - .@"scroll-margin-bottom" => .{ "scroll-margin-bottom", VendorPrefix{ .none = true } }, - .@"scroll-margin-left" => .{ "scroll-margin-left", VendorPrefix{ .none = true } }, - .@"scroll-margin-right" => .{ "scroll-margin-right", VendorPrefix{ .none = true } }, - .@"scroll-margin-block-start" => .{ "scroll-margin-block-start", VendorPrefix{ .none = true } }, - .@"scroll-margin-block-end" => .{ "scroll-margin-block-end", VendorPrefix{ .none = true } }, - .@"scroll-margin-inline-start" => .{ "scroll-margin-inline-start", VendorPrefix{ .none = true } }, - .@"scroll-margin-inline-end" => .{ "scroll-margin-inline-end", VendorPrefix{ .none = true } }, - .@"scroll-margin-block" => .{ "scroll-margin-block", VendorPrefix{ .none = true } }, - .@"scroll-margin-inline" => .{ "scroll-margin-inline", VendorPrefix{ .none = true } }, - .@"scroll-margin" => .{ "scroll-margin", VendorPrefix{ .none = true } }, - .@"scroll-padding-top" => .{ "scroll-padding-top", VendorPrefix{ .none = true } }, - .@"scroll-padding-bottom" => .{ "scroll-padding-bottom", VendorPrefix{ .none = true } }, - .@"scroll-padding-left" => .{ "scroll-padding-left", VendorPrefix{ .none = true } }, - .@"scroll-padding-right" => .{ "scroll-padding-right", VendorPrefix{ .none = true } }, - .@"scroll-padding-block-start" => .{ "scroll-padding-block-start", VendorPrefix{ .none = true } }, - .@"scroll-padding-block-end" => .{ "scroll-padding-block-end", VendorPrefix{ .none = true } }, - .@"scroll-padding-inline-start" => .{ "scroll-padding-inline-start", VendorPrefix{ .none = true } }, - .@"scroll-padding-inline-end" => .{ "scroll-padding-inline-end", VendorPrefix{ .none = true } }, - .@"scroll-padding-block" => .{ "scroll-padding-block", VendorPrefix{ .none = true } }, - .@"scroll-padding-inline" => .{ "scroll-padding-inline", VendorPrefix{ .none = true } }, - .@"scroll-padding" => .{ "scroll-padding", VendorPrefix{ .none = true } }, - .@"font-weight" => .{ "font-weight", VendorPrefix{ .none = true } }, - .@"font-size" => .{ "font-size", VendorPrefix{ .none = true } }, - .@"font-stretch" => .{ "font-stretch", VendorPrefix{ .none = true } }, - .@"font-family" => .{ "font-family", VendorPrefix{ .none = true } }, - .@"font-style" => .{ "font-style", VendorPrefix{ .none = true } }, - .@"font-variant-caps" => .{ "font-variant-caps", VendorPrefix{ .none = true } }, - .@"line-height" => .{ "line-height", VendorPrefix{ .none = true } }, - .font => .{ "font", VendorPrefix{ .none = true } }, - .@"transition-property" => |*x| .{ "transition-property", x.@"1" }, - .@"transition-duration" => |*x| .{ "transition-duration", x.@"1" }, - .@"transition-delay" => |*x| .{ "transition-delay", x.@"1" }, - .@"transition-timing-function" => |*x| .{ "transition-timing-function", x.@"1" }, - .transition => |*x| .{ "transition", x.@"1" }, - .transform => |*x| .{ "transform", x.@"1" }, - .@"transform-origin" => |*x| .{ "transform-origin", x.@"1" }, - .@"transform-style" => |*x| .{ "transform-style", x.@"1" }, - .@"transform-box" => .{ "transform-box", VendorPrefix{ .none = true } }, - .@"backface-visibility" => |*x| .{ "backface-visibility", x.@"1" }, - .perspective => |*x| .{ "perspective", x.@"1" }, - .@"perspective-origin" => |*x| .{ "perspective-origin", x.@"1" }, - .translate => .{ "translate", VendorPrefix{ .none = true } }, - .rotate => .{ "rotate", VendorPrefix{ .none = true } }, - .scale => .{ "scale", VendorPrefix{ .none = true } }, - .@"text-decoration-color" => |*x| .{ "text-decoration-color", x.@"1" }, - .@"text-emphasis-color" => |*x| .{ "text-emphasis-color", x.@"1" }, - .@"text-shadow" => .{ "text-shadow", VendorPrefix{ .none = true } }, - .direction => .{ "direction", VendorPrefix{ .none = true } }, - .composes => .{ "composes", VendorPrefix{ .none = true } }, - .@"mask-image" => |*x| .{ "mask-image", x.@"1" }, - .@"mask-mode" => .{ "mask-mode", VendorPrefix{ .none = true } }, - .@"mask-repeat" => |*x| .{ "mask-repeat", x.@"1" }, - .@"mask-position-x" => .{ "mask-position-x", VendorPrefix{ .none = true } }, - .@"mask-position-y" => .{ "mask-position-y", VendorPrefix{ .none = true } }, - .@"mask-position" => |*x| .{ "mask-position", x.@"1" }, - .@"mask-clip" => |*x| .{ "mask-clip", x.@"1" }, - .@"mask-origin" => |*x| .{ "mask-origin", x.@"1" }, - .@"mask-size" => |*x| .{ "mask-size", x.@"1" }, - .@"mask-composite" => .{ "mask-composite", VendorPrefix{ .none = true } }, - .@"mask-type" => .{ "mask-type", VendorPrefix{ .none = true } }, - .mask => |*x| .{ "mask", x.@"1" }, - .@"mask-border-source" => .{ "mask-border-source", VendorPrefix{ .none = true } }, - .@"mask-border-mode" => .{ "mask-border-mode", VendorPrefix{ .none = true } }, - .@"mask-border-slice" => .{ "mask-border-slice", VendorPrefix{ .none = true } }, - .@"mask-border-width" => .{ "mask-border-width", VendorPrefix{ .none = true } }, - .@"mask-border-outset" => .{ "mask-border-outset", VendorPrefix{ .none = true } }, - .@"mask-border-repeat" => .{ "mask-border-repeat", VendorPrefix{ .none = true } }, - .@"mask-border" => .{ "mask-border", VendorPrefix{ .none = true } }, - .@"-webkit-mask-composite" => .{ "-webkit-mask-composite", VendorPrefix{ .none = true } }, - .@"mask-source-type" => |*x| .{ "mask-source-type", x.@"1" }, - .@"mask-box-image" => |*x| .{ "mask-box-image", x.@"1" }, - .@"mask-box-image-source" => |*x| .{ "mask-box-image-source", x.@"1" }, - .@"mask-box-image-slice" => |*x| .{ "mask-box-image-slice", x.@"1" }, - .@"mask-box-image-width" => |*x| .{ "mask-box-image-width", x.@"1" }, - .@"mask-box-image-outset" => |*x| .{ "mask-box-image-outset", x.@"1" }, - .@"mask-box-image-repeat" => |*x| .{ "mask-box-image-repeat", x.@"1" }, - .@"color-scheme" => .{ "color-scheme", VendorPrefix{ .none = true } }, - .all => .{ "all", VendorPrefix{ .none = true } }, - .unparsed => |*unparsed| brk: { - var prefix = unparsed.property_id.prefix(); - if (prefix.isEmpty()) { - prefix = VendorPrefix{ .none = true }; - } - break :brk .{ unparsed.property_id.name(), prefix }; - }, - .custom => unreachable, - }; - } - - /// Serializes the value of a CSS property without its name or `!important` flag. - pub fn valueToCss(this: *const Property, dest: *css.Printer) PrintErr!void { - return switch (this.*) { - .@"background-color" => |*value| value.toCss(dest), - .@"background-image" => |*value| value.toCss(dest), - .@"background-position-x" => |*value| value.toCss(dest), - .@"background-position-y" => |*value| value.toCss(dest), - .@"background-position" => |*value| value.toCss(dest), - .@"background-size" => |*value| value.toCss(dest), - .@"background-repeat" => |*value| value.toCss(dest), - .@"background-attachment" => |*value| value.toCss(dest), - .@"background-clip" => |*value| value[0].toCss(dest), - .@"background-origin" => |*value| value.toCss(dest), - .background => |*value| value.toCss(dest), - .@"box-shadow" => |*value| value[0].toCss(dest), - .opacity => |*value| value.toCss(dest), - .color => |*value| value.toCss(dest), - .display => |*value| value.toCss(dest), - .visibility => |*value| value.toCss(dest), - .width => |*value| value.toCss(dest), - .height => |*value| value.toCss(dest), - .@"min-width" => |*value| value.toCss(dest), - .@"min-height" => |*value| value.toCss(dest), - .@"max-width" => |*value| value.toCss(dest), - .@"max-height" => |*value| value.toCss(dest), - .@"block-size" => |*value| value.toCss(dest), - .@"inline-size" => |*value| value.toCss(dest), - .@"min-block-size" => |*value| value.toCss(dest), - .@"min-inline-size" => |*value| value.toCss(dest), - .@"max-block-size" => |*value| value.toCss(dest), - .@"max-inline-size" => |*value| value.toCss(dest), - .@"box-sizing" => |*value| value[0].toCss(dest), - .@"aspect-ratio" => |*value| value.toCss(dest), - .overflow => |*value| value.toCss(dest), - .@"overflow-x" => |*value| value.toCss(dest), - .@"overflow-y" => |*value| value.toCss(dest), - .@"text-overflow" => |*value| value[0].toCss(dest), - .position => |*value| value.toCss(dest), - .top => |*value| value.toCss(dest), - .bottom => |*value| value.toCss(dest), - .left => |*value| value.toCss(dest), - .right => |*value| value.toCss(dest), - .@"inset-block-start" => |*value| value.toCss(dest), - .@"inset-block-end" => |*value| value.toCss(dest), - .@"inset-inline-start" => |*value| value.toCss(dest), - .@"inset-inline-end" => |*value| value.toCss(dest), - .@"inset-block" => |*value| value.toCss(dest), - .@"inset-inline" => |*value| value.toCss(dest), - .inset => |*value| value.toCss(dest), - .@"border-spacing" => |*value| value.toCss(dest), - .@"border-top-color" => |*value| value.toCss(dest), - .@"border-bottom-color" => |*value| value.toCss(dest), - .@"border-left-color" => |*value| value.toCss(dest), - .@"border-right-color" => |*value| value.toCss(dest), - .@"border-block-start-color" => |*value| value.toCss(dest), - .@"border-block-end-color" => |*value| value.toCss(dest), - .@"border-inline-start-color" => |*value| value.toCss(dest), - .@"border-inline-end-color" => |*value| value.toCss(dest), - .@"border-top-style" => |*value| value.toCss(dest), - .@"border-bottom-style" => |*value| value.toCss(dest), - .@"border-left-style" => |*value| value.toCss(dest), - .@"border-right-style" => |*value| value.toCss(dest), - .@"border-block-start-style" => |*value| value.toCss(dest), - .@"border-block-end-style" => |*value| value.toCss(dest), - .@"border-inline-start-style" => |*value| value.toCss(dest), - .@"border-inline-end-style" => |*value| value.toCss(dest), - .@"border-top-width" => |*value| value.toCss(dest), - .@"border-bottom-width" => |*value| value.toCss(dest), - .@"border-left-width" => |*value| value.toCss(dest), - .@"border-right-width" => |*value| value.toCss(dest), - .@"border-block-start-width" => |*value| value.toCss(dest), - .@"border-block-end-width" => |*value| value.toCss(dest), - .@"border-inline-start-width" => |*value| value.toCss(dest), - .@"border-inline-end-width" => |*value| value.toCss(dest), - .@"border-top-left-radius" => |*value| value[0].toCss(dest), - .@"border-top-right-radius" => |*value| value[0].toCss(dest), - .@"border-bottom-left-radius" => |*value| value[0].toCss(dest), - .@"border-bottom-right-radius" => |*value| value[0].toCss(dest), - .@"border-start-start-radius" => |*value| value.toCss(dest), - .@"border-start-end-radius" => |*value| value.toCss(dest), - .@"border-end-start-radius" => |*value| value.toCss(dest), - .@"border-end-end-radius" => |*value| value.toCss(dest), - .@"border-radius" => |*value| value[0].toCss(dest), - .@"border-image-source" => |*value| value.toCss(dest), - .@"border-image-outset" => |*value| value.toCss(dest), - .@"border-image-repeat" => |*value| value.toCss(dest), - .@"border-image-width" => |*value| value.toCss(dest), - .@"border-image-slice" => |*value| value.toCss(dest), - .@"border-image" => |*value| value[0].toCss(dest), - .@"border-color" => |*value| value.toCss(dest), - .@"border-style" => |*value| value.toCss(dest), - .@"border-width" => |*value| value.toCss(dest), - .@"border-block-color" => |*value| value.toCss(dest), - .@"border-block-style" => |*value| value.toCss(dest), - .@"border-block-width" => |*value| value.toCss(dest), - .@"border-inline-color" => |*value| value.toCss(dest), - .@"border-inline-style" => |*value| value.toCss(dest), - .@"border-inline-width" => |*value| value.toCss(dest), - .border => |*value| value.toCss(dest), - .@"border-top" => |*value| value.toCss(dest), - .@"border-bottom" => |*value| value.toCss(dest), - .@"border-left" => |*value| value.toCss(dest), - .@"border-right" => |*value| value.toCss(dest), - .@"border-block" => |*value| value.toCss(dest), - .@"border-block-start" => |*value| value.toCss(dest), - .@"border-block-end" => |*value| value.toCss(dest), - .@"border-inline" => |*value| value.toCss(dest), - .@"border-inline-start" => |*value| value.toCss(dest), - .@"border-inline-end" => |*value| value.toCss(dest), - .outline => |*value| value.toCss(dest), - .@"outline-color" => |*value| value.toCss(dest), - .@"outline-style" => |*value| value.toCss(dest), - .@"outline-width" => |*value| value.toCss(dest), - .@"flex-direction" => |*value| value[0].toCss(dest), - .@"flex-wrap" => |*value| value[0].toCss(dest), - .@"flex-flow" => |*value| value[0].toCss(dest), - .@"flex-grow" => |*value| CSSNumberFns.toCss(&value[0], dest), - .@"flex-shrink" => |*value| CSSNumberFns.toCss(&value[0], dest), - .@"flex-basis" => |*value| value[0].toCss(dest), - .flex => |*value| value[0].toCss(dest), - .order => |*value| CSSIntegerFns.toCss(&value[0], dest), - .@"align-content" => |*value| value[0].toCss(dest), - .@"justify-content" => |*value| value[0].toCss(dest), - .@"place-content" => |*value| value.toCss(dest), - .@"align-self" => |*value| value[0].toCss(dest), - .@"justify-self" => |*value| value.toCss(dest), - .@"place-self" => |*value| value.toCss(dest), - .@"align-items" => |*value| value[0].toCss(dest), - .@"justify-items" => |*value| value.toCss(dest), - .@"place-items" => |*value| value.toCss(dest), - .@"row-gap" => |*value| value.toCss(dest), - .@"column-gap" => |*value| value.toCss(dest), - .gap => |*value| value.toCss(dest), - .@"box-orient" => |*value| value[0].toCss(dest), - .@"box-direction" => |*value| value[0].toCss(dest), - .@"box-ordinal-group" => |*value| CSSIntegerFns.toCss(&value[0], dest), - .@"box-align" => |*value| value[0].toCss(dest), - .@"box-flex" => |*value| CSSNumberFns.toCss(&value[0], dest), - .@"box-flex-group" => |*value| CSSIntegerFns.toCss(&value[0], dest), - .@"box-pack" => |*value| value[0].toCss(dest), - .@"box-lines" => |*value| value[0].toCss(dest), - .@"flex-pack" => |*value| value[0].toCss(dest), - .@"flex-order" => |*value| CSSIntegerFns.toCss(&value[0], dest), - .@"flex-align" => |*value| value[0].toCss(dest), - .@"flex-item-align" => |*value| value[0].toCss(dest), - .@"flex-line-pack" => |*value| value[0].toCss(dest), - .@"flex-positive" => |*value| CSSNumberFns.toCss(&value[0], dest), - .@"flex-negative" => |*value| CSSNumberFns.toCss(&value[0], dest), - .@"flex-preferred-size" => |*value| value[0].toCss(dest), - .@"margin-top" => |*value| value.toCss(dest), - .@"margin-bottom" => |*value| value.toCss(dest), - .@"margin-left" => |*value| value.toCss(dest), - .@"margin-right" => |*value| value.toCss(dest), - .@"margin-block-start" => |*value| value.toCss(dest), - .@"margin-block-end" => |*value| value.toCss(dest), - .@"margin-inline-start" => |*value| value.toCss(dest), - .@"margin-inline-end" => |*value| value.toCss(dest), - .@"margin-block" => |*value| value.toCss(dest), - .@"margin-inline" => |*value| value.toCss(dest), - .margin => |*value| value.toCss(dest), - .@"padding-top" => |*value| value.toCss(dest), - .@"padding-bottom" => |*value| value.toCss(dest), - .@"padding-left" => |*value| value.toCss(dest), - .@"padding-right" => |*value| value.toCss(dest), - .@"padding-block-start" => |*value| value.toCss(dest), - .@"padding-block-end" => |*value| value.toCss(dest), - .@"padding-inline-start" => |*value| value.toCss(dest), - .@"padding-inline-end" => |*value| value.toCss(dest), - .@"padding-block" => |*value| value.toCss(dest), - .@"padding-inline" => |*value| value.toCss(dest), - .padding => |*value| value.toCss(dest), - .@"scroll-margin-top" => |*value| value.toCss(dest), - .@"scroll-margin-bottom" => |*value| value.toCss(dest), - .@"scroll-margin-left" => |*value| value.toCss(dest), - .@"scroll-margin-right" => |*value| value.toCss(dest), - .@"scroll-margin-block-start" => |*value| value.toCss(dest), - .@"scroll-margin-block-end" => |*value| value.toCss(dest), - .@"scroll-margin-inline-start" => |*value| value.toCss(dest), - .@"scroll-margin-inline-end" => |*value| value.toCss(dest), - .@"scroll-margin-block" => |*value| value.toCss(dest), - .@"scroll-margin-inline" => |*value| value.toCss(dest), - .@"scroll-margin" => |*value| value.toCss(dest), - .@"scroll-padding-top" => |*value| value.toCss(dest), - .@"scroll-padding-bottom" => |*value| value.toCss(dest), - .@"scroll-padding-left" => |*value| value.toCss(dest), - .@"scroll-padding-right" => |*value| value.toCss(dest), - .@"scroll-padding-block-start" => |*value| value.toCss(dest), - .@"scroll-padding-block-end" => |*value| value.toCss(dest), - .@"scroll-padding-inline-start" => |*value| value.toCss(dest), - .@"scroll-padding-inline-end" => |*value| value.toCss(dest), - .@"scroll-padding-block" => |*value| value.toCss(dest), - .@"scroll-padding-inline" => |*value| value.toCss(dest), - .@"scroll-padding" => |*value| value.toCss(dest), - .@"font-weight" => |*value| value.toCss(dest), - .@"font-size" => |*value| value.toCss(dest), - .@"font-stretch" => |*value| value.toCss(dest), - .@"font-family" => |*value| value.toCss(dest), - .@"font-style" => |*value| value.toCss(dest), - .@"font-variant-caps" => |*value| value.toCss(dest), - .@"line-height" => |*value| value.toCss(dest), - .font => |*value| value.toCss(dest), - .@"transition-property" => |*value| value[0].toCss(dest), - .@"transition-duration" => |*value| value[0].toCss(dest), - .@"transition-delay" => |*value| value[0].toCss(dest), - .@"transition-timing-function" => |*value| value[0].toCss(dest), - .transition => |*value| value[0].toCss(dest), - .transform => |*value| value[0].toCss(dest), - .@"transform-origin" => |*value| value[0].toCss(dest), - .@"transform-style" => |*value| value[0].toCss(dest), - .@"transform-box" => |*value| value.toCss(dest), - .@"backface-visibility" => |*value| value[0].toCss(dest), - .perspective => |*value| value[0].toCss(dest), - .@"perspective-origin" => |*value| value[0].toCss(dest), - .translate => |*value| value.toCss(dest), - .rotate => |*value| value.toCss(dest), - .scale => |*value| value.toCss(dest), - .@"text-decoration-color" => |*value| value[0].toCss(dest), - .@"text-emphasis-color" => |*value| value[0].toCss(dest), - .@"text-shadow" => |*value| value.toCss(dest), - .direction => |*value| value.toCss(dest), - .composes => |*value| value.toCss(dest), - .@"mask-image" => |*value| value[0].toCss(dest), - .@"mask-mode" => |*value| value.toCss(dest), - .@"mask-repeat" => |*value| value[0].toCss(dest), - .@"mask-position-x" => |*value| value.toCss(dest), - .@"mask-position-y" => |*value| value.toCss(dest), - .@"mask-position" => |*value| value[0].toCss(dest), - .@"mask-clip" => |*value| value[0].toCss(dest), - .@"mask-origin" => |*value| value[0].toCss(dest), - .@"mask-size" => |*value| value[0].toCss(dest), - .@"mask-composite" => |*value| value.toCss(dest), - .@"mask-type" => |*value| value.toCss(dest), - .mask => |*value| value[0].toCss(dest), - .@"mask-border-source" => |*value| value.toCss(dest), - .@"mask-border-mode" => |*value| value.toCss(dest), - .@"mask-border-slice" => |*value| value.toCss(dest), - .@"mask-border-width" => |*value| value.toCss(dest), - .@"mask-border-outset" => |*value| value.toCss(dest), - .@"mask-border-repeat" => |*value| value.toCss(dest), - .@"mask-border" => |*value| value.toCss(dest), - .@"-webkit-mask-composite" => |*value| value.toCss(dest), - .@"mask-source-type" => |*value| value[0].toCss(dest), - .@"mask-box-image" => |*value| value[0].toCss(dest), - .@"mask-box-image-source" => |*value| value[0].toCss(dest), - .@"mask-box-image-slice" => |*value| value[0].toCss(dest), - .@"mask-box-image-width" => |*value| value[0].toCss(dest), - .@"mask-box-image-outset" => |*value| value[0].toCss(dest), - .@"mask-box-image-repeat" => |*value| value[0].toCss(dest), - .@"color-scheme" => |*value| value.toCss(dest), - .all => |*keyword| keyword.toCss(dest), - .unparsed => |*unparsed| unparsed.value.toCss(dest, false), - .custom => |*c| c.value.toCss(dest, c.name == .custom), - }; - } - - /// Returns the given longhand property for a shorthand. - pub fn longhand(this: *const Property, property_id: *const PropertyId) ?Property { - switch (this.*) { - .@"background-position" => |*v| return v.longhand(property_id), - .overflow => |*v| return v.longhand(property_id), - .@"inset-block" => |*v| return v.longhand(property_id), - .@"inset-inline" => |*v| return v.longhand(property_id), - .inset => |*v| return v.longhand(property_id), - .@"border-radius" => |*v| { - if (!(v[1] == property_id.prefix())) return null; - return v[0].longhand(property_id); - }, - .@"border-image" => |*v| { - if (!(v[1] == property_id.prefix())) return null; - return v[0].longhand(property_id); - }, - .@"border-color" => |*v| return v.longhand(property_id), - .@"border-style" => |*v| return v.longhand(property_id), - .@"border-width" => |*v| return v.longhand(property_id), - .@"border-block-color" => |*v| return v.longhand(property_id), - .@"border-block-style" => |*v| return v.longhand(property_id), - .@"border-block-width" => |*v| return v.longhand(property_id), - .@"border-inline-color" => |*v| return v.longhand(property_id), - .@"border-inline-style" => |*v| return v.longhand(property_id), - .@"border-inline-width" => |*v| return v.longhand(property_id), - .border => |*v| return v.longhand(property_id), - .@"border-top" => |*v| return v.longhand(property_id), - .@"border-bottom" => |*v| return v.longhand(property_id), - .@"border-left" => |*v| return v.longhand(property_id), - .@"border-right" => |*v| return v.longhand(property_id), - .@"border-block" => |*v| return v.longhand(property_id), - .@"border-block-start" => |*v| return v.longhand(property_id), - .@"border-block-end" => |*v| return v.longhand(property_id), - .@"border-inline" => |*v| return v.longhand(property_id), - .@"border-inline-start" => |*v| return v.longhand(property_id), - .@"border-inline-end" => |*v| return v.longhand(property_id), - .outline => |*v| return v.longhand(property_id), - .@"flex-flow" => |*v| { - if (!(v[1] == property_id.prefix())) return null; - return v[0].longhand(property_id); - }, - .flex => |*v| { - if (!(v[1] == property_id.prefix())) return null; - return v[0].longhand(property_id); - }, - .@"place-content" => |*v| return v.longhand(property_id), - .@"place-self" => |*v| return v.longhand(property_id), - .@"place-items" => |*v| return v.longhand(property_id), - .gap => |*v| return v.longhand(property_id), - .@"margin-block" => |*v| return v.longhand(property_id), - .@"margin-inline" => |*v| return v.longhand(property_id), - .margin => |*v| return v.longhand(property_id), - .@"padding-block" => |*v| return v.longhand(property_id), - .@"padding-inline" => |*v| return v.longhand(property_id), - .padding => |*v| return v.longhand(property_id), - .@"scroll-margin-block" => |*v| return v.longhand(property_id), - .@"scroll-margin-inline" => |*v| return v.longhand(property_id), - .@"scroll-margin" => |*v| return v.longhand(property_id), - .@"scroll-padding-block" => |*v| return v.longhand(property_id), - .@"scroll-padding-inline" => |*v| return v.longhand(property_id), - .@"scroll-padding" => |*v| return v.longhand(property_id), - .font => |*v| return v.longhand(property_id), - .transition => |*v| { - if (!(v[1] == property_id.prefix())) return null; - return v[0].longhand(property_id); - }, - .mask => |*v| { - if (!(v[1] == property_id.prefix())) return null; - return v[0].longhand(property_id); - }, - .@"mask-border" => |*v| return v.longhand(property_id), - else => {}, - } - return null; - } - - pub fn eql(lhs: *const Property, rhs: *const Property) bool { - if (@intFromEnum(lhs.*) != @intFromEnum(rhs.*)) return false; - return switch (lhs.*) { - .@"background-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"background-color"), - .@"background-image" => |*v| css.generic.eql(SmallList(Image, 1), v, &rhs.@"background-image"), - .@"background-position-x" => |*v| css.generic.eql(SmallList(css_values.position.HorizontalPosition, 1), v, &rhs.@"background-position-x"), - .@"background-position-y" => |*v| css.generic.eql(SmallList(css_values.position.VerticalPosition, 1), v, &rhs.@"background-position-y"), - .@"background-position" => |*v| css.generic.eql(SmallList(background.BackgroundPosition, 1), v, &rhs.@"background-position"), - .@"background-size" => |*v| css.generic.eql(SmallList(background.BackgroundSize, 1), v, &rhs.@"background-size"), - .@"background-repeat" => |*v| css.generic.eql(SmallList(background.BackgroundRepeat, 1), v, &rhs.@"background-repeat"), - .@"background-attachment" => |*v| css.generic.eql(SmallList(background.BackgroundAttachment, 1), v, &rhs.@"background-attachment"), - .@"background-clip" => |*v| css.generic.eql(SmallList(background.BackgroundClip, 1), &v[0], &rhs.@"background-clip"[0]) and v[1] == rhs.@"background-clip"[1], - .@"background-origin" => |*v| css.generic.eql(SmallList(background.BackgroundOrigin, 1), v, &rhs.@"background-origin"), - .background => |*v| css.generic.eql(SmallList(background.Background, 1), v, &rhs.background), - .@"box-shadow" => |*v| css.generic.eql(SmallList(box_shadow.BoxShadow, 1), &v[0], &rhs.@"box-shadow"[0]) and v[1] == rhs.@"box-shadow"[1], - .opacity => |*v| css.generic.eql(css.css_values.alpha.AlphaValue, v, &rhs.opacity), - .color => |*v| css.generic.eql(CssColor, v, &rhs.color), - .display => |*v| css.generic.eql(display.Display, v, &rhs.display), - .visibility => |*v| css.generic.eql(display.Visibility, v, &rhs.visibility), - .width => |*v| css.generic.eql(size.Size, v, &rhs.width), - .height => |*v| css.generic.eql(size.Size, v, &rhs.height), - .@"min-width" => |*v| css.generic.eql(size.Size, v, &rhs.@"min-width"), - .@"min-height" => |*v| css.generic.eql(size.Size, v, &rhs.@"min-height"), - .@"max-width" => |*v| css.generic.eql(size.MaxSize, v, &rhs.@"max-width"), - .@"max-height" => |*v| css.generic.eql(size.MaxSize, v, &rhs.@"max-height"), - .@"block-size" => |*v| css.generic.eql(size.Size, v, &rhs.@"block-size"), - .@"inline-size" => |*v| css.generic.eql(size.Size, v, &rhs.@"inline-size"), - .@"min-block-size" => |*v| css.generic.eql(size.Size, v, &rhs.@"min-block-size"), - .@"min-inline-size" => |*v| css.generic.eql(size.Size, v, &rhs.@"min-inline-size"), - .@"max-block-size" => |*v| css.generic.eql(size.MaxSize, v, &rhs.@"max-block-size"), - .@"max-inline-size" => |*v| css.generic.eql(size.MaxSize, v, &rhs.@"max-inline-size"), - .@"box-sizing" => |*v| css.generic.eql(size.BoxSizing, &v[0], &rhs.@"box-sizing"[0]) and v[1] == rhs.@"box-sizing"[1], - .@"aspect-ratio" => |*v| css.generic.eql(size.AspectRatio, v, &rhs.@"aspect-ratio"), - .overflow => |*v| css.generic.eql(overflow.Overflow, v, &rhs.overflow), - .@"overflow-x" => |*v| css.generic.eql(overflow.OverflowKeyword, v, &rhs.@"overflow-x"), - .@"overflow-y" => |*v| css.generic.eql(overflow.OverflowKeyword, v, &rhs.@"overflow-y"), - .@"text-overflow" => |*v| css.generic.eql(overflow.TextOverflow, &v[0], &rhs.@"text-overflow"[0]) and v[1] == rhs.@"text-overflow"[1], - .position => |*v| css.generic.eql(position.Position, v, &rhs.position), - .top => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.top), - .bottom => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.bottom), - .left => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.left), - .right => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.right), - .@"inset-block-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"inset-block-start"), - .@"inset-block-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"inset-block-end"), - .@"inset-inline-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"inset-inline-start"), - .@"inset-inline-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"inset-inline-end"), - .@"inset-block" => |*v| css.generic.eql(margin_padding.InsetBlock, v, &rhs.@"inset-block"), - .@"inset-inline" => |*v| css.generic.eql(margin_padding.InsetInline, v, &rhs.@"inset-inline"), - .inset => |*v| css.generic.eql(margin_padding.Inset, v, &rhs.inset), - .@"border-spacing" => |*v| css.generic.eql(css.css_values.size.Size2D(Length), v, &rhs.@"border-spacing"), - .@"border-top-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-top-color"), - .@"border-bottom-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-bottom-color"), - .@"border-left-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-left-color"), - .@"border-right-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-right-color"), - .@"border-block-start-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-block-start-color"), - .@"border-block-end-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-block-end-color"), - .@"border-inline-start-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-inline-start-color"), - .@"border-inline-end-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"border-inline-end-color"), - .@"border-top-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-top-style"), - .@"border-bottom-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-bottom-style"), - .@"border-left-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-left-style"), - .@"border-right-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-right-style"), - .@"border-block-start-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-block-start-style"), - .@"border-block-end-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-block-end-style"), - .@"border-inline-start-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-inline-start-style"), - .@"border-inline-end-style" => |*v| css.generic.eql(border.LineStyle, v, &rhs.@"border-inline-end-style"), - .@"border-top-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-top-width"), - .@"border-bottom-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-bottom-width"), - .@"border-left-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-left-width"), - .@"border-right-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-right-width"), - .@"border-block-start-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-block-start-width"), - .@"border-block-end-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-block-end-width"), - .@"border-inline-start-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-inline-start-width"), - .@"border-inline-end-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"border-inline-end-width"), - .@"border-top-left-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-top-left-radius"[0]) and (v[1] == rhs.@"border-top-left-radius"[1]), - .@"border-top-right-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-top-right-radius"[0]) and (v[1] == rhs.@"border-top-right-radius"[1]), - .@"border-bottom-left-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-bottom-left-radius"[0]) and (v[1] == rhs.@"border-bottom-left-radius"[1]), - .@"border-bottom-right-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), &v[0], &rhs.@"border-bottom-right-radius"[0]) and (v[1] == rhs.@"border-bottom-right-radius"[1]), - .@"border-start-start-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-start-start-radius"), - .@"border-start-end-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-start-end-radius"), - .@"border-end-start-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-end-start-radius"), - .@"border-end-end-radius" => |*v| css.generic.eql(Size2D(LengthPercentage), v, &rhs.@"border-end-end-radius"), - .@"border-radius" => |*v| css.generic.eql(BorderRadius, &v[0], &rhs.@"border-radius"[0]) and (v[1] == rhs.@"border-radius"[1]), - .@"border-image-source" => |*v| css.generic.eql(Image, v, &rhs.@"border-image-source"), - .@"border-image-outset" => |*v| css.generic.eql(Rect(LengthOrNumber), v, &rhs.@"border-image-outset"), - .@"border-image-repeat" => |*v| css.generic.eql(BorderImageRepeat, v, &rhs.@"border-image-repeat"), - .@"border-image-width" => |*v| css.generic.eql(Rect(BorderImageSideWidth), v, &rhs.@"border-image-width"), - .@"border-image-slice" => |*v| css.generic.eql(BorderImageSlice, v, &rhs.@"border-image-slice"), - .@"border-image" => |*v| css.generic.eql(BorderImage, &v[0], &rhs.@"border-image"[0]) and (v[1] == rhs.@"border-image"[1]), - .@"border-color" => |*v| css.generic.eql(BorderColor, v, &rhs.@"border-color"), - .@"border-style" => |*v| css.generic.eql(BorderStyle, v, &rhs.@"border-style"), - .@"border-width" => |*v| css.generic.eql(BorderWidth, v, &rhs.@"border-width"), - .@"border-block-color" => |*v| css.generic.eql(BorderBlockColor, v, &rhs.@"border-block-color"), - .@"border-block-style" => |*v| css.generic.eql(BorderBlockStyle, v, &rhs.@"border-block-style"), - .@"border-block-width" => |*v| css.generic.eql(BorderBlockWidth, v, &rhs.@"border-block-width"), - .@"border-inline-color" => |*v| css.generic.eql(BorderInlineColor, v, &rhs.@"border-inline-color"), - .@"border-inline-style" => |*v| css.generic.eql(BorderInlineStyle, v, &rhs.@"border-inline-style"), - .@"border-inline-width" => |*v| css.generic.eql(BorderInlineWidth, v, &rhs.@"border-inline-width"), - .border => |*v| css.generic.eql(Border, v, &rhs.border), - .@"border-top" => |*v| css.generic.eql(BorderTop, v, &rhs.@"border-top"), - .@"border-bottom" => |*v| css.generic.eql(BorderBottom, v, &rhs.@"border-bottom"), - .@"border-left" => |*v| css.generic.eql(BorderLeft, v, &rhs.@"border-left"), - .@"border-right" => |*v| css.generic.eql(BorderRight, v, &rhs.@"border-right"), - .@"border-block" => |*v| css.generic.eql(BorderBlock, v, &rhs.@"border-block"), - .@"border-block-start" => |*v| css.generic.eql(BorderBlockStart, v, &rhs.@"border-block-start"), - .@"border-block-end" => |*v| css.generic.eql(BorderBlockEnd, v, &rhs.@"border-block-end"), - .@"border-inline" => |*v| css.generic.eql(BorderInline, v, &rhs.@"border-inline"), - .@"border-inline-start" => |*v| css.generic.eql(BorderInlineStart, v, &rhs.@"border-inline-start"), - .@"border-inline-end" => |*v| css.generic.eql(BorderInlineEnd, v, &rhs.@"border-inline-end"), - .outline => |*v| css.generic.eql(Outline, v, &rhs.outline), - .@"outline-color" => |*v| css.generic.eql(CssColor, v, &rhs.@"outline-color"), - .@"outline-style" => |*v| css.generic.eql(OutlineStyle, v, &rhs.@"outline-style"), - .@"outline-width" => |*v| css.generic.eql(BorderSideWidth, v, &rhs.@"outline-width"), - .@"flex-direction" => |*v| css.generic.eql(FlexDirection, &v[0], &rhs.@"flex-direction"[0]) and (v[1] == rhs.@"flex-direction"[1]), - .@"flex-wrap" => |*v| css.generic.eql(FlexWrap, &v[0], &rhs.@"flex-wrap"[0]) and (v[1] == rhs.@"flex-wrap"[1]), - .@"flex-flow" => |*v| css.generic.eql(FlexFlow, &v[0], &rhs.@"flex-flow"[0]) and (v[1] == rhs.@"flex-flow"[1]), - .@"flex-grow" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-grow"[0]) and (v[1] == rhs.@"flex-grow"[1]), - .@"flex-shrink" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-shrink"[0]) and (v[1] == rhs.@"flex-shrink"[1]), - .@"flex-basis" => |*v| css.generic.eql(LengthPercentageOrAuto, &v[0], &rhs.@"flex-basis"[0]) and (v[1] == rhs.@"flex-basis"[1]), - .flex => |*v| css.generic.eql(Flex, &v[0], &rhs.flex[0]) and (v[1] == rhs.flex[1]), - .order => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.order[0]) and (v[1] == rhs.order[1]), - .@"align-content" => |*v| css.generic.eql(AlignContent, &v[0], &rhs.@"align-content"[0]) and (v[1] == rhs.@"align-content"[1]), - .@"justify-content" => |*v| css.generic.eql(JustifyContent, &v[0], &rhs.@"justify-content"[0]) and (v[1] == rhs.@"justify-content"[1]), - .@"place-content" => |*v| css.generic.eql(PlaceContent, v, &rhs.@"place-content"), - .@"align-self" => |*v| css.generic.eql(AlignSelf, &v[0], &rhs.@"align-self"[0]) and (v[1] == rhs.@"align-self"[1]), - .@"justify-self" => |*v| css.generic.eql(JustifySelf, v, &rhs.@"justify-self"), - .@"place-self" => |*v| css.generic.eql(PlaceSelf, v, &rhs.@"place-self"), - .@"align-items" => |*v| css.generic.eql(AlignItems, &v[0], &rhs.@"align-items"[0]) and (v[1] == rhs.@"align-items"[1]), - .@"justify-items" => |*v| css.generic.eql(JustifyItems, v, &rhs.@"justify-items"), - .@"place-items" => |*v| css.generic.eql(PlaceItems, v, &rhs.@"place-items"), - .@"row-gap" => |*v| css.generic.eql(GapValue, v, &rhs.@"row-gap"), - .@"column-gap" => |*v| css.generic.eql(GapValue, v, &rhs.@"column-gap"), - .gap => |*v| css.generic.eql(Gap, v, &rhs.gap), - .@"box-orient" => |*v| css.generic.eql(BoxOrient, &v[0], &rhs.@"box-orient"[0]) and (v[1] == rhs.@"box-orient"[1]), - .@"box-direction" => |*v| css.generic.eql(BoxDirection, &v[0], &rhs.@"box-direction"[0]) and (v[1] == rhs.@"box-direction"[1]), - .@"box-ordinal-group" => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.@"box-ordinal-group"[0]) and (v[1] == rhs.@"box-ordinal-group"[1]), - .@"box-align" => |*v| css.generic.eql(BoxAlign, &v[0], &rhs.@"box-align"[0]) and (v[1] == rhs.@"box-align"[1]), - .@"box-flex" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"box-flex"[0]) and (v[1] == rhs.@"box-flex"[1]), - .@"box-flex-group" => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.@"box-flex-group"[0]) and (v[1] == rhs.@"box-flex-group"[1]), - .@"box-pack" => |*v| css.generic.eql(BoxPack, &v[0], &rhs.@"box-pack"[0]) and (v[1] == rhs.@"box-pack"[1]), - .@"box-lines" => |*v| css.generic.eql(BoxLines, &v[0], &rhs.@"box-lines"[0]) and (v[1] == rhs.@"box-lines"[1]), - .@"flex-pack" => |*v| css.generic.eql(FlexPack, &v[0], &rhs.@"flex-pack"[0]) and (v[1] == rhs.@"flex-pack"[1]), - .@"flex-order" => |*v| css.generic.eql(CSSInteger, &v[0], &rhs.@"flex-order"[0]) and (v[1] == rhs.@"flex-order"[1]), - .@"flex-align" => |*v| css.generic.eql(BoxAlign, &v[0], &rhs.@"flex-align"[0]) and (v[1] == rhs.@"flex-align"[1]), - .@"flex-item-align" => |*v| css.generic.eql(FlexItemAlign, &v[0], &rhs.@"flex-item-align"[0]) and (v[1] == rhs.@"flex-item-align"[1]), - .@"flex-line-pack" => |*v| css.generic.eql(FlexLinePack, &v[0], &rhs.@"flex-line-pack"[0]) and (v[1] == rhs.@"flex-line-pack"[1]), - .@"flex-positive" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-positive"[0]) and (v[1] == rhs.@"flex-positive"[1]), - .@"flex-negative" => |*v| css.generic.eql(CSSNumber, &v[0], &rhs.@"flex-negative"[0]) and (v[1] == rhs.@"flex-negative"[1]), - .@"flex-preferred-size" => |*v| css.generic.eql(LengthPercentageOrAuto, &v[0], &rhs.@"flex-preferred-size"[0]) and (v[1] == rhs.@"flex-preferred-size"[1]), - .@"margin-top" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-top"), - .@"margin-bottom" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-bottom"), - .@"margin-left" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-left"), - .@"margin-right" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-right"), - .@"margin-block-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-block-start"), - .@"margin-block-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-block-end"), - .@"margin-inline-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-inline-start"), - .@"margin-inline-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"margin-inline-end"), - .@"margin-block" => |*v| css.generic.eql(MarginBlock, v, &rhs.@"margin-block"), - .@"margin-inline" => |*v| css.generic.eql(MarginInline, v, &rhs.@"margin-inline"), - .margin => |*v| css.generic.eql(Margin, v, &rhs.margin), - .@"padding-top" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-top"), - .@"padding-bottom" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-bottom"), - .@"padding-left" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-left"), - .@"padding-right" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-right"), - .@"padding-block-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-block-start"), - .@"padding-block-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-block-end"), - .@"padding-inline-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-inline-start"), - .@"padding-inline-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"padding-inline-end"), - .@"padding-block" => |*v| css.generic.eql(PaddingBlock, v, &rhs.@"padding-block"), - .@"padding-inline" => |*v| css.generic.eql(PaddingInline, v, &rhs.@"padding-inline"), - .padding => |*v| css.generic.eql(Padding, v, &rhs.padding), - .@"scroll-margin-top" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-top"), - .@"scroll-margin-bottom" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-bottom"), - .@"scroll-margin-left" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-left"), - .@"scroll-margin-right" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-right"), - .@"scroll-margin-block-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-block-start"), - .@"scroll-margin-block-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-block-end"), - .@"scroll-margin-inline-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-inline-start"), - .@"scroll-margin-inline-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-margin-inline-end"), - .@"scroll-margin-block" => |*v| css.generic.eql(ScrollMarginBlock, v, &rhs.@"scroll-margin-block"), - .@"scroll-margin-inline" => |*v| css.generic.eql(ScrollMarginInline, v, &rhs.@"scroll-margin-inline"), - .@"scroll-margin" => |*v| css.generic.eql(ScrollMargin, v, &rhs.@"scroll-margin"), - .@"scroll-padding-top" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-top"), - .@"scroll-padding-bottom" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-bottom"), - .@"scroll-padding-left" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-left"), - .@"scroll-padding-right" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-right"), - .@"scroll-padding-block-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-block-start"), - .@"scroll-padding-block-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-block-end"), - .@"scroll-padding-inline-start" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-inline-start"), - .@"scroll-padding-inline-end" => |*v| css.generic.eql(LengthPercentageOrAuto, v, &rhs.@"scroll-padding-inline-end"), - .@"scroll-padding-block" => |*v| css.generic.eql(ScrollPaddingBlock, v, &rhs.@"scroll-padding-block"), - .@"scroll-padding-inline" => |*v| css.generic.eql(ScrollPaddingInline, v, &rhs.@"scroll-padding-inline"), - .@"scroll-padding" => |*v| css.generic.eql(ScrollPadding, v, &rhs.@"scroll-padding"), - .@"font-weight" => |*v| css.generic.eql(FontWeight, v, &rhs.@"font-weight"), - .@"font-size" => |*v| css.generic.eql(FontSize, v, &rhs.@"font-size"), - .@"font-stretch" => |*v| css.generic.eql(FontStretch, v, &rhs.@"font-stretch"), - .@"font-family" => |*v| css.generic.eql(BabyList(FontFamily), v, &rhs.@"font-family"), - .@"font-style" => |*v| css.generic.eql(FontStyle, v, &rhs.@"font-style"), - .@"font-variant-caps" => |*v| css.generic.eql(FontVariantCaps, v, &rhs.@"font-variant-caps"), - .@"line-height" => |*v| css.generic.eql(LineHeight, v, &rhs.@"line-height"), - .font => |*v| css.generic.eql(Font, v, &rhs.font), - .@"transition-property" => |*v| css.generic.eql(SmallList(PropertyId, 1), &v[0], &rhs.@"transition-property"[0]) and (v[1] == rhs.@"transition-property"[1]), - .@"transition-duration" => |*v| css.generic.eql(SmallList(Time, 1), &v[0], &rhs.@"transition-duration"[0]) and (v[1] == rhs.@"transition-duration"[1]), - .@"transition-delay" => |*v| css.generic.eql(SmallList(Time, 1), &v[0], &rhs.@"transition-delay"[0]) and (v[1] == rhs.@"transition-delay"[1]), - .@"transition-timing-function" => |*v| css.generic.eql(SmallList(EasingFunction, 1), &v[0], &rhs.@"transition-timing-function"[0]) and (v[1] == rhs.@"transition-timing-function"[1]), - .transition => |*v| css.generic.eql(SmallList(Transition, 1), &v[0], &rhs.transition[0]) and (v[1] == rhs.transition[1]), - .transform => |*v| css.generic.eql(TransformList, &v[0], &rhs.transform[0]) and (v[1] == rhs.transform[1]), - .@"transform-origin" => |*v| css.generic.eql(Position, &v[0], &rhs.@"transform-origin"[0]) and (v[1] == rhs.@"transform-origin"[1]), - .@"transform-style" => |*v| css.generic.eql(TransformStyle, &v[0], &rhs.@"transform-style"[0]) and (v[1] == rhs.@"transform-style"[1]), - .@"transform-box" => |*v| css.generic.eql(TransformBox, v, &rhs.@"transform-box"), - .@"backface-visibility" => |*v| css.generic.eql(BackfaceVisibility, &v[0], &rhs.@"backface-visibility"[0]) and (v[1] == rhs.@"backface-visibility"[1]), - .perspective => |*v| css.generic.eql(Perspective, &v[0], &rhs.perspective[0]) and (v[1] == rhs.perspective[1]), - .@"perspective-origin" => |*v| css.generic.eql(Position, &v[0], &rhs.@"perspective-origin"[0]) and (v[1] == rhs.@"perspective-origin"[1]), - .translate => |*v| css.generic.eql(Translate, v, &rhs.translate), - .rotate => |*v| css.generic.eql(Rotate, v, &rhs.rotate), - .scale => |*v| css.generic.eql(Scale, v, &rhs.scale), - .@"text-decoration-color" => |*v| css.generic.eql(CssColor, &v[0], &rhs.@"text-decoration-color"[0]) and (v[1] == rhs.@"text-decoration-color"[1]), - .@"text-emphasis-color" => |*v| css.generic.eql(CssColor, &v[0], &rhs.@"text-emphasis-color"[0]) and (v[1] == rhs.@"text-emphasis-color"[1]), - .@"text-shadow" => |*v| css.generic.eql(SmallList(TextShadow, 1), v, &rhs.@"text-shadow"), - .direction => |*v| css.generic.eql(Direction, v, &rhs.direction), - .composes => |*v| css.generic.eql(Composes, v, &rhs.composes), - .@"mask-image" => |*v| css.generic.eql(SmallList(Image, 1), &v[0], &rhs.@"mask-image"[0]) and (v[1] == rhs.@"mask-image"[1]), - .@"mask-mode" => |*v| css.generic.eql(SmallList(MaskMode, 1), v, &rhs.@"mask-mode"), - .@"mask-repeat" => |*v| css.generic.eql(SmallList(BackgroundRepeat, 1), &v[0], &rhs.@"mask-repeat"[0]) and (v[1] == rhs.@"mask-repeat"[1]), - .@"mask-position-x" => |*v| css.generic.eql(SmallList(HorizontalPosition, 1), v, &rhs.@"mask-position-x"), - .@"mask-position-y" => |*v| css.generic.eql(SmallList(VerticalPosition, 1), v, &rhs.@"mask-position-y"), - .@"mask-position" => |*v| css.generic.eql(SmallList(Position, 1), &v[0], &rhs.@"mask-position"[0]) and (v[1] == rhs.@"mask-position"[1]), - .@"mask-clip" => |*v| css.generic.eql(SmallList(MaskClip, 1), &v[0], &rhs.@"mask-clip"[0]) and (v[1] == rhs.@"mask-clip"[1]), - .@"mask-origin" => |*v| css.generic.eql(SmallList(GeometryBox, 1), &v[0], &rhs.@"mask-origin"[0]) and (v[1] == rhs.@"mask-origin"[1]), - .@"mask-size" => |*v| css.generic.eql(SmallList(BackgroundSize, 1), &v[0], &rhs.@"mask-size"[0]) and (v[1] == rhs.@"mask-size"[1]), - .@"mask-composite" => |*v| css.generic.eql(SmallList(MaskComposite, 1), v, &rhs.@"mask-composite"), - .@"mask-type" => |*v| css.generic.eql(MaskType, v, &rhs.@"mask-type"), - .mask => |*v| css.generic.eql(SmallList(Mask, 1), &v[0], &rhs.mask[0]) and (v[1] == rhs.mask[1]), - .@"mask-border-source" => |*v| css.generic.eql(Image, v, &rhs.@"mask-border-source"), - .@"mask-border-mode" => |*v| css.generic.eql(MaskBorderMode, v, &rhs.@"mask-border-mode"), - .@"mask-border-slice" => |*v| css.generic.eql(BorderImageSlice, v, &rhs.@"mask-border-slice"), - .@"mask-border-width" => |*v| css.generic.eql(Rect(BorderImageSideWidth), v, &rhs.@"mask-border-width"), - .@"mask-border-outset" => |*v| css.generic.eql(Rect(LengthOrNumber), v, &rhs.@"mask-border-outset"), - .@"mask-border-repeat" => |*v| css.generic.eql(BorderImageRepeat, v, &rhs.@"mask-border-repeat"), - .@"mask-border" => |*v| css.generic.eql(MaskBorder, v, &rhs.@"mask-border"), - .@"-webkit-mask-composite" => |*v| css.generic.eql(SmallList(WebKitMaskComposite, 1), v, &rhs.@"-webkit-mask-composite"), - .@"mask-source-type" => |*v| css.generic.eql(SmallList(WebKitMaskSourceType, 1), &v[0], &rhs.@"mask-source-type"[0]) and (v[1] == rhs.@"mask-source-type"[1]), - .@"mask-box-image" => |*v| css.generic.eql(BorderImage, &v[0], &rhs.@"mask-box-image"[0]) and (v[1] == rhs.@"mask-box-image"[1]), - .@"mask-box-image-source" => |*v| css.generic.eql(Image, &v[0], &rhs.@"mask-box-image-source"[0]) and (v[1] == rhs.@"mask-box-image-source"[1]), - .@"mask-box-image-slice" => |*v| css.generic.eql(BorderImageSlice, &v[0], &rhs.@"mask-box-image-slice"[0]) and (v[1] == rhs.@"mask-box-image-slice"[1]), - .@"mask-box-image-width" => |*v| css.generic.eql(Rect(BorderImageSideWidth), &v[0], &rhs.@"mask-box-image-width"[0]) and (v[1] == rhs.@"mask-box-image-width"[1]), - .@"mask-box-image-outset" => |*v| css.generic.eql(Rect(LengthOrNumber), &v[0], &rhs.@"mask-box-image-outset"[0]) and (v[1] == rhs.@"mask-box-image-outset"[1]), - .@"mask-box-image-repeat" => |*v| css.generic.eql(BorderImageRepeat, &v[0], &rhs.@"mask-box-image-repeat"[0]) and (v[1] == rhs.@"mask-box-image-repeat"[1]), - .@"color-scheme" => |*v| css.generic.eql(ColorScheme, v, &rhs.@"color-scheme"), - .unparsed => |*u| u.eql(&rhs.unparsed), - .all => true, - .custom => |*c| c.eql(&rhs.custom), - }; - } -}; -pub const PropertyId = union(PropertyIdTag) { - @"background-color", - @"background-image", - @"background-position-x", - @"background-position-y", - @"background-position", - @"background-size", - @"background-repeat", - @"background-attachment", - @"background-clip": VendorPrefix, - @"background-origin", - background, - @"box-shadow": VendorPrefix, - opacity, - color, - display, - visibility, - width, - height, - @"min-width", - @"min-height", - @"max-width", - @"max-height", - @"block-size", - @"inline-size", - @"min-block-size", - @"min-inline-size", - @"max-block-size", - @"max-inline-size", - @"box-sizing": VendorPrefix, - @"aspect-ratio", - overflow, - @"overflow-x", - @"overflow-y", - @"text-overflow": VendorPrefix, - position, - top, - bottom, - left, - right, - @"inset-block-start", - @"inset-block-end", - @"inset-inline-start", - @"inset-inline-end", - @"inset-block", - @"inset-inline", - inset, - @"border-spacing", - @"border-top-color", - @"border-bottom-color", - @"border-left-color", - @"border-right-color", - @"border-block-start-color", - @"border-block-end-color", - @"border-inline-start-color", - @"border-inline-end-color", - @"border-top-style", - @"border-bottom-style", - @"border-left-style", - @"border-right-style", - @"border-block-start-style", - @"border-block-end-style", - @"border-inline-start-style", - @"border-inline-end-style", - @"border-top-width", - @"border-bottom-width", - @"border-left-width", - @"border-right-width", - @"border-block-start-width", - @"border-block-end-width", - @"border-inline-start-width", - @"border-inline-end-width", - @"border-top-left-radius": VendorPrefix, - @"border-top-right-radius": VendorPrefix, - @"border-bottom-left-radius": VendorPrefix, - @"border-bottom-right-radius": VendorPrefix, - @"border-start-start-radius", - @"border-start-end-radius", - @"border-end-start-radius", - @"border-end-end-radius", - @"border-radius": VendorPrefix, - @"border-image-source", - @"border-image-outset", - @"border-image-repeat", - @"border-image-width", - @"border-image-slice", - @"border-image": VendorPrefix, - @"border-color", - @"border-style", - @"border-width", - @"border-block-color", - @"border-block-style", - @"border-block-width", - @"border-inline-color", - @"border-inline-style", - @"border-inline-width", - border, - @"border-top", - @"border-bottom", - @"border-left", - @"border-right", - @"border-block", - @"border-block-start", - @"border-block-end", - @"border-inline", - @"border-inline-start", - @"border-inline-end", - outline, - @"outline-color", - @"outline-style", - @"outline-width", - @"flex-direction": VendorPrefix, - @"flex-wrap": VendorPrefix, - @"flex-flow": VendorPrefix, - @"flex-grow": VendorPrefix, - @"flex-shrink": VendorPrefix, - @"flex-basis": VendorPrefix, - flex: VendorPrefix, - order: VendorPrefix, - @"align-content": VendorPrefix, - @"justify-content": VendorPrefix, - @"place-content", - @"align-self": VendorPrefix, - @"justify-self", - @"place-self", - @"align-items": VendorPrefix, - @"justify-items", - @"place-items", - @"row-gap", - @"column-gap", - gap, - @"box-orient": VendorPrefix, - @"box-direction": VendorPrefix, - @"box-ordinal-group": VendorPrefix, - @"box-align": VendorPrefix, - @"box-flex": VendorPrefix, - @"box-flex-group": VendorPrefix, - @"box-pack": VendorPrefix, - @"box-lines": VendorPrefix, - @"flex-pack": VendorPrefix, - @"flex-order": VendorPrefix, - @"flex-align": VendorPrefix, - @"flex-item-align": VendorPrefix, - @"flex-line-pack": VendorPrefix, - @"flex-positive": VendorPrefix, - @"flex-negative": VendorPrefix, - @"flex-preferred-size": VendorPrefix, - @"margin-top", - @"margin-bottom", - @"margin-left", - @"margin-right", - @"margin-block-start", - @"margin-block-end", - @"margin-inline-start", - @"margin-inline-end", - @"margin-block", - @"margin-inline", - margin, - @"padding-top", - @"padding-bottom", - @"padding-left", - @"padding-right", - @"padding-block-start", - @"padding-block-end", - @"padding-inline-start", - @"padding-inline-end", - @"padding-block", - @"padding-inline", - padding, - @"scroll-margin-top", - @"scroll-margin-bottom", - @"scroll-margin-left", - @"scroll-margin-right", - @"scroll-margin-block-start", - @"scroll-margin-block-end", - @"scroll-margin-inline-start", - @"scroll-margin-inline-end", - @"scroll-margin-block", - @"scroll-margin-inline", - @"scroll-margin", - @"scroll-padding-top", - @"scroll-padding-bottom", - @"scroll-padding-left", - @"scroll-padding-right", - @"scroll-padding-block-start", - @"scroll-padding-block-end", - @"scroll-padding-inline-start", - @"scroll-padding-inline-end", - @"scroll-padding-block", - @"scroll-padding-inline", - @"scroll-padding", - @"font-weight", - @"font-size", - @"font-stretch", - @"font-family", - @"font-style", - @"font-variant-caps", - @"line-height", - font, - @"transition-property": VendorPrefix, - @"transition-duration": VendorPrefix, - @"transition-delay": VendorPrefix, - @"transition-timing-function": VendorPrefix, - transition: VendorPrefix, - transform: VendorPrefix, - @"transform-origin": VendorPrefix, - @"transform-style": VendorPrefix, - @"transform-box", - @"backface-visibility": VendorPrefix, - perspective: VendorPrefix, - @"perspective-origin": VendorPrefix, - translate, - rotate, - scale, - @"text-decoration-color": VendorPrefix, - @"text-emphasis-color": VendorPrefix, - @"text-shadow", - direction, - composes, - @"mask-image": VendorPrefix, - @"mask-mode", - @"mask-repeat": VendorPrefix, - @"mask-position-x", - @"mask-position-y", - @"mask-position": VendorPrefix, - @"mask-clip": VendorPrefix, - @"mask-origin": VendorPrefix, - @"mask-size": VendorPrefix, - @"mask-composite", - @"mask-type", - mask: VendorPrefix, - @"mask-border-source", - @"mask-border-mode", - @"mask-border-slice", - @"mask-border-width", - @"mask-border-outset", - @"mask-border-repeat", - @"mask-border", - @"-webkit-mask-composite", - @"mask-source-type": VendorPrefix, - @"mask-box-image": VendorPrefix, - @"mask-box-image-source": VendorPrefix, - @"mask-box-image-slice": VendorPrefix, - @"mask-box-image-width": VendorPrefix, - @"mask-box-image-outset": VendorPrefix, - @"mask-box-image-repeat": VendorPrefix, - @"color-scheme", - all, - unparsed, - custom: CustomPropertyName, - - pub const toCss = properties_impl.property_id_mixin.toCss; - pub const parse = properties_impl.property_id_mixin.parse; - pub const fromString = properties_impl.property_id_mixin.fromString; - pub const fromStr = fromString; - - /// Returns the property name, without any vendor prefixes. - pub inline fn name(this: *const PropertyId) []const u8 { - if (this.* == .custom) return this.custom.asStr(); - return @tagName(this.*); - } - - /// Returns the vendor prefix for this property id. - pub fn prefix(this: *const PropertyId) VendorPrefix { - return switch (this.*) { - .@"background-color" => .empty, - .@"background-image" => .empty, - .@"background-position-x" => .empty, - .@"background-position-y" => .empty, - .@"background-position" => .empty, - .@"background-size" => .empty, - .@"background-repeat" => .empty, - .@"background-attachment" => .empty, - .@"background-clip" => |p| p, - .@"background-origin" => .empty, - .background => .empty, - .@"box-shadow" => |p| p, - .opacity => .empty, - .color => .empty, - .display => .empty, - .visibility => .empty, - .width => .empty, - .height => .empty, - .@"min-width" => .empty, - .@"min-height" => .empty, - .@"max-width" => .empty, - .@"max-height" => .empty, - .@"block-size" => .empty, - .@"inline-size" => .empty, - .@"min-block-size" => .empty, - .@"min-inline-size" => .empty, - .@"max-block-size" => .empty, - .@"max-inline-size" => .empty, - .@"box-sizing" => |p| p, - .@"aspect-ratio" => .empty, - .overflow => .empty, - .@"overflow-x" => .empty, - .@"overflow-y" => .empty, - .@"text-overflow" => |p| p, - .position => .empty, - .top => .empty, - .bottom => .empty, - .left => .empty, - .right => .empty, - .@"inset-block-start" => .empty, - .@"inset-block-end" => .empty, - .@"inset-inline-start" => .empty, - .@"inset-inline-end" => .empty, - .@"inset-block" => .empty, - .@"inset-inline" => .empty, - .inset => .empty, - .@"border-spacing" => .empty, - .@"border-top-color" => .empty, - .@"border-bottom-color" => .empty, - .@"border-left-color" => .empty, - .@"border-right-color" => .empty, - .@"border-block-start-color" => .empty, - .@"border-block-end-color" => .empty, - .@"border-inline-start-color" => .empty, - .@"border-inline-end-color" => .empty, - .@"border-top-style" => .empty, - .@"border-bottom-style" => .empty, - .@"border-left-style" => .empty, - .@"border-right-style" => .empty, - .@"border-block-start-style" => .empty, - .@"border-block-end-style" => .empty, - .@"border-inline-start-style" => .empty, - .@"border-inline-end-style" => .empty, - .@"border-top-width" => .empty, - .@"border-bottom-width" => .empty, - .@"border-left-width" => .empty, - .@"border-right-width" => .empty, - .@"border-block-start-width" => .empty, - .@"border-block-end-width" => .empty, - .@"border-inline-start-width" => .empty, - .@"border-inline-end-width" => .empty, - .@"border-top-left-radius" => |p| p, - .@"border-top-right-radius" => |p| p, - .@"border-bottom-left-radius" => |p| p, - .@"border-bottom-right-radius" => |p| p, - .@"border-start-start-radius" => .empty, - .@"border-start-end-radius" => .empty, - .@"border-end-start-radius" => .empty, - .@"border-end-end-radius" => .empty, - .@"border-radius" => |p| p, - .@"border-image-source" => .empty, - .@"border-image-outset" => .empty, - .@"border-image-repeat" => .empty, - .@"border-image-width" => .empty, - .@"border-image-slice" => .empty, - .@"border-image" => |p| p, - .@"border-color" => .empty, - .@"border-style" => .empty, - .@"border-width" => .empty, - .@"border-block-color" => .empty, - .@"border-block-style" => .empty, - .@"border-block-width" => .empty, - .@"border-inline-color" => .empty, - .@"border-inline-style" => .empty, - .@"border-inline-width" => .empty, - .border => .empty, - .@"border-top" => .empty, - .@"border-bottom" => .empty, - .@"border-left" => .empty, - .@"border-right" => .empty, - .@"border-block" => .empty, - .@"border-block-start" => .empty, - .@"border-block-end" => .empty, - .@"border-inline" => .empty, - .@"border-inline-start" => .empty, - .@"border-inline-end" => .empty, - .outline => .empty, - .@"outline-color" => .empty, - .@"outline-style" => .empty, - .@"outline-width" => .empty, - .@"flex-direction" => |p| p, - .@"flex-wrap" => |p| p, - .@"flex-flow" => |p| p, - .@"flex-grow" => |p| p, - .@"flex-shrink" => |p| p, - .@"flex-basis" => |p| p, - .flex => |p| p, - .order => |p| p, - .@"align-content" => |p| p, - .@"justify-content" => |p| p, - .@"place-content" => .empty, - .@"align-self" => |p| p, - .@"justify-self" => .empty, - .@"place-self" => .empty, - .@"align-items" => |p| p, - .@"justify-items" => .empty, - .@"place-items" => .empty, - .@"row-gap" => .empty, - .@"column-gap" => .empty, - .gap => .empty, - .@"box-orient" => |p| p, - .@"box-direction" => |p| p, - .@"box-ordinal-group" => |p| p, - .@"box-align" => |p| p, - .@"box-flex" => |p| p, - .@"box-flex-group" => |p| p, - .@"box-pack" => |p| p, - .@"box-lines" => |p| p, - .@"flex-pack" => |p| p, - .@"flex-order" => |p| p, - .@"flex-align" => |p| p, - .@"flex-item-align" => |p| p, - .@"flex-line-pack" => |p| p, - .@"flex-positive" => |p| p, - .@"flex-negative" => |p| p, - .@"flex-preferred-size" => |p| p, - .@"margin-top" => .empty, - .@"margin-bottom" => .empty, - .@"margin-left" => .empty, - .@"margin-right" => .empty, - .@"margin-block-start" => .empty, - .@"margin-block-end" => .empty, - .@"margin-inline-start" => .empty, - .@"margin-inline-end" => .empty, - .@"margin-block" => .empty, - .@"margin-inline" => .empty, - .margin => .empty, - .@"padding-top" => .empty, - .@"padding-bottom" => .empty, - .@"padding-left" => .empty, - .@"padding-right" => .empty, - .@"padding-block-start" => .empty, - .@"padding-block-end" => .empty, - .@"padding-inline-start" => .empty, - .@"padding-inline-end" => .empty, - .@"padding-block" => .empty, - .@"padding-inline" => .empty, - .padding => .empty, - .@"scroll-margin-top" => .empty, - .@"scroll-margin-bottom" => .empty, - .@"scroll-margin-left" => .empty, - .@"scroll-margin-right" => .empty, - .@"scroll-margin-block-start" => .empty, - .@"scroll-margin-block-end" => .empty, - .@"scroll-margin-inline-start" => .empty, - .@"scroll-margin-inline-end" => .empty, - .@"scroll-margin-block" => .empty, - .@"scroll-margin-inline" => .empty, - .@"scroll-margin" => .empty, - .@"scroll-padding-top" => .empty, - .@"scroll-padding-bottom" => .empty, - .@"scroll-padding-left" => .empty, - .@"scroll-padding-right" => .empty, - .@"scroll-padding-block-start" => .empty, - .@"scroll-padding-block-end" => .empty, - .@"scroll-padding-inline-start" => .empty, - .@"scroll-padding-inline-end" => .empty, - .@"scroll-padding-block" => .empty, - .@"scroll-padding-inline" => .empty, - .@"scroll-padding" => .empty, - .@"font-weight" => .empty, - .@"font-size" => .empty, - .@"font-stretch" => .empty, - .@"font-family" => .empty, - .@"font-style" => .empty, - .@"font-variant-caps" => .empty, - .@"line-height" => .empty, - .font => .empty, - .@"transition-property" => |p| p, - .@"transition-duration" => |p| p, - .@"transition-delay" => |p| p, - .@"transition-timing-function" => |p| p, - .transition => |p| p, - .transform => |p| p, - .@"transform-origin" => |p| p, - .@"transform-style" => |p| p, - .@"transform-box" => .empty, - .@"backface-visibility" => |p| p, - .perspective => |p| p, - .@"perspective-origin" => |p| p, - .translate => .empty, - .rotate => .empty, - .scale => .empty, - .@"text-decoration-color" => |p| p, - .@"text-emphasis-color" => |p| p, - .@"text-shadow" => .empty, - .direction => .empty, - .composes => .empty, - .@"mask-image" => |p| p, - .@"mask-mode" => .empty, - .@"mask-repeat" => |p| p, - .@"mask-position-x" => .empty, - .@"mask-position-y" => .empty, - .@"mask-position" => |p| p, - .@"mask-clip" => |p| p, - .@"mask-origin" => |p| p, - .@"mask-size" => |p| p, - .@"mask-composite" => .empty, - .@"mask-type" => .empty, - .mask => |p| p, - .@"mask-border-source" => .empty, - .@"mask-border-mode" => .empty, - .@"mask-border-slice" => .empty, - .@"mask-border-width" => .empty, - .@"mask-border-outset" => .empty, - .@"mask-border-repeat" => .empty, - .@"mask-border" => .empty, - .@"-webkit-mask-composite" => .empty, - .@"mask-source-type" => |p| p, - .@"mask-box-image" => |p| p, - .@"mask-box-image-source" => |p| p, - .@"mask-box-image-slice" => |p| p, - .@"mask-box-image-width" => |p| p, - .@"mask-box-image-outset" => |p| p, - .@"mask-box-image-repeat" => |p| p, - .@"color-scheme" => .empty, - .all, .custom, .unparsed => .empty, - }; - } - - pub fn fromNameAndPrefix(name1: []const u8, pre: VendorPrefix) ?PropertyId { - const Enum = enum { @"background-color", @"background-image", @"background-position-x", @"background-position-y", @"background-position", @"background-size", @"background-repeat", @"background-attachment", @"background-clip", @"background-origin", background, @"box-shadow", opacity, color, display, visibility, width, height, @"min-width", @"min-height", @"max-width", @"max-height", @"block-size", @"inline-size", @"min-block-size", @"min-inline-size", @"max-block-size", @"max-inline-size", @"box-sizing", @"aspect-ratio", overflow, @"overflow-x", @"overflow-y", @"text-overflow", position, top, bottom, left, right, @"inset-block-start", @"inset-block-end", @"inset-inline-start", @"inset-inline-end", @"inset-block", @"inset-inline", inset, @"border-spacing", @"border-top-color", @"border-bottom-color", @"border-left-color", @"border-right-color", @"border-block-start-color", @"border-block-end-color", @"border-inline-start-color", @"border-inline-end-color", @"border-top-style", @"border-bottom-style", @"border-left-style", @"border-right-style", @"border-block-start-style", @"border-block-end-style", @"border-inline-start-style", @"border-inline-end-style", @"border-top-width", @"border-bottom-width", @"border-left-width", @"border-right-width", @"border-block-start-width", @"border-block-end-width", @"border-inline-start-width", @"border-inline-end-width", @"border-top-left-radius", @"border-top-right-radius", @"border-bottom-left-radius", @"border-bottom-right-radius", @"border-start-start-radius", @"border-start-end-radius", @"border-end-start-radius", @"border-end-end-radius", @"border-radius", @"border-image-source", @"border-image-outset", @"border-image-repeat", @"border-image-width", @"border-image-slice", @"border-image", @"border-color", @"border-style", @"border-width", @"border-block-color", @"border-block-style", @"border-block-width", @"border-inline-color", @"border-inline-style", @"border-inline-width", border, @"border-top", @"border-bottom", @"border-left", @"border-right", @"border-block", @"border-block-start", @"border-block-end", @"border-inline", @"border-inline-start", @"border-inline-end", outline, @"outline-color", @"outline-style", @"outline-width", @"flex-direction", @"flex-wrap", @"flex-flow", @"flex-grow", @"flex-shrink", @"flex-basis", flex, order, @"align-content", @"justify-content", @"place-content", @"align-self", @"justify-self", @"place-self", @"align-items", @"justify-items", @"place-items", @"row-gap", @"column-gap", gap, @"box-orient", @"box-direction", @"box-ordinal-group", @"box-align", @"box-flex", @"box-flex-group", @"box-pack", @"box-lines", @"flex-pack", @"flex-order", @"flex-align", @"flex-item-align", @"flex-line-pack", @"flex-positive", @"flex-negative", @"flex-preferred-size", @"margin-top", @"margin-bottom", @"margin-left", @"margin-right", @"margin-block-start", @"margin-block-end", @"margin-inline-start", @"margin-inline-end", @"margin-block", @"margin-inline", margin, @"padding-top", @"padding-bottom", @"padding-left", @"padding-right", @"padding-block-start", @"padding-block-end", @"padding-inline-start", @"padding-inline-end", @"padding-block", @"padding-inline", padding, @"scroll-margin-top", @"scroll-margin-bottom", @"scroll-margin-left", @"scroll-margin-right", @"scroll-margin-block-start", @"scroll-margin-block-end", @"scroll-margin-inline-start", @"scroll-margin-inline-end", @"scroll-margin-block", @"scroll-margin-inline", @"scroll-margin", @"scroll-padding-top", @"scroll-padding-bottom", @"scroll-padding-left", @"scroll-padding-right", @"scroll-padding-block-start", @"scroll-padding-block-end", @"scroll-padding-inline-start", @"scroll-padding-inline-end", @"scroll-padding-block", @"scroll-padding-inline", @"scroll-padding", @"font-weight", @"font-size", @"font-stretch", @"font-family", @"font-style", @"font-variant-caps", @"line-height", font, @"transition-property", @"transition-duration", @"transition-delay", @"transition-timing-function", transition, transform, @"transform-origin", @"transform-style", @"transform-box", @"backface-visibility", perspective, @"perspective-origin", translate, rotate, scale, @"text-decoration-color", @"text-emphasis-color", @"text-shadow", direction, composes, @"mask-image", @"mask-mode", @"mask-repeat", @"mask-position-x", @"mask-position-y", @"mask-position", @"mask-clip", @"mask-origin", @"mask-size", @"mask-composite", @"mask-type", mask, @"mask-border-source", @"mask-border-mode", @"mask-border-slice", @"mask-border-width", @"mask-border-outset", @"mask-border-repeat", @"mask-border", @"-webkit-mask-composite", @"mask-source-type", @"mask-box-image", @"mask-box-image-source", @"mask-box-image-slice", @"mask-box-image-width", @"mask-box-image-outset", @"mask-box-image-repeat", @"color-scheme" }; - const Map = comptime bun.ComptimeEnumMap(Enum); - if (Map.getASCIIICaseInsensitive(name1)) |prop| { - switch (prop) { - .@"background-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-color"; - }, - .@"background-image" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-image"; - }, - .@"background-position-x" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-position-x"; - }, - .@"background-position-y" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-position-y"; - }, - .@"background-position" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-position"; - }, - .@"background-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-size"; - }, - .@"background-repeat" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-repeat"; - }, - .@"background-attachment" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-attachment"; - }, - .@"background-clip" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"background-clip" = pre }; - }, - .@"background-origin" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"background-origin"; - }, - .background => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .background; - }, - .@"box-shadow" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-shadow" = pre }; - }, - .opacity => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .opacity; - }, - .color => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .color; - }, - .display => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .display; - }, - .visibility => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .visibility; - }, - .width => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .width; - }, - .height => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .height; - }, - .@"min-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"min-width"; - }, - .@"min-height" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"min-height"; - }, - .@"max-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"max-width"; - }, - .@"max-height" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"max-height"; - }, - .@"block-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"block-size"; - }, - .@"inline-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"inline-size"; - }, - .@"min-block-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"min-block-size"; - }, - .@"min-inline-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"min-inline-size"; - }, - .@"max-block-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"max-block-size"; - }, - .@"max-inline-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"max-inline-size"; - }, - .@"box-sizing" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-sizing" = pre }; - }, - .@"aspect-ratio" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"aspect-ratio"; - }, - .overflow => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .overflow; - }, - .@"overflow-x" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"overflow-x"; - }, - .@"overflow-y" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"overflow-y"; - }, - .@"text-overflow" => { - const allowed_prefixes = VendorPrefix{ .none = true, .o = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"text-overflow" = pre }; - }, - .position => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .position; - }, - .top => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .top; - }, - .bottom => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .bottom; - }, - .left => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .left; - }, - .right => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .right; - }, - .@"inset-block-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"inset-block-start"; - }, - .@"inset-block-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"inset-block-end"; - }, - .@"inset-inline-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"inset-inline-start"; - }, - .@"inset-inline-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"inset-inline-end"; - }, - .@"inset-block" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"inset-block"; - }, - .@"inset-inline" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"inset-inline"; - }, - .inset => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .inset; - }, - .@"border-spacing" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-spacing"; - }, - .@"border-top-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-top-color"; - }, - .@"border-bottom-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-bottom-color"; - }, - .@"border-left-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-left-color"; - }, - .@"border-right-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-right-color"; - }, - .@"border-block-start-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-start-color"; - }, - .@"border-block-end-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-end-color"; - }, - .@"border-inline-start-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-start-color"; - }, - .@"border-inline-end-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-end-color"; - }, - .@"border-top-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-top-style"; - }, - .@"border-bottom-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-bottom-style"; - }, - .@"border-left-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-left-style"; - }, - .@"border-right-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-right-style"; - }, - .@"border-block-start-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-start-style"; - }, - .@"border-block-end-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-end-style"; - }, - .@"border-inline-start-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-start-style"; - }, - .@"border-inline-end-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-end-style"; - }, - .@"border-top-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-top-width"; - }, - .@"border-bottom-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-bottom-width"; - }, - .@"border-left-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-left-width"; - }, - .@"border-right-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-right-width"; - }, - .@"border-block-start-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-start-width"; - }, - .@"border-block-end-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-end-width"; - }, - .@"border-inline-start-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-start-width"; - }, - .@"border-inline-end-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-end-width"; - }, - .@"border-top-left-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"border-top-left-radius" = pre }; - }, - .@"border-top-right-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"border-top-right-radius" = pre }; - }, - .@"border-bottom-left-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"border-bottom-left-radius" = pre }; - }, - .@"border-bottom-right-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"border-bottom-right-radius" = pre }; - }, - .@"border-start-start-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-start-start-radius"; - }, - .@"border-start-end-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-start-end-radius"; - }, - .@"border-end-start-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-end-start-radius"; - }, - .@"border-end-end-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-end-end-radius"; - }, - .@"border-radius" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"border-radius" = pre }; - }, - .@"border-image-source" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-image-source"; - }, - .@"border-image-outset" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-image-outset"; - }, - .@"border-image-repeat" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-image-repeat"; - }, - .@"border-image-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-image-width"; - }, - .@"border-image-slice" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-image-slice"; - }, - .@"border-image" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .o = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"border-image" = pre }; - }, - .@"border-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-color"; - }, - .@"border-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-style"; - }, - .@"border-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-width"; - }, - .@"border-block-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-color"; - }, - .@"border-block-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-style"; - }, - .@"border-block-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-width"; - }, - .@"border-inline-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-color"; - }, - .@"border-inline-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-style"; - }, - .@"border-inline-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-width"; - }, - .border => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .border; - }, - .@"border-top" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-top"; - }, - .@"border-bottom" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-bottom"; - }, - .@"border-left" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-left"; - }, - .@"border-right" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-right"; - }, - .@"border-block" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block"; - }, - .@"border-block-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-start"; - }, - .@"border-block-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-block-end"; - }, - .@"border-inline" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline"; - }, - .@"border-inline-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-start"; - }, - .@"border-inline-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"border-inline-end"; - }, - .outline => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .outline; - }, - .@"outline-color" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"outline-color"; - }, - .@"outline-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"outline-style"; - }, - .@"outline-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"outline-width"; - }, - .@"flex-direction" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-direction" = pre }; - }, - .@"flex-wrap" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-wrap" = pre }; - }, - .@"flex-flow" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-flow" = pre }; - }, - .@"flex-grow" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-grow" = pre }; - }, - .@"flex-shrink" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-shrink" = pre }; - }, - .@"flex-basis" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-basis" = pre }; - }, - .flex => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .flex = pre }; - }, - .order => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .order = pre }; - }, - .@"align-content" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"align-content" = pre }; - }, - .@"justify-content" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"justify-content" = pre }; - }, - .@"place-content" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"place-content"; - }, - .@"align-self" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"align-self" = pre }; - }, - .@"justify-self" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"justify-self"; - }, - .@"place-self" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"place-self"; - }, - .@"align-items" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"align-items" = pre }; - }, - .@"justify-items" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"justify-items"; - }, - .@"place-items" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"place-items"; - }, - .@"row-gap" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"row-gap"; - }, - .@"column-gap" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"column-gap"; - }, - .gap => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .gap; - }, - .@"box-orient" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-orient" = pre }; - }, - .@"box-direction" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-direction" = pre }; - }, - .@"box-ordinal-group" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-ordinal-group" = pre }; - }, - .@"box-align" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-align" = pre }; - }, - .@"box-flex" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-flex" = pre }; - }, - .@"box-flex-group" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-flex-group" = pre }; - }, - .@"box-pack" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-pack" = pre }; - }, - .@"box-lines" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"box-lines" = pre }; - }, - .@"flex-pack" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-pack" = pre }; - }, - .@"flex-order" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-order" = pre }; - }, - .@"flex-align" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-align" = pre }; - }, - .@"flex-item-align" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-item-align" = pre }; - }, - .@"flex-line-pack" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-line-pack" = pre }; - }, - .@"flex-positive" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-positive" = pre }; - }, - .@"flex-negative" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-negative" = pre }; - }, - .@"flex-preferred-size" => { - const allowed_prefixes = VendorPrefix{ .none = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"flex-preferred-size" = pre }; - }, - .@"margin-top" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-top"; - }, - .@"margin-bottom" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-bottom"; - }, - .@"margin-left" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-left"; - }, - .@"margin-right" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-right"; - }, - .@"margin-block-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-block-start"; - }, - .@"margin-block-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-block-end"; - }, - .@"margin-inline-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-inline-start"; - }, - .@"margin-inline-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-inline-end"; - }, - .@"margin-block" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-block"; - }, - .@"margin-inline" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"margin-inline"; - }, - .margin => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .margin; - }, - .@"padding-top" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-top"; - }, - .@"padding-bottom" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-bottom"; - }, - .@"padding-left" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-left"; - }, - .@"padding-right" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-right"; - }, - .@"padding-block-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-block-start"; - }, - .@"padding-block-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-block-end"; - }, - .@"padding-inline-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-inline-start"; - }, - .@"padding-inline-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-inline-end"; - }, - .@"padding-block" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-block"; - }, - .@"padding-inline" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"padding-inline"; - }, - .padding => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .padding; - }, - .@"scroll-margin-top" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-top"; - }, - .@"scroll-margin-bottom" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-bottom"; - }, - .@"scroll-margin-left" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-left"; - }, - .@"scroll-margin-right" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-right"; - }, - .@"scroll-margin-block-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-block-start"; - }, - .@"scroll-margin-block-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-block-end"; - }, - .@"scroll-margin-inline-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-inline-start"; - }, - .@"scroll-margin-inline-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-inline-end"; - }, - .@"scroll-margin-block" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-block"; - }, - .@"scroll-margin-inline" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin-inline"; - }, - .@"scroll-margin" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-margin"; - }, - .@"scroll-padding-top" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-top"; - }, - .@"scroll-padding-bottom" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-bottom"; - }, - .@"scroll-padding-left" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-left"; - }, - .@"scroll-padding-right" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-right"; - }, - .@"scroll-padding-block-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-block-start"; - }, - .@"scroll-padding-block-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-block-end"; - }, - .@"scroll-padding-inline-start" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-inline-start"; - }, - .@"scroll-padding-inline-end" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-inline-end"; - }, - .@"scroll-padding-block" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-block"; - }, - .@"scroll-padding-inline" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding-inline"; - }, - .@"scroll-padding" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"scroll-padding"; - }, - .@"font-weight" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"font-weight"; - }, - .@"font-size" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"font-size"; - }, - .@"font-stretch" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"font-stretch"; - }, - .@"font-family" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"font-family"; - }, - .@"font-style" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"font-style"; - }, - .@"font-variant-caps" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"font-variant-caps"; - }, - .@"line-height" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"line-height"; - }, - .font => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .font; - }, - .@"transition-property" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"transition-property" = pre }; - }, - .@"transition-duration" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"transition-duration" = pre }; - }, - .@"transition-delay" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"transition-delay" = pre }; - }, - .@"transition-timing-function" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"transition-timing-function" = pre }; - }, - .transition => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .ms = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .transition = pre }; - }, - .transform => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .ms = true, .o = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .transform = pre }; - }, - .@"transform-origin" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true, .ms = true, .o = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"transform-origin" = pre }; - }, - .@"transform-style" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"transform-style" = pre }; - }, - .@"transform-box" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"transform-box"; - }, - .@"backface-visibility" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"backface-visibility" = pre }; - }, - .perspective => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .perspective = pre }; - }, - .@"perspective-origin" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"perspective-origin" = pre }; - }, - .translate => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .translate; - }, - .rotate => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .rotate; - }, - .scale => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .scale; - }, - .@"text-decoration-color" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true, .moz = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"text-decoration-color" = pre }; - }, - .@"text-emphasis-color" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"text-emphasis-color" = pre }; - }, - .@"text-shadow" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"text-shadow"; - }, - .direction => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .direction; - }, - .composes => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .composes; - }, - .@"mask-image" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-image" = pre }; - }, - .@"mask-mode" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-mode"; - }, - .@"mask-repeat" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-repeat" = pre }; - }, - .@"mask-position-x" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-position-x"; - }, - .@"mask-position-y" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-position-y"; - }, - .@"mask-position" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-position" = pre }; - }, - .@"mask-clip" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-clip" = pre }; - }, - .@"mask-origin" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-origin" = pre }; - }, - .@"mask-size" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-size" = pre }; - }, - .@"mask-composite" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-composite"; - }, - .@"mask-type" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-type"; - }, - .mask => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .mask = pre }; - }, - .@"mask-border-source" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-border-source"; - }, - .@"mask-border-mode" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-border-mode"; - }, - .@"mask-border-slice" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-border-slice"; - }, - .@"mask-border-width" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-border-width"; - }, - .@"mask-border-outset" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-border-outset"; - }, - .@"mask-border-repeat" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-border-repeat"; - }, - .@"mask-border" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"mask-border"; - }, - .@"-webkit-mask-composite" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"-webkit-mask-composite"; - }, - .@"mask-source-type" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-source-type" = pre }; - }, - .@"mask-box-image" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-box-image" = pre }; - }, - .@"mask-box-image-source" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-box-image-source" = pre }; - }, - .@"mask-box-image-slice" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-box-image-slice" = pre }; - }, - .@"mask-box-image-width" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-box-image-width" = pre }; - }, - .@"mask-box-image-outset" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-box-image-outset" = pre }; - }, - .@"mask-box-image-repeat" => { - const allowed_prefixes = VendorPrefix{ .none = true, .webkit = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .{ .@"mask-box-image-repeat" = pre }; - }, - .@"color-scheme" => { - const allowed_prefixes = VendorPrefix{ .none = true }; - if (bits.contains(VendorPrefix, allowed_prefixes, pre)) return .@"color-scheme"; - }, - } - } - - return null; - } - - pub fn withPrefix(this: *const PropertyId, pre: VendorPrefix) PropertyId { - return switch (this.*) { - .@"background-color" => .@"background-color", - .@"background-image" => .@"background-image", - .@"background-position-x" => .@"background-position-x", - .@"background-position-y" => .@"background-position-y", - .@"background-position" => .@"background-position", - .@"background-size" => .@"background-size", - .@"background-repeat" => .@"background-repeat", - .@"background-attachment" => .@"background-attachment", - .@"background-clip" => .{ .@"background-clip" = pre }, - .@"background-origin" => .@"background-origin", - .background => .background, - .@"box-shadow" => .{ .@"box-shadow" = pre }, - .opacity => .opacity, - .color => .color, - .display => .display, - .visibility => .visibility, - .width => .width, - .height => .height, - .@"min-width" => .@"min-width", - .@"min-height" => .@"min-height", - .@"max-width" => .@"max-width", - .@"max-height" => .@"max-height", - .@"block-size" => .@"block-size", - .@"inline-size" => .@"inline-size", - .@"min-block-size" => .@"min-block-size", - .@"min-inline-size" => .@"min-inline-size", - .@"max-block-size" => .@"max-block-size", - .@"max-inline-size" => .@"max-inline-size", - .@"box-sizing" => .{ .@"box-sizing" = pre }, - .@"aspect-ratio" => .@"aspect-ratio", - .overflow => .overflow, - .@"overflow-x" => .@"overflow-x", - .@"overflow-y" => .@"overflow-y", - .@"text-overflow" => .{ .@"text-overflow" = pre }, - .position => .position, - .top => .top, - .bottom => .bottom, - .left => .left, - .right => .right, - .@"inset-block-start" => .@"inset-block-start", - .@"inset-block-end" => .@"inset-block-end", - .@"inset-inline-start" => .@"inset-inline-start", - .@"inset-inline-end" => .@"inset-inline-end", - .@"inset-block" => .@"inset-block", - .@"inset-inline" => .@"inset-inline", - .inset => .inset, - .@"border-spacing" => .@"border-spacing", - .@"border-top-color" => .@"border-top-color", - .@"border-bottom-color" => .@"border-bottom-color", - .@"border-left-color" => .@"border-left-color", - .@"border-right-color" => .@"border-right-color", - .@"border-block-start-color" => .@"border-block-start-color", - .@"border-block-end-color" => .@"border-block-end-color", - .@"border-inline-start-color" => .@"border-inline-start-color", - .@"border-inline-end-color" => .@"border-inline-end-color", - .@"border-top-style" => .@"border-top-style", - .@"border-bottom-style" => .@"border-bottom-style", - .@"border-left-style" => .@"border-left-style", - .@"border-right-style" => .@"border-right-style", - .@"border-block-start-style" => .@"border-block-start-style", - .@"border-block-end-style" => .@"border-block-end-style", - .@"border-inline-start-style" => .@"border-inline-start-style", - .@"border-inline-end-style" => .@"border-inline-end-style", - .@"border-top-width" => .@"border-top-width", - .@"border-bottom-width" => .@"border-bottom-width", - .@"border-left-width" => .@"border-left-width", - .@"border-right-width" => .@"border-right-width", - .@"border-block-start-width" => .@"border-block-start-width", - .@"border-block-end-width" => .@"border-block-end-width", - .@"border-inline-start-width" => .@"border-inline-start-width", - .@"border-inline-end-width" => .@"border-inline-end-width", - .@"border-top-left-radius" => .{ .@"border-top-left-radius" = pre }, - .@"border-top-right-radius" => .{ .@"border-top-right-radius" = pre }, - .@"border-bottom-left-radius" => .{ .@"border-bottom-left-radius" = pre }, - .@"border-bottom-right-radius" => .{ .@"border-bottom-right-radius" = pre }, - .@"border-start-start-radius" => .@"border-start-start-radius", - .@"border-start-end-radius" => .@"border-start-end-radius", - .@"border-end-start-radius" => .@"border-end-start-radius", - .@"border-end-end-radius" => .@"border-end-end-radius", - .@"border-radius" => .{ .@"border-radius" = pre }, - .@"border-image-source" => .@"border-image-source", - .@"border-image-outset" => .@"border-image-outset", - .@"border-image-repeat" => .@"border-image-repeat", - .@"border-image-width" => .@"border-image-width", - .@"border-image-slice" => .@"border-image-slice", - .@"border-image" => .{ .@"border-image" = pre }, - .@"border-color" => .@"border-color", - .@"border-style" => .@"border-style", - .@"border-width" => .@"border-width", - .@"border-block-color" => .@"border-block-color", - .@"border-block-style" => .@"border-block-style", - .@"border-block-width" => .@"border-block-width", - .@"border-inline-color" => .@"border-inline-color", - .@"border-inline-style" => .@"border-inline-style", - .@"border-inline-width" => .@"border-inline-width", - .border => .border, - .@"border-top" => .@"border-top", - .@"border-bottom" => .@"border-bottom", - .@"border-left" => .@"border-left", - .@"border-right" => .@"border-right", - .@"border-block" => .@"border-block", - .@"border-block-start" => .@"border-block-start", - .@"border-block-end" => .@"border-block-end", - .@"border-inline" => .@"border-inline", - .@"border-inline-start" => .@"border-inline-start", - .@"border-inline-end" => .@"border-inline-end", - .outline => .outline, - .@"outline-color" => .@"outline-color", - .@"outline-style" => .@"outline-style", - .@"outline-width" => .@"outline-width", - .@"flex-direction" => .{ .@"flex-direction" = pre }, - .@"flex-wrap" => .{ .@"flex-wrap" = pre }, - .@"flex-flow" => .{ .@"flex-flow" = pre }, - .@"flex-grow" => .{ .@"flex-grow" = pre }, - .@"flex-shrink" => .{ .@"flex-shrink" = pre }, - .@"flex-basis" => .{ .@"flex-basis" = pre }, - .flex => .{ .flex = pre }, - .order => .{ .order = pre }, - .@"align-content" => .{ .@"align-content" = pre }, - .@"justify-content" => .{ .@"justify-content" = pre }, - .@"place-content" => .@"place-content", - .@"align-self" => .{ .@"align-self" = pre }, - .@"justify-self" => .@"justify-self", - .@"place-self" => .@"place-self", - .@"align-items" => .{ .@"align-items" = pre }, - .@"justify-items" => .@"justify-items", - .@"place-items" => .@"place-items", - .@"row-gap" => .@"row-gap", - .@"column-gap" => .@"column-gap", - .gap => .gap, - .@"box-orient" => .{ .@"box-orient" = pre }, - .@"box-direction" => .{ .@"box-direction" = pre }, - .@"box-ordinal-group" => .{ .@"box-ordinal-group" = pre }, - .@"box-align" => .{ .@"box-align" = pre }, - .@"box-flex" => .{ .@"box-flex" = pre }, - .@"box-flex-group" => .{ .@"box-flex-group" = pre }, - .@"box-pack" => .{ .@"box-pack" = pre }, - .@"box-lines" => .{ .@"box-lines" = pre }, - .@"flex-pack" => .{ .@"flex-pack" = pre }, - .@"flex-order" => .{ .@"flex-order" = pre }, - .@"flex-align" => .{ .@"flex-align" = pre }, - .@"flex-item-align" => .{ .@"flex-item-align" = pre }, - .@"flex-line-pack" => .{ .@"flex-line-pack" = pre }, - .@"flex-positive" => .{ .@"flex-positive" = pre }, - .@"flex-negative" => .{ .@"flex-negative" = pre }, - .@"flex-preferred-size" => .{ .@"flex-preferred-size" = pre }, - .@"margin-top" => .@"margin-top", - .@"margin-bottom" => .@"margin-bottom", - .@"margin-left" => .@"margin-left", - .@"margin-right" => .@"margin-right", - .@"margin-block-start" => .@"margin-block-start", - .@"margin-block-end" => .@"margin-block-end", - .@"margin-inline-start" => .@"margin-inline-start", - .@"margin-inline-end" => .@"margin-inline-end", - .@"margin-block" => .@"margin-block", - .@"margin-inline" => .@"margin-inline", - .margin => .margin, - .@"padding-top" => .@"padding-top", - .@"padding-bottom" => .@"padding-bottom", - .@"padding-left" => .@"padding-left", - .@"padding-right" => .@"padding-right", - .@"padding-block-start" => .@"padding-block-start", - .@"padding-block-end" => .@"padding-block-end", - .@"padding-inline-start" => .@"padding-inline-start", - .@"padding-inline-end" => .@"padding-inline-end", - .@"padding-block" => .@"padding-block", - .@"padding-inline" => .@"padding-inline", - .padding => .padding, - .@"scroll-margin-top" => .@"scroll-margin-top", - .@"scroll-margin-bottom" => .@"scroll-margin-bottom", - .@"scroll-margin-left" => .@"scroll-margin-left", - .@"scroll-margin-right" => .@"scroll-margin-right", - .@"scroll-margin-block-start" => .@"scroll-margin-block-start", - .@"scroll-margin-block-end" => .@"scroll-margin-block-end", - .@"scroll-margin-inline-start" => .@"scroll-margin-inline-start", - .@"scroll-margin-inline-end" => .@"scroll-margin-inline-end", - .@"scroll-margin-block" => .@"scroll-margin-block", - .@"scroll-margin-inline" => .@"scroll-margin-inline", - .@"scroll-margin" => .@"scroll-margin", - .@"scroll-padding-top" => .@"scroll-padding-top", - .@"scroll-padding-bottom" => .@"scroll-padding-bottom", - .@"scroll-padding-left" => .@"scroll-padding-left", - .@"scroll-padding-right" => .@"scroll-padding-right", - .@"scroll-padding-block-start" => .@"scroll-padding-block-start", - .@"scroll-padding-block-end" => .@"scroll-padding-block-end", - .@"scroll-padding-inline-start" => .@"scroll-padding-inline-start", - .@"scroll-padding-inline-end" => .@"scroll-padding-inline-end", - .@"scroll-padding-block" => .@"scroll-padding-block", - .@"scroll-padding-inline" => .@"scroll-padding-inline", - .@"scroll-padding" => .@"scroll-padding", - .@"font-weight" => .@"font-weight", - .@"font-size" => .@"font-size", - .@"font-stretch" => .@"font-stretch", - .@"font-family" => .@"font-family", - .@"font-style" => .@"font-style", - .@"font-variant-caps" => .@"font-variant-caps", - .@"line-height" => .@"line-height", - .font => .font, - .@"transition-property" => .{ .@"transition-property" = pre }, - .@"transition-duration" => .{ .@"transition-duration" = pre }, - .@"transition-delay" => .{ .@"transition-delay" = pre }, - .@"transition-timing-function" => .{ .@"transition-timing-function" = pre }, - .transition => .{ .transition = pre }, - .transform => .{ .transform = pre }, - .@"transform-origin" => .{ .@"transform-origin" = pre }, - .@"transform-style" => .{ .@"transform-style" = pre }, - .@"transform-box" => .@"transform-box", - .@"backface-visibility" => .{ .@"backface-visibility" = pre }, - .perspective => .{ .perspective = pre }, - .@"perspective-origin" => .{ .@"perspective-origin" = pre }, - .translate => .translate, - .rotate => .rotate, - .scale => .scale, - .@"text-decoration-color" => .{ .@"text-decoration-color" = pre }, - .@"text-emphasis-color" => .{ .@"text-emphasis-color" = pre }, - .@"text-shadow" => .@"text-shadow", - .direction => .direction, - .composes => .composes, - .@"mask-image" => .{ .@"mask-image" = pre }, - .@"mask-mode" => .@"mask-mode", - .@"mask-repeat" => .{ .@"mask-repeat" = pre }, - .@"mask-position-x" => .@"mask-position-x", - .@"mask-position-y" => .@"mask-position-y", - .@"mask-position" => .{ .@"mask-position" = pre }, - .@"mask-clip" => .{ .@"mask-clip" = pre }, - .@"mask-origin" => .{ .@"mask-origin" = pre }, - .@"mask-size" => .{ .@"mask-size" = pre }, - .@"mask-composite" => .@"mask-composite", - .@"mask-type" => .@"mask-type", - .mask => .{ .mask = pre }, - .@"mask-border-source" => .@"mask-border-source", - .@"mask-border-mode" => .@"mask-border-mode", - .@"mask-border-slice" => .@"mask-border-slice", - .@"mask-border-width" => .@"mask-border-width", - .@"mask-border-outset" => .@"mask-border-outset", - .@"mask-border-repeat" => .@"mask-border-repeat", - .@"mask-border" => .@"mask-border", - .@"-webkit-mask-composite" => .@"-webkit-mask-composite", - .@"mask-source-type" => .{ .@"mask-source-type" = pre }, - .@"mask-box-image" => .{ .@"mask-box-image" = pre }, - .@"mask-box-image-source" => .{ .@"mask-box-image-source" = pre }, - .@"mask-box-image-slice" => .{ .@"mask-box-image-slice" = pre }, - .@"mask-box-image-width" => .{ .@"mask-box-image-width" = pre }, - .@"mask-box-image-outset" => .{ .@"mask-box-image-outset" = pre }, - .@"mask-box-image-repeat" => .{ .@"mask-box-image-repeat" = pre }, - .@"color-scheme" => .@"color-scheme", - else => this.*, - }; - } - - pub fn addPrefix(this: *PropertyId, pre: VendorPrefix) void { - return switch (this.*) { - inline else => |*p| { - switch (@TypeOf(p)) { - *void, *CustomPropertyName => {}, - *VendorPrefix => bits.insert(VendorPrefix, p, pre), - else => |T| @compileError("unexpected " ++ @typeName(T)), - } - }, - }; - } - - pub inline fn deepClone(this: *const PropertyId, _: std.mem.Allocator) PropertyId { - return this.*; - } - - pub fn eql(lhs: *const PropertyId, rhs: *const PropertyId) bool { - if (@intFromEnum(lhs.*) != @intFromEnum(rhs.*)) return false; - inline for (bun.meta.EnumFields(PropertyId), std.meta.fields(PropertyId)) |enum_field, union_field| { - if (enum_field.value == @intFromEnum(lhs.*)) { - if (comptime union_field.type == css.VendorPrefix) { - return @field(lhs, union_field.name) == @field(rhs, union_field.name); - } else { - return true; - } - } - } - unreachable; - } - - pub fn hash(this: *const PropertyId, hasher: *std.hash.Wyhash) void { - const tag = @intFromEnum(this.*); - hasher.update(std.mem.asBytes(&tag)); - } - - pub fn setPrefixesForTargets(this: *PropertyId, targets: Targets) void { - switch (this.*) { - .@"background-color" => {}, - .@"background-image" => {}, - .@"background-position-x" => {}, - .@"background-position-y" => {}, - .@"background-position" => {}, - .@"background-size" => {}, - .@"background-repeat" => {}, - .@"background-attachment" => {}, - .@"background-clip" => |*x| { - x.* = targets.prefixes(x.*, Feature.background_clip); - }, - - .@"background-origin" => {}, - .background => {}, - .@"box-shadow" => |*x| { - x.* = targets.prefixes(x.*, Feature.box_shadow); - }, - - .opacity => {}, - .color => {}, - .display => {}, - .visibility => {}, - .width => {}, - .height => {}, - .@"min-width" => {}, - .@"min-height" => {}, - .@"max-width" => {}, - .@"max-height" => {}, - .@"block-size" => {}, - .@"inline-size" => {}, - .@"min-block-size" => {}, - .@"min-inline-size" => {}, - .@"max-block-size" => {}, - .@"max-inline-size" => {}, - .@"box-sizing" => |*x| { - x.* = targets.prefixes(x.*, Feature.box_sizing); - }, - - .@"aspect-ratio" => {}, - .overflow => {}, - .@"overflow-x" => {}, - .@"overflow-y" => {}, - .@"text-overflow" => |*x| { - x.* = targets.prefixes(x.*, Feature.text_overflow); - }, - - .position => {}, - .top => {}, - .bottom => {}, - .left => {}, - .right => {}, - .@"inset-block-start" => {}, - .@"inset-block-end" => {}, - .@"inset-inline-start" => {}, - .@"inset-inline-end" => {}, - .@"inset-block" => {}, - .@"inset-inline" => {}, - .inset => {}, - .@"border-spacing" => {}, - .@"border-top-color" => {}, - .@"border-bottom-color" => {}, - .@"border-left-color" => {}, - .@"border-right-color" => {}, - .@"border-block-start-color" => {}, - .@"border-block-end-color" => {}, - .@"border-inline-start-color" => {}, - .@"border-inline-end-color" => {}, - .@"border-top-style" => {}, - .@"border-bottom-style" => {}, - .@"border-left-style" => {}, - .@"border-right-style" => {}, - .@"border-block-start-style" => {}, - .@"border-block-end-style" => {}, - .@"border-inline-start-style" => {}, - .@"border-inline-end-style" => {}, - .@"border-top-width" => {}, - .@"border-bottom-width" => {}, - .@"border-left-width" => {}, - .@"border-right-width" => {}, - .@"border-block-start-width" => {}, - .@"border-block-end-width" => {}, - .@"border-inline-start-width" => {}, - .@"border-inline-end-width" => {}, - .@"border-top-left-radius" => |*x| { - x.* = targets.prefixes(x.*, Feature.border_top_left_radius); - }, - - .@"border-top-right-radius" => |*x| { - x.* = targets.prefixes(x.*, Feature.border_top_right_radius); - }, - - .@"border-bottom-left-radius" => |*x| { - x.* = targets.prefixes(x.*, Feature.border_bottom_left_radius); - }, - - .@"border-bottom-right-radius" => |*x| { - x.* = targets.prefixes(x.*, Feature.border_bottom_right_radius); - }, - - .@"border-start-start-radius" => {}, - .@"border-start-end-radius" => {}, - .@"border-end-start-radius" => {}, - .@"border-end-end-radius" => {}, - .@"border-radius" => |*x| { - x.* = targets.prefixes(x.*, Feature.border_radius); - }, - - .@"border-image-source" => {}, - .@"border-image-outset" => {}, - .@"border-image-repeat" => {}, - .@"border-image-width" => {}, - .@"border-image-slice" => {}, - .@"border-image" => |*x| { - x.* = targets.prefixes(x.*, Feature.border_image); - }, - - .@"border-color" => {}, - .@"border-style" => {}, - .@"border-width" => {}, - .@"border-block-color" => {}, - .@"border-block-style" => {}, - .@"border-block-width" => {}, - .@"border-inline-color" => {}, - .@"border-inline-style" => {}, - .@"border-inline-width" => {}, - .border => {}, - .@"border-top" => {}, - .@"border-bottom" => {}, - .@"border-left" => {}, - .@"border-right" => {}, - .@"border-block" => {}, - .@"border-block-start" => {}, - .@"border-block-end" => {}, - .@"border-inline" => {}, - .@"border-inline-start" => {}, - .@"border-inline-end" => {}, - .outline => {}, - .@"outline-color" => {}, - .@"outline-style" => {}, - .@"outline-width" => {}, - .@"flex-direction" => |*x| { - x.* = targets.prefixes(x.*, Feature.flex_direction); - }, - - .@"flex-wrap" => |*x| { - x.* = targets.prefixes(x.*, Feature.flex_wrap); - }, - - .@"flex-flow" => |*x| { - x.* = targets.prefixes(x.*, Feature.flex_flow); - }, - - .@"flex-grow" => |*x| { - x.* = targets.prefixes(x.*, Feature.flex_grow); - }, - - .@"flex-shrink" => |*x| { - x.* = targets.prefixes(x.*, Feature.flex_shrink); - }, - - .@"flex-basis" => |*x| { - x.* = targets.prefixes(x.*, Feature.flex_basis); - }, - - .flex => |*x| { - x.* = targets.prefixes(x.*, Feature.flex); - }, - - .order => |*x| { - x.* = targets.prefixes(x.*, Feature.order); - }, - - .@"align-content" => |*x| { - x.* = targets.prefixes(x.*, Feature.align_content); - }, - - .@"justify-content" => |*x| { - x.* = targets.prefixes(x.*, Feature.justify_content); - }, - - .@"place-content" => {}, - .@"align-self" => |*x| { - x.* = targets.prefixes(x.*, Feature.align_self); - }, - - .@"justify-self" => {}, - .@"place-self" => {}, - .@"align-items" => |*x| { - x.* = targets.prefixes(x.*, Feature.align_items); - }, - - .@"justify-items" => {}, - .@"place-items" => {}, - .@"row-gap" => {}, - .@"column-gap" => {}, - .gap => {}, - .@"box-orient" => {}, - .@"box-direction" => {}, - .@"box-ordinal-group" => {}, - .@"box-align" => {}, - .@"box-flex" => {}, - .@"box-flex-group" => {}, - .@"box-pack" => {}, - .@"box-lines" => {}, - .@"flex-pack" => {}, - .@"flex-order" => {}, - .@"flex-align" => {}, - .@"flex-item-align" => {}, - .@"flex-line-pack" => {}, - .@"flex-positive" => {}, - .@"flex-negative" => {}, - .@"flex-preferred-size" => {}, - .@"margin-top" => {}, - .@"margin-bottom" => {}, - .@"margin-left" => {}, - .@"margin-right" => {}, - .@"margin-block-start" => {}, - .@"margin-block-end" => {}, - .@"margin-inline-start" => {}, - .@"margin-inline-end" => {}, - .@"margin-block" => {}, - .@"margin-inline" => {}, - .margin => {}, - .@"padding-top" => {}, - .@"padding-bottom" => {}, - .@"padding-left" => {}, - .@"padding-right" => {}, - .@"padding-block-start" => {}, - .@"padding-block-end" => {}, - .@"padding-inline-start" => {}, - .@"padding-inline-end" => {}, - .@"padding-block" => {}, - .@"padding-inline" => {}, - .padding => {}, - .@"scroll-margin-top" => {}, - .@"scroll-margin-bottom" => {}, - .@"scroll-margin-left" => {}, - .@"scroll-margin-right" => {}, - .@"scroll-margin-block-start" => {}, - .@"scroll-margin-block-end" => {}, - .@"scroll-margin-inline-start" => {}, - .@"scroll-margin-inline-end" => {}, - .@"scroll-margin-block" => {}, - .@"scroll-margin-inline" => {}, - .@"scroll-margin" => {}, - .@"scroll-padding-top" => {}, - .@"scroll-padding-bottom" => {}, - .@"scroll-padding-left" => {}, - .@"scroll-padding-right" => {}, - .@"scroll-padding-block-start" => {}, - .@"scroll-padding-block-end" => {}, - .@"scroll-padding-inline-start" => {}, - .@"scroll-padding-inline-end" => {}, - .@"scroll-padding-block" => {}, - .@"scroll-padding-inline" => {}, - .@"scroll-padding" => {}, - .@"font-weight" => {}, - .@"font-size" => {}, - .@"font-stretch" => {}, - .@"font-family" => {}, - .@"font-style" => {}, - .@"font-variant-caps" => {}, - .@"line-height" => {}, - .font => {}, - .@"transition-property" => |*x| { - x.* = targets.prefixes(x.*, Feature.transition_property); - }, - - .@"transition-duration" => |*x| { - x.* = targets.prefixes(x.*, Feature.transition_duration); - }, - - .@"transition-delay" => |*x| { - x.* = targets.prefixes(x.*, Feature.transition_delay); - }, - - .@"transition-timing-function" => |*x| { - x.* = targets.prefixes(x.*, Feature.transition_timing_function); - }, - - .transition => |*x| { - x.* = targets.prefixes(x.*, Feature.transition); - }, - - .transform => |*x| { - x.* = targets.prefixes(x.*, Feature.transform); - }, - - .@"transform-origin" => |*x| { - x.* = targets.prefixes(x.*, Feature.transform_origin); - }, - - .@"transform-style" => |*x| { - x.* = targets.prefixes(x.*, Feature.transform_style); - }, - - .@"transform-box" => {}, - .@"backface-visibility" => |*x| { - x.* = targets.prefixes(x.*, Feature.backface_visibility); - }, - - .perspective => |*x| { - x.* = targets.prefixes(x.*, Feature.perspective); - }, - - .@"perspective-origin" => |*x| { - x.* = targets.prefixes(x.*, Feature.perspective_origin); - }, - - .translate => {}, - .rotate => {}, - .scale => {}, - .@"text-decoration-color" => |*x| { - x.* = targets.prefixes(x.*, Feature.text_decoration_color); - }, - - .@"text-emphasis-color" => |*x| { - x.* = targets.prefixes(x.*, Feature.text_emphasis_color); - }, - - .@"text-shadow" => {}, - .direction => {}, - .composes => {}, - .@"mask-image" => |*x| { - x.* = targets.prefixes(x.*, Feature.mask_image); - }, - - .@"mask-mode" => {}, - .@"mask-repeat" => |*x| { - x.* = targets.prefixes(x.*, Feature.mask_repeat); - }, - - .@"mask-position-x" => {}, - .@"mask-position-y" => {}, - .@"mask-position" => |*x| { - x.* = targets.prefixes(x.*, Feature.mask_position); - }, - - .@"mask-clip" => |*x| { - x.* = targets.prefixes(x.*, Feature.mask_clip); - }, - - .@"mask-origin" => |*x| { - x.* = targets.prefixes(x.*, Feature.mask_origin); - }, - - .@"mask-size" => |*x| { - x.* = targets.prefixes(x.*, Feature.mask_size); - }, - - .@"mask-composite" => {}, - .@"mask-type" => {}, - .mask => |*x| { - x.* = targets.prefixes(x.*, Feature.mask); - }, - - .@"mask-border-source" => {}, - .@"mask-border-mode" => {}, - .@"mask-border-slice" => {}, - .@"mask-border-width" => {}, - .@"mask-border-outset" => {}, - .@"mask-border-repeat" => {}, - .@"mask-border" => {}, - .@"-webkit-mask-composite" => {}, - .@"mask-source-type" => {}, - .@"mask-box-image" => {}, - .@"mask-box-image-source" => {}, - .@"mask-box-image-slice" => {}, - .@"mask-box-image-width" => {}, - .@"mask-box-image-outset" => {}, - .@"mask-box-image-repeat" => {}, - .@"color-scheme" => {}, - else => {}, - } - } -}; -pub const PropertyIdTag = enum(u16) { - @"background-color", - @"background-image", - @"background-position-x", - @"background-position-y", - @"background-position", - @"background-size", - @"background-repeat", - @"background-attachment", - @"background-clip", - @"background-origin", - background, - @"box-shadow", - opacity, - color, - display, - visibility, - width, - height, - @"min-width", - @"min-height", - @"max-width", - @"max-height", - @"block-size", - @"inline-size", - @"min-block-size", - @"min-inline-size", - @"max-block-size", - @"max-inline-size", - @"box-sizing", - @"aspect-ratio", - overflow, - @"overflow-x", - @"overflow-y", - @"text-overflow", - position, - top, - bottom, - left, - right, - @"inset-block-start", - @"inset-block-end", - @"inset-inline-start", - @"inset-inline-end", - @"inset-block", - @"inset-inline", - inset, - @"border-spacing", - @"border-top-color", - @"border-bottom-color", - @"border-left-color", - @"border-right-color", - @"border-block-start-color", - @"border-block-end-color", - @"border-inline-start-color", - @"border-inline-end-color", - @"border-top-style", - @"border-bottom-style", - @"border-left-style", - @"border-right-style", - @"border-block-start-style", - @"border-block-end-style", - @"border-inline-start-style", - @"border-inline-end-style", - @"border-top-width", - @"border-bottom-width", - @"border-left-width", - @"border-right-width", - @"border-block-start-width", - @"border-block-end-width", - @"border-inline-start-width", - @"border-inline-end-width", - @"border-top-left-radius", - @"border-top-right-radius", - @"border-bottom-left-radius", - @"border-bottom-right-radius", - @"border-start-start-radius", - @"border-start-end-radius", - @"border-end-start-radius", - @"border-end-end-radius", - @"border-radius", - @"border-image-source", - @"border-image-outset", - @"border-image-repeat", - @"border-image-width", - @"border-image-slice", - @"border-image", - @"border-color", - @"border-style", - @"border-width", - @"border-block-color", - @"border-block-style", - @"border-block-width", - @"border-inline-color", - @"border-inline-style", - @"border-inline-width", - border, - @"border-top", - @"border-bottom", - @"border-left", - @"border-right", - @"border-block", - @"border-block-start", - @"border-block-end", - @"border-inline", - @"border-inline-start", - @"border-inline-end", - outline, - @"outline-color", - @"outline-style", - @"outline-width", - @"flex-direction", - @"flex-wrap", - @"flex-flow", - @"flex-grow", - @"flex-shrink", - @"flex-basis", - flex, - order, - @"align-content", - @"justify-content", - @"place-content", - @"align-self", - @"justify-self", - @"place-self", - @"align-items", - @"justify-items", - @"place-items", - @"row-gap", - @"column-gap", - gap, - @"box-orient", - @"box-direction", - @"box-ordinal-group", - @"box-align", - @"box-flex", - @"box-flex-group", - @"box-pack", - @"box-lines", - @"flex-pack", - @"flex-order", - @"flex-align", - @"flex-item-align", - @"flex-line-pack", - @"flex-positive", - @"flex-negative", - @"flex-preferred-size", - @"margin-top", - @"margin-bottom", - @"margin-left", - @"margin-right", - @"margin-block-start", - @"margin-block-end", - @"margin-inline-start", - @"margin-inline-end", - @"margin-block", - @"margin-inline", - margin, - @"padding-top", - @"padding-bottom", - @"padding-left", - @"padding-right", - @"padding-block-start", - @"padding-block-end", - @"padding-inline-start", - @"padding-inline-end", - @"padding-block", - @"padding-inline", - padding, - @"scroll-margin-top", - @"scroll-margin-bottom", - @"scroll-margin-left", - @"scroll-margin-right", - @"scroll-margin-block-start", - @"scroll-margin-block-end", - @"scroll-margin-inline-start", - @"scroll-margin-inline-end", - @"scroll-margin-block", - @"scroll-margin-inline", - @"scroll-margin", - @"scroll-padding-top", - @"scroll-padding-bottom", - @"scroll-padding-left", - @"scroll-padding-right", - @"scroll-padding-block-start", - @"scroll-padding-block-end", - @"scroll-padding-inline-start", - @"scroll-padding-inline-end", - @"scroll-padding-block", - @"scroll-padding-inline", - @"scroll-padding", - @"font-weight", - @"font-size", - @"font-stretch", - @"font-family", - @"font-style", - @"font-variant-caps", - @"line-height", - font, - @"transition-property", - @"transition-duration", - @"transition-delay", - @"transition-timing-function", - transition, - transform, - @"transform-origin", - @"transform-style", - @"transform-box", - @"backface-visibility", - perspective, - @"perspective-origin", - translate, - rotate, - scale, - @"text-decoration-color", - @"text-emphasis-color", - @"text-shadow", - direction, - composes, - @"mask-image", - @"mask-mode", - @"mask-repeat", - @"mask-position-x", - @"mask-position-y", - @"mask-position", - @"mask-clip", - @"mask-origin", - @"mask-size", - @"mask-composite", - @"mask-type", - mask, - @"mask-border-source", - @"mask-border-mode", - @"mask-border-slice", - @"mask-border-width", - @"mask-border-outset", - @"mask-border-repeat", - @"mask-border", - @"-webkit-mask-composite", - @"mask-source-type", - @"mask-box-image", - @"mask-box-image-source", - @"mask-box-image-slice", - @"mask-box-image-width", - @"mask-box-image-outset", - @"mask-box-image-repeat", - @"color-scheme", - all, - unparsed, - custom, - - /// Helper function used in comptime code to know whether to access the underlying value - /// with tuple indexing syntax because it may have a VendorPrefix associated with it. - pub fn hasVendorPrefix(this: PropertyIdTag) bool { - return switch (this) { - .@"background-color" => false, - .@"background-image" => false, - .@"background-position-x" => false, - .@"background-position-y" => false, - .@"background-position" => false, - .@"background-size" => false, - .@"background-repeat" => false, - .@"background-attachment" => false, - .@"background-clip" => true, - .@"background-origin" => false, - .background => false, - .@"box-shadow" => true, - .opacity => false, - .color => false, - .display => false, - .visibility => false, - .width => false, - .height => false, - .@"min-width" => false, - .@"min-height" => false, - .@"max-width" => false, - .@"max-height" => false, - .@"block-size" => false, - .@"inline-size" => false, - .@"min-block-size" => false, - .@"min-inline-size" => false, - .@"max-block-size" => false, - .@"max-inline-size" => false, - .@"box-sizing" => true, - .@"aspect-ratio" => false, - .overflow => false, - .@"overflow-x" => false, - .@"overflow-y" => false, - .@"text-overflow" => true, - .position => false, - .top => false, - .bottom => false, - .left => false, - .right => false, - .@"inset-block-start" => false, - .@"inset-block-end" => false, - .@"inset-inline-start" => false, - .@"inset-inline-end" => false, - .@"inset-block" => false, - .@"inset-inline" => false, - .inset => false, - .@"border-spacing" => false, - .@"border-top-color" => false, - .@"border-bottom-color" => false, - .@"border-left-color" => false, - .@"border-right-color" => false, - .@"border-block-start-color" => false, - .@"border-block-end-color" => false, - .@"border-inline-start-color" => false, - .@"border-inline-end-color" => false, - .@"border-top-style" => false, - .@"border-bottom-style" => false, - .@"border-left-style" => false, - .@"border-right-style" => false, - .@"border-block-start-style" => false, - .@"border-block-end-style" => false, - .@"border-inline-start-style" => false, - .@"border-inline-end-style" => false, - .@"border-top-width" => false, - .@"border-bottom-width" => false, - .@"border-left-width" => false, - .@"border-right-width" => false, - .@"border-block-start-width" => false, - .@"border-block-end-width" => false, - .@"border-inline-start-width" => false, - .@"border-inline-end-width" => false, - .@"border-top-left-radius" => true, - .@"border-top-right-radius" => true, - .@"border-bottom-left-radius" => true, - .@"border-bottom-right-radius" => true, - .@"border-start-start-radius" => false, - .@"border-start-end-radius" => false, - .@"border-end-start-radius" => false, - .@"border-end-end-radius" => false, - .@"border-radius" => true, - .@"border-image-source" => false, - .@"border-image-outset" => false, - .@"border-image-repeat" => false, - .@"border-image-width" => false, - .@"border-image-slice" => false, - .@"border-image" => true, - .@"border-color" => false, - .@"border-style" => false, - .@"border-width" => false, - .@"border-block-color" => false, - .@"border-block-style" => false, - .@"border-block-width" => false, - .@"border-inline-color" => false, - .@"border-inline-style" => false, - .@"border-inline-width" => false, - .border => false, - .@"border-top" => false, - .@"border-bottom" => false, - .@"border-left" => false, - .@"border-right" => false, - .@"border-block" => false, - .@"border-block-start" => false, - .@"border-block-end" => false, - .@"border-inline" => false, - .@"border-inline-start" => false, - .@"border-inline-end" => false, - .outline => false, - .@"outline-color" => false, - .@"outline-style" => false, - .@"outline-width" => false, - .@"flex-direction" => true, - .@"flex-wrap" => true, - .@"flex-flow" => true, - .@"flex-grow" => true, - .@"flex-shrink" => true, - .@"flex-basis" => true, - .flex => true, - .order => true, - .@"align-content" => true, - .@"justify-content" => true, - .@"place-content" => false, - .@"align-self" => true, - .@"justify-self" => false, - .@"place-self" => false, - .@"align-items" => true, - .@"justify-items" => false, - .@"place-items" => false, - .@"row-gap" => false, - .@"column-gap" => false, - .gap => false, - .@"box-orient" => true, - .@"box-direction" => true, - .@"box-ordinal-group" => true, - .@"box-align" => true, - .@"box-flex" => true, - .@"box-flex-group" => true, - .@"box-pack" => true, - .@"box-lines" => true, - .@"flex-pack" => true, - .@"flex-order" => true, - .@"flex-align" => true, - .@"flex-item-align" => true, - .@"flex-line-pack" => true, - .@"flex-positive" => true, - .@"flex-negative" => true, - .@"flex-preferred-size" => true, - .@"margin-top" => false, - .@"margin-bottom" => false, - .@"margin-left" => false, - .@"margin-right" => false, - .@"margin-block-start" => false, - .@"margin-block-end" => false, - .@"margin-inline-start" => false, - .@"margin-inline-end" => false, - .@"margin-block" => false, - .@"margin-inline" => false, - .margin => false, - .@"padding-top" => false, - .@"padding-bottom" => false, - .@"padding-left" => false, - .@"padding-right" => false, - .@"padding-block-start" => false, - .@"padding-block-end" => false, - .@"padding-inline-start" => false, - .@"padding-inline-end" => false, - .@"padding-block" => false, - .@"padding-inline" => false, - .padding => false, - .@"scroll-margin-top" => false, - .@"scroll-margin-bottom" => false, - .@"scroll-margin-left" => false, - .@"scroll-margin-right" => false, - .@"scroll-margin-block-start" => false, - .@"scroll-margin-block-end" => false, - .@"scroll-margin-inline-start" => false, - .@"scroll-margin-inline-end" => false, - .@"scroll-margin-block" => false, - .@"scroll-margin-inline" => false, - .@"scroll-margin" => false, - .@"scroll-padding-top" => false, - .@"scroll-padding-bottom" => false, - .@"scroll-padding-left" => false, - .@"scroll-padding-right" => false, - .@"scroll-padding-block-start" => false, - .@"scroll-padding-block-end" => false, - .@"scroll-padding-inline-start" => false, - .@"scroll-padding-inline-end" => false, - .@"scroll-padding-block" => false, - .@"scroll-padding-inline" => false, - .@"scroll-padding" => false, - .@"font-weight" => false, - .@"font-size" => false, - .@"font-stretch" => false, - .@"font-family" => false, - .@"font-style" => false, - .@"font-variant-caps" => false, - .@"line-height" => false, - .font => false, - .@"transition-property" => true, - .@"transition-duration" => true, - .@"transition-delay" => true, - .@"transition-timing-function" => true, - .transition => true, - .transform => true, - .@"transform-origin" => true, - .@"transform-style" => true, - .@"transform-box" => false, - .@"backface-visibility" => true, - .perspective => true, - .@"perspective-origin" => true, - .translate => false, - .rotate => false, - .scale => false, - .@"text-decoration-color" => true, - .@"text-emphasis-color" => true, - .@"text-shadow" => false, - .direction => false, - .composes => false, - .@"mask-image" => true, - .@"mask-mode" => false, - .@"mask-repeat" => true, - .@"mask-position-x" => false, - .@"mask-position-y" => false, - .@"mask-position" => true, - .@"mask-clip" => true, - .@"mask-origin" => true, - .@"mask-size" => true, - .@"mask-composite" => false, - .@"mask-type" => false, - .mask => true, - .@"mask-border-source" => false, - .@"mask-border-mode" => false, - .@"mask-border-slice" => false, - .@"mask-border-width" => false, - .@"mask-border-outset" => false, - .@"mask-border-repeat" => false, - .@"mask-border" => false, - .@"-webkit-mask-composite" => false, - .@"mask-source-type" => true, - .@"mask-box-image" => true, - .@"mask-box-image-source" => true, - .@"mask-box-image-slice" => true, - .@"mask-box-image-width" => true, - .@"mask-box-image-outset" => true, - .@"mask-box-image-repeat" => true, - .@"color-scheme" => false, - .unparsed => false, - .custom => false, - .all => false, - }; - } - - /// Helper function used in comptime code to know whether to access the underlying value - /// with tuple indexing syntax because it may have a VendorPrefix associated with it. - pub fn valueType(this: PropertyIdTag) type { - return switch (this) { - .@"background-color" => CssColor, - .@"background-image" => SmallList(Image, 1), - .@"background-position-x" => SmallList(css_values.position.HorizontalPosition, 1), - .@"background-position-y" => SmallList(css_values.position.VerticalPosition, 1), - .@"background-position" => SmallList(background.BackgroundPosition, 1), - .@"background-size" => SmallList(background.BackgroundSize, 1), - .@"background-repeat" => SmallList(background.BackgroundRepeat, 1), - .@"background-attachment" => SmallList(background.BackgroundAttachment, 1), - .@"background-clip" => SmallList(background.BackgroundClip, 1), - .@"background-origin" => SmallList(background.BackgroundOrigin, 1), - .background => SmallList(background.Background, 1), - .@"box-shadow" => SmallList(box_shadow.BoxShadow, 1), - .opacity => css.css_values.alpha.AlphaValue, - .color => CssColor, - .display => display.Display, - .visibility => display.Visibility, - .width => size.Size, - .height => size.Size, - .@"min-width" => size.Size, - .@"min-height" => size.Size, - .@"max-width" => size.MaxSize, - .@"max-height" => size.MaxSize, - .@"block-size" => size.Size, - .@"inline-size" => size.Size, - .@"min-block-size" => size.Size, - .@"min-inline-size" => size.Size, - .@"max-block-size" => size.MaxSize, - .@"max-inline-size" => size.MaxSize, - .@"box-sizing" => size.BoxSizing, - .@"aspect-ratio" => size.AspectRatio, - .overflow => overflow.Overflow, - .@"overflow-x" => overflow.OverflowKeyword, - .@"overflow-y" => overflow.OverflowKeyword, - .@"text-overflow" => overflow.TextOverflow, - .position => position.Position, - .top => LengthPercentageOrAuto, - .bottom => LengthPercentageOrAuto, - .left => LengthPercentageOrAuto, - .right => LengthPercentageOrAuto, - .@"inset-block-start" => LengthPercentageOrAuto, - .@"inset-block-end" => LengthPercentageOrAuto, - .@"inset-inline-start" => LengthPercentageOrAuto, - .@"inset-inline-end" => LengthPercentageOrAuto, - .@"inset-block" => margin_padding.InsetBlock, - .@"inset-inline" => margin_padding.InsetInline, - .inset => margin_padding.Inset, - .@"border-spacing" => css.css_values.size.Size2D(Length), - .@"border-top-color" => CssColor, - .@"border-bottom-color" => CssColor, - .@"border-left-color" => CssColor, - .@"border-right-color" => CssColor, - .@"border-block-start-color" => CssColor, - .@"border-block-end-color" => CssColor, - .@"border-inline-start-color" => CssColor, - .@"border-inline-end-color" => CssColor, - .@"border-top-style" => border.LineStyle, - .@"border-bottom-style" => border.LineStyle, - .@"border-left-style" => border.LineStyle, - .@"border-right-style" => border.LineStyle, - .@"border-block-start-style" => border.LineStyle, - .@"border-block-end-style" => border.LineStyle, - .@"border-inline-start-style" => border.LineStyle, - .@"border-inline-end-style" => border.LineStyle, - .@"border-top-width" => BorderSideWidth, - .@"border-bottom-width" => BorderSideWidth, - .@"border-left-width" => BorderSideWidth, - .@"border-right-width" => BorderSideWidth, - .@"border-block-start-width" => BorderSideWidth, - .@"border-block-end-width" => BorderSideWidth, - .@"border-inline-start-width" => BorderSideWidth, - .@"border-inline-end-width" => BorderSideWidth, - .@"border-top-left-radius" => Size2D(LengthPercentage), - .@"border-top-right-radius" => Size2D(LengthPercentage), - .@"border-bottom-left-radius" => Size2D(LengthPercentage), - .@"border-bottom-right-radius" => Size2D(LengthPercentage), - .@"border-start-start-radius" => Size2D(LengthPercentage), - .@"border-start-end-radius" => Size2D(LengthPercentage), - .@"border-end-start-radius" => Size2D(LengthPercentage), - .@"border-end-end-radius" => Size2D(LengthPercentage), - .@"border-radius" => BorderRadius, - .@"border-image-source" => Image, - .@"border-image-outset" => Rect(LengthOrNumber), - .@"border-image-repeat" => BorderImageRepeat, - .@"border-image-width" => Rect(BorderImageSideWidth), - .@"border-image-slice" => BorderImageSlice, - .@"border-image" => BorderImage, - .@"border-color" => BorderColor, - .@"border-style" => BorderStyle, - .@"border-width" => BorderWidth, - .@"border-block-color" => BorderBlockColor, - .@"border-block-style" => BorderBlockStyle, - .@"border-block-width" => BorderBlockWidth, - .@"border-inline-color" => BorderInlineColor, - .@"border-inline-style" => BorderInlineStyle, - .@"border-inline-width" => BorderInlineWidth, - .border => Border, - .@"border-top" => BorderTop, - .@"border-bottom" => BorderBottom, - .@"border-left" => BorderLeft, - .@"border-right" => BorderRight, - .@"border-block" => BorderBlock, - .@"border-block-start" => BorderBlockStart, - .@"border-block-end" => BorderBlockEnd, - .@"border-inline" => BorderInline, - .@"border-inline-start" => BorderInlineStart, - .@"border-inline-end" => BorderInlineEnd, - .outline => Outline, - .@"outline-color" => CssColor, - .@"outline-style" => OutlineStyle, - .@"outline-width" => BorderSideWidth, - .@"flex-direction" => FlexDirection, - .@"flex-wrap" => FlexWrap, - .@"flex-flow" => FlexFlow, - .@"flex-grow" => CSSNumber, - .@"flex-shrink" => CSSNumber, - .@"flex-basis" => LengthPercentageOrAuto, - .flex => Flex, - .order => CSSInteger, - .@"align-content" => AlignContent, - .@"justify-content" => JustifyContent, - .@"place-content" => PlaceContent, - .@"align-self" => AlignSelf, - .@"justify-self" => JustifySelf, - .@"place-self" => PlaceSelf, - .@"align-items" => AlignItems, - .@"justify-items" => JustifyItems, - .@"place-items" => PlaceItems, - .@"row-gap" => GapValue, - .@"column-gap" => GapValue, - .gap => Gap, - .@"box-orient" => BoxOrient, - .@"box-direction" => BoxDirection, - .@"box-ordinal-group" => CSSInteger, - .@"box-align" => BoxAlign, - .@"box-flex" => CSSNumber, - .@"box-flex-group" => CSSInteger, - .@"box-pack" => BoxPack, - .@"box-lines" => BoxLines, - .@"flex-pack" => FlexPack, - .@"flex-order" => CSSInteger, - .@"flex-align" => BoxAlign, - .@"flex-item-align" => FlexItemAlign, - .@"flex-line-pack" => FlexLinePack, - .@"flex-positive" => CSSNumber, - .@"flex-negative" => CSSNumber, - .@"flex-preferred-size" => LengthPercentageOrAuto, - .@"margin-top" => LengthPercentageOrAuto, - .@"margin-bottom" => LengthPercentageOrAuto, - .@"margin-left" => LengthPercentageOrAuto, - .@"margin-right" => LengthPercentageOrAuto, - .@"margin-block-start" => LengthPercentageOrAuto, - .@"margin-block-end" => LengthPercentageOrAuto, - .@"margin-inline-start" => LengthPercentageOrAuto, - .@"margin-inline-end" => LengthPercentageOrAuto, - .@"margin-block" => MarginBlock, - .@"margin-inline" => MarginInline, - .margin => Margin, - .@"padding-top" => LengthPercentageOrAuto, - .@"padding-bottom" => LengthPercentageOrAuto, - .@"padding-left" => LengthPercentageOrAuto, - .@"padding-right" => LengthPercentageOrAuto, - .@"padding-block-start" => LengthPercentageOrAuto, - .@"padding-block-end" => LengthPercentageOrAuto, - .@"padding-inline-start" => LengthPercentageOrAuto, - .@"padding-inline-end" => LengthPercentageOrAuto, - .@"padding-block" => PaddingBlock, - .@"padding-inline" => PaddingInline, - .padding => Padding, - .@"scroll-margin-top" => LengthPercentageOrAuto, - .@"scroll-margin-bottom" => LengthPercentageOrAuto, - .@"scroll-margin-left" => LengthPercentageOrAuto, - .@"scroll-margin-right" => LengthPercentageOrAuto, - .@"scroll-margin-block-start" => LengthPercentageOrAuto, - .@"scroll-margin-block-end" => LengthPercentageOrAuto, - .@"scroll-margin-inline-start" => LengthPercentageOrAuto, - .@"scroll-margin-inline-end" => LengthPercentageOrAuto, - .@"scroll-margin-block" => ScrollMarginBlock, - .@"scroll-margin-inline" => ScrollMarginInline, - .@"scroll-margin" => ScrollMargin, - .@"scroll-padding-top" => LengthPercentageOrAuto, - .@"scroll-padding-bottom" => LengthPercentageOrAuto, - .@"scroll-padding-left" => LengthPercentageOrAuto, - .@"scroll-padding-right" => LengthPercentageOrAuto, - .@"scroll-padding-block-start" => LengthPercentageOrAuto, - .@"scroll-padding-block-end" => LengthPercentageOrAuto, - .@"scroll-padding-inline-start" => LengthPercentageOrAuto, - .@"scroll-padding-inline-end" => LengthPercentageOrAuto, - .@"scroll-padding-block" => ScrollPaddingBlock, - .@"scroll-padding-inline" => ScrollPaddingInline, - .@"scroll-padding" => ScrollPadding, - .@"font-weight" => FontWeight, - .@"font-size" => FontSize, - .@"font-stretch" => FontStretch, - .@"font-family" => BabyList(FontFamily), - .@"font-style" => FontStyle, - .@"font-variant-caps" => FontVariantCaps, - .@"line-height" => LineHeight, - .font => Font, - .@"transition-property" => SmallList(PropertyId, 1), - .@"transition-duration" => SmallList(Time, 1), - .@"transition-delay" => SmallList(Time, 1), - .@"transition-timing-function" => SmallList(EasingFunction, 1), - .transition => SmallList(Transition, 1), - .transform => TransformList, - .@"transform-origin" => Position, - .@"transform-style" => TransformStyle, - .@"transform-box" => TransformBox, - .@"backface-visibility" => BackfaceVisibility, - .perspective => Perspective, - .@"perspective-origin" => Position, - .translate => Translate, - .rotate => Rotate, - .scale => Scale, - .@"text-decoration-color" => CssColor, - .@"text-emphasis-color" => CssColor, - .@"text-shadow" => SmallList(TextShadow, 1), - .direction => Direction, - .composes => Composes, - .@"mask-image" => SmallList(Image, 1), - .@"mask-mode" => SmallList(MaskMode, 1), - .@"mask-repeat" => SmallList(BackgroundRepeat, 1), - .@"mask-position-x" => SmallList(HorizontalPosition, 1), - .@"mask-position-y" => SmallList(VerticalPosition, 1), - .@"mask-position" => SmallList(Position, 1), - .@"mask-clip" => SmallList(MaskClip, 1), - .@"mask-origin" => SmallList(GeometryBox, 1), - .@"mask-size" => SmallList(BackgroundSize, 1), - .@"mask-composite" => SmallList(MaskComposite, 1), - .@"mask-type" => MaskType, - .mask => SmallList(Mask, 1), - .@"mask-border-source" => Image, - .@"mask-border-mode" => MaskBorderMode, - .@"mask-border-slice" => BorderImageSlice, - .@"mask-border-width" => Rect(BorderImageSideWidth), - .@"mask-border-outset" => Rect(LengthOrNumber), - .@"mask-border-repeat" => BorderImageRepeat, - .@"mask-border" => MaskBorder, - .@"-webkit-mask-composite" => SmallList(WebKitMaskComposite, 1), - .@"mask-source-type" => SmallList(WebKitMaskSourceType, 1), - .@"mask-box-image" => BorderImage, - .@"mask-box-image-source" => Image, - .@"mask-box-image-slice" => BorderImageSlice, - .@"mask-box-image-width" => Rect(BorderImageSideWidth), - .@"mask-box-image-outset" => Rect(LengthOrNumber), - .@"mask-box-image-repeat" => BorderImageRepeat, - .@"color-scheme" => ColorScheme, - .all => CSSWideKeyword, - .unparsed => UnparsedProperty, - .custom => CustomProperty, - }; - } -}; - -const properties_impl = @import("./properties_impl.zig"); -const std = @import("std"); -const Allocator = std.mem.Allocator; - -const bun = @import("bun"); -const BabyList = bun.BabyList; -const bits = bun.bits; diff --git a/src/css/properties/properties_impl.zig b/src/css/properties/properties_impl.zig deleted file mode 100644 index 364e828381bd..000000000000 --- a/src/css/properties/properties_impl.zig +++ /dev/null @@ -1,109 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const CustomPropertyName = css.css_properties.CustomPropertyName; - -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const VendorPrefix = css.VendorPrefix; - -const PropertyId = css.PropertyId; -const Property = css.Property; - -pub const property_id_mixin = struct { - pub fn toCss(this: *const PropertyId, dest: *Printer) PrintErr!void { - var first = true; - const name = this.name(); - const prefix_value = this.prefix().orNone(); - - inline for (VendorPrefix.FIELDS) |field| { - if (@field(prefix_value, field)) { - var prefix: VendorPrefix = .{}; - @field(prefix, field) = true; - - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - try prefix.toCss(dest); - try dest.writeStr(name); - } - } - } - - pub fn parse(input: *css.Parser) css.Result(PropertyId) { - const name = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = fromString(name) }; - } - - pub fn fromString(name_: []const u8) PropertyId { - const name_ref = name_; - var prefix: VendorPrefix = undefined; - var trimmed_name: []const u8 = undefined; - - // TODO: todo_stuff.match_ignore_ascii_case - if (bun.strings.startsWithCaseInsensitiveAscii(name_ref, "-webkit-")) { - prefix = VendorPrefix{ .webkit = true }; - trimmed_name = name_ref[8..]; - } else if (bun.strings.startsWithCaseInsensitiveAscii(name_ref, "-moz-")) { - prefix = VendorPrefix{ .moz = true }; - trimmed_name = name_ref[5..]; - } else if (bun.strings.startsWithCaseInsensitiveAscii(name_ref, "-o-")) { - prefix = VendorPrefix{ .o = true }; - trimmed_name = name_ref[3..]; - } else if (bun.strings.startsWithCaseInsensitiveAscii(name_ref, "-ms-")) { - prefix = VendorPrefix{ .ms = true }; - trimmed_name = name_ref[4..]; - } else { - prefix = VendorPrefix{ .none = true }; - trimmed_name = name_ref; - } - - return PropertyId.fromNameAndPrefix(trimmed_name, prefix) orelse .{ .custom = CustomPropertyName.fromStr(name_) }; - } -}; - -pub const property_mixin = struct { - /// Serializes the CSS property, with an optional `!important` flag. - pub fn toCss(this: *const Property, dest: *Printer, important: bool) PrintErr!void { - if (this.* == .custom) { - try this.custom.name.toCss(dest); - try dest.delim(':', false); - try this.valueToCss(dest); - if (important) { - try dest.whitespace(); - try dest.writeStr("!important"); - } - return; - } - const name, const prefix = this.__toCssHelper(); - var first = true; - - inline for (VendorPrefix.FIELDS) |field| { - if (@field(prefix, field)) { - var p: VendorPrefix = .{}; - @field(p, field) = true; - - if (first) { - first = false; - } else { - try dest.writeChar(';'); - try dest.newline(); - } - try p.toCss(dest); - try dest.writeStr(name); - try dest.delim(':', false); - try this.valueToCss(dest); - if (important) { - try dest.whitespace(); - try dest.writeStr("!important"); - } - } - } - } -}; - -const bun = @import("bun"); diff --git a/src/css/properties/shape.zig b/src/css/properties/shape.zig deleted file mode 100644 index e36e7d5cd652..000000000000 --- a/src/css/properties/shape.zig +++ /dev/null @@ -1,15 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -/// A [``](https://www.w3.org/TR/css-shapes-1/#typedef-fill-rule) used to -/// determine the interior of a `polygon()` shape. -/// -/// See [Polygon](Polygon). -pub const FillRule = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A CSS [``](https://www.w3.org/TR/css-color-4/#typedef-alpha-value), -/// used to represent opacity. -/// -/// Parses either a `` or ``, but is always stored and serialized as a number. -pub const AlphaValue = struct { - v: f32, -}; diff --git a/src/css/properties/size.zig b/src/css/properties/size.zig deleted file mode 100644 index a02d9eda28b4..000000000000 --- a/src/css/properties/size.zig +++ /dev/null @@ -1,607 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const PropertyId = css.PropertyId; -const PropertyIdTag = css.PropertyIdTag; -const Property = css.Property; -const UnparsedProperty = css.css_properties.custom.UnparsedProperty; - -const PropertyCategory = css.logical.PropertyCategory; - -const LengthPercentage = css.css_values.length.LengthPercentage; -const Ratio = css.css_values.ratio.Ratio; - -pub const BoxSizing = enum { - /// Exclude the margin/border/padding from the width and height. - @"content-box", - /// Include the padding and border (but not the margin) in the width and height. - @"border-box", - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -pub const Size = union(enum) { - /// The `auto` keyworda - auto, - /// An explicit length or percentage. - length_percentage: LengthPercentage, - /// The `min-content` keyword. - min_content: css.VendorPrefix, - /// The `max-content` keyword. - max_content: css.VendorPrefix, - /// The `fit-content` keyword. - fit_content: css.VendorPrefix, - /// The `fit-content()` function. - fit_content_function: LengthPercentage, - /// The `stretch` keyword, or the `-webkit-fill-available` or `-moz-available` prefixed keywords. - stretch: css.VendorPrefix, - /// The `contain` keyword. - contain, - - pub fn parse(input: *css.Parser) css.Result(Size) { - const Enum = enum { - auto, - @"min-content", - @"-webkit-min-content", - @"-moz-min-content", - @"max-content", - @"-webkit-max-content", - @"-moz-max-content", - stretch, - @"-webkit-fill-available", - @"-moz-available", - @"fit-content", - @"-webkit-fit-content", - @"-moz-fit-content", - contain, - }; - const Map = comptime bun.ComptimeEnumMap(Enum); - const res = input.tryParse(struct { - pub fn parseFn(i: *css.Parser) css.Result(Size) { - const ident = switch (i.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (Map.getASCIIICaseInsensitive(ident)) |res| { - return .{ .result = switch (res) { - .auto => .auto, - .@"min-content" => .{ .min_content = css.VendorPrefix{ .none = true } }, - .@"-webkit-min-content" => .{ .min_content = css.VendorPrefix{ .webkit = true } }, - .@"-moz-min-content" => .{ .min_content = css.VendorPrefix{ .moz = true } }, - .@"max-content" => .{ .max_content = css.VendorPrefix{ .none = true } }, - .@"-webkit-max-content" => .{ .max_content = css.VendorPrefix{ .webkit = true } }, - .@"-moz-max-content" => .{ .max_content = css.VendorPrefix{ .moz = true } }, - .stretch => .{ .stretch = css.VendorPrefix{ .none = true } }, - .@"-webkit-fill-available" => .{ .stretch = css.VendorPrefix{ .webkit = true } }, - .@"-moz-available" => .{ .stretch = css.VendorPrefix{ .moz = true } }, - .@"fit-content" => .{ .fit_content = css.VendorPrefix{ .none = true } }, - .@"-webkit-fit-content" => .{ .fit_content = css.VendorPrefix{ .webkit = true } }, - .@"-moz-fit-content" => .{ .fit_content = css.VendorPrefix{ .moz = true } }, - .contain => .contain, - } }; - } else return .{ .err = i.newCustomError(css.ParserError.invalid_value) }; - } - }.parseFn, .{}); - - if (res == .result) return res; - - if (input.tryParse(parseFitContent, .{}).asValue()) |v| { - return .{ .result = Size{ .fit_content_function = v } }; - } - - const lp = switch (input.tryParse(LengthPercentage.parse, .{})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = Size{ .length_percentage = lp } }; - } - - pub fn toCss(this: *const Size, dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .auto => dest.writeStr("auto"), - .contain => dest.writeStr("contain"), - .min_content => |vp| { - try vp.toCss(dest); - try dest.writeStr("min-content"); - }, - .max_content => |vp| { - try vp.toCss(dest); - try dest.writeStr("max-content"); - }, - .fit_content => |vp| { - try vp.toCss(dest); - try dest.writeStr("fit-content"); - }, - .stretch => |vp| { - if (vp == css.VendorPrefix{ .none = true }) { - try dest.writeStr("stretch"); - } else if (vp == css.VendorPrefix{ .webkit = true }) { - try dest.writeStr("-webkit-fill-available"); - } else if (vp == css.VendorPrefix{ .moz = true }) { - try dest.writeStr("-moz-available"); - } else { - bun.unreachablePanic("Unexpected vendor prefixes", .{}); - } - }, - .fit_content_function => |l| { - try dest.writeStr("fit-content("); - try l.toCss(dest); - try dest.writeChar(')'); - }, - .length_percentage => |l| return l.toCss(dest), - }; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - const F = css.compat.Feature; - return switch (this.*) { - .length_percentage => |*l| l.isCompatible(browsers), - .min_content => F.isCompatible(.min_content_size, browsers), - .max_content => F.isCompatible(.max_content_size, browsers), - .fit_content => F.isCompatible(.fit_content_size, browsers), - .fit_content_function => |*l| F.isCompatible(.fit_content_function_size, browsers) and l.isCompatible(browsers), - .stretch => |*vp| F.isCompatible(switch (vp.asBits()) { - css.VendorPrefix.NONE.asBits() => F.stretch_size, - css.VendorPrefix.WEBKIT.asBits() => F.webkit_fill_available_size, - css.VendorPrefix.MOZ.asBits() => F.moz_available_size, - else => return false, - }, browsers), - .contain => false, // ??? no data in mdn - .auto => true, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [minimum](https://drafts.csswg.org/css-sizing-3/#min-size-properties) -/// and [maximum](https://drafts.csswg.org/css-sizing-3/#max-size-properties) size properties, -/// e.g. `min-width` and `max-height`. -pub const MaxSize = union(enum) { - /// The `none` keyword. - none, - /// An explicit length or percentage. - length_percentage: LengthPercentage, - /// The `min-content` keyword. - min_content: css.VendorPrefix, - /// The `max-content` keyword. - max_content: css.VendorPrefix, - /// The `fit-content` keyword. - fit_content: css.VendorPrefix, - /// The `fit-content()` function. - fit_content_function: LengthPercentage, - /// The `stretch` keyword, or the `-webkit-fill-available` or `-moz-available` prefixed keywords. - stretch: css.VendorPrefix, - /// The `contain` keyword. - contain, - - pub fn parse(input: *css.Parser) css.Result(MaxSize) { - const Ident = enum { - none, - min_content, - webkit_min_content, - moz_min_content, - max_content, - webkit_max_content, - moz_max_content, - stretch, - webkit_fill_available, - moz_available, - fit_content, - webkit_fit_content, - moz_fit_content, - contain, - }; - - const IdentMap = bun.ComptimeStringMap(Ident, .{ - .{ "none", .none }, - .{ "min-content", .min_content }, - .{ "-webkit-min-content", .webkit_min_content }, - .{ "-moz-min-content", .moz_min_content }, - .{ "max-content", .max_content }, - .{ "-webkit-max-content", .webkit_max_content }, - .{ "-moz-max-content", .moz_max_content }, - .{ "stretch", .stretch }, - .{ "-webkit-fill-available", .webkit_fill_available }, - .{ "-moz-available", .moz_available }, - .{ "fit-content", .fit_content }, - .{ "-webkit-fit-content", .webkit_fit_content }, - .{ "-moz-fit-content", .moz_fit_content }, - .{ "contain", .contain }, - }); - - const res = input.tryParse(struct { - fn parse(i: *css.Parser) css.Result(MaxSize) { - const ident = switch (i.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const mapped = IdentMap.getASCIIICaseInsensitive(ident) orelse return .{ .err = i.newCustomError(css.ParserError.invalid_value) }; - return .{ .result = switch (mapped) { - .none => .none, - .min_content => .{ .min_content = .{ .none = true } }, - .webkit_min_content => .{ .min_content = .{ .webkit = true } }, - .moz_min_content => .{ .min_content = .{ .moz = true } }, - .max_content => .{ .max_content = .{ .none = true } }, - .webkit_max_content => .{ .max_content = .{ .webkit = true } }, - .moz_max_content => .{ .max_content = .{ .moz = true } }, - .stretch => .{ .stretch = .{ .none = true } }, - .webkit_fill_available => .{ .stretch = .{ .webkit = true } }, - .moz_available => .{ .stretch = .{ .moz = true } }, - .fit_content => .{ .fit_content = .{ .none = true } }, - .webkit_fit_content => .{ .fit_content = .{ .webkit = true } }, - .moz_fit_content => .{ .fit_content = .{ .moz = true } }, - .contain => .contain, - } }; - } - }.parse, .{}); - - if (res.isOk()) { - return res; - } - - if (input.tryParse(parseFitContent, .{}).asValue()) |v| { - return .{ .result = .{ .fit_content_function = v } }; - } - - return switch (input.tryParse(LengthPercentage.parse, .{})) { - .result => |v| .{ .result = .{ .length_percentage = v } }, - .err => |e| .{ .err = e }, - }; - } - - pub fn toCss(this: *const MaxSize, dest: *css.Printer) css.PrintErr!void { - switch (this.*) { - .none => try dest.writeStr("none"), - .contain => try dest.writeStr("contain"), - .min_content => |vp| { - try vp.toCss(dest); - try dest.writeStr("min-content"); - }, - .max_content => |vp| { - try vp.toCss(dest); - try dest.writeStr("max-content"); - }, - .fit_content => |vp| { - try vp.toCss(dest); - try dest.writeStr("fit-content"); - }, - .stretch => |vp| { - if (vp == css.VendorPrefix{ .none = true }) { - try dest.writeStr("stretch"); - } else if (vp == css.VendorPrefix{ .webkit = true }) { - try dest.writeStr("-webkit-fill-available"); - } else if (vp == css.VendorPrefix{ .moz = true }) { - try dest.writeStr("-moz-available"); - } else { - bun.unreachablePanic("Unexpected vendor prefixes", .{}); - } - }, - .fit_content_function => |l| { - try dest.writeStr("fit-content("); - try l.toCss(dest); - try dest.writeChar(')'); - }, - .length_percentage => |l| try l.toCss(dest), - } - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - const F = css.compat.Feature; - return switch (this.*) { - .length_percentage => |*l| l.isCompatible(browsers), - .min_content => F.isCompatible(.min_content_size, browsers), - .max_content => F.isCompatible(.max_content_size, browsers), - .fit_content => F.isCompatible(.fit_content_size, browsers), - .fit_content_function => |*l| F.isCompatible(F.fit_content_function_size, browsers) and l.isCompatible(browsers), - .stretch => |*vp| F.isCompatible( - switch (vp.asBits()) { - css.VendorPrefix.NONE.asBits() => F.stretch_size, - css.VendorPrefix.WEBKIT.asBits() => F.webkit_fill_available_size, - css.VendorPrefix.MOZ.asBits() => F.moz_available_size, - else => return false, - }, - browsers, - ), - .contain => false, // ??? no data in mdn - .none => true, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -/// A value for the [aspect-ratio](https://drafts.csswg.org/css-sizing-4/#aspect-ratio) property. -pub const AspectRatio = struct { - /// The `auto` keyword. - auto: bool, - /// A preferred aspect ratio for the box, specified as width / height. - ratio: ?Ratio, - - pub fn parse(input: *css.Parser) css.Result(AspectRatio) { - const location = input.currentSourceLocation(); - var auto = input.tryParse(css.Parser.expectIdentMatching, .{"auto"}); - - const ratio = input.tryParse(Ratio.parse, .{}); - if (auto.isErr()) { - auto = input.tryParse(css.Parser.expectIdentMatching, .{"auto"}); - } - if (auto.isErr() and ratio.isErr()) { - return .{ .err = location.newCustomError(css.ParserError{ .invalid_value = {} }) }; - } - - return .{ - .result = AspectRatio{ - .auto = auto.isOk(), - .ratio = ratio.asValue(), - }, - }; - } - - pub fn toCss(this: *const AspectRatio, dest: *css.Printer) css.PrintErr!void { - if (this.auto) { - try dest.writeStr("auto"); - } - - if (this.ratio) |*ratio| { - if (this.auto) try dest.writeChar(' '); - try ratio.toCss(dest); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -fn parseFitContent(input: *css.Parser) css.Result(LengthPercentage) { - if (input.expectFunctionMatching("fit-content").asErr()) |e| return .{ .err = e }; - return input.parseNestedBlock(LengthPercentage, {}, css.voidWrap(LengthPercentage, LengthPercentage.parse)); -} - -pub const SizeProperty = packed struct(u16) { - width: bool = false, - height: bool = false, - @"min-width": bool = false, - @"min-height": bool = false, - @"max-width": bool = false, - @"max-height": bool = false, - @"block-size": bool = false, - @"inline-size": bool = false, - @"min-block-size": bool = false, - @"min-inline-size": bool = false, - @"max-block-size": bool = false, - @"max-inline-size": bool = false, - __unused: u4 = 0, - - pub fn tryFromPropertyIdTag(property_id: PropertyIdTag) ?SizeProperty { - inline for (std.meta.fields(@This())) |field| { - if (comptime std.mem.eql(u8, field.name, "__unused")) continue; - if (@intFromEnum(@field(PropertyIdTag, field.name)) == @intFromEnum(@as(PropertyIdTag, property_id))) { - var ret: SizeProperty = .{}; - @field(ret, field.name) = true; - return ret; - } - } - return null; - } -}; - -pub const SizeHandler = struct { - width: ?Size = null, - height: ?Size = null, - min_width: ?Size = null, - min_height: ?Size = null, - max_width: ?MaxSize = null, - max_height: ?MaxSize = null, - block_size: ?Size = null, - inline_size: ?Size = null, - min_block_size: ?Size = null, - min_inline_size: ?Size = null, - max_block_size: ?MaxSize = null, - max_inline_size: ?MaxSize = null, - has_any: bool = false, - flushed_properties: SizeProperty = .{}, - category: PropertyCategory = PropertyCategory.default(), - - const Feature = css.Feature; - - pub fn handleProperty(this: *@This(), property: *const Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool { - const logical_supported = !context.shouldCompileLogical(Feature.logical_size); - - switch (property.*) { - .width => |*v| this.propertyHelper("width", Size, v, PropertyCategory.physical, dest, context), - .height => |*v| this.propertyHelper("height", Size, v, PropertyCategory.physical, dest, context), - .@"min-width" => |*v| this.propertyHelper("min_width", Size, v, PropertyCategory.physical, dest, context), - .@"min-height" => |*v| this.propertyHelper("min_height", Size, v, PropertyCategory.physical, dest, context), - .@"max-width" => |*v| this.propertyHelper("max_width", MaxSize, v, PropertyCategory.physical, dest, context), - .@"max-height" => |*v| this.propertyHelper("max_height", MaxSize, v, PropertyCategory.physical, dest, context), - .@"block-size" => |*v| this.propertyHelper("block_size", Size, v, PropertyCategory.logical, dest, context), - .@"min-block-size" => |*v| this.propertyHelper("min_block_size", Size, v, PropertyCategory.logical, dest, context), - .@"max-block-size" => |*v| this.propertyHelper("max_block_size", MaxSize, v, PropertyCategory.logical, dest, context), - .@"inline-size" => |*v| this.propertyHelper("inline_size", Size, v, PropertyCategory.logical, dest, context), - .@"min-inline-size" => |*v| this.propertyHelper("min_inline_size", Size, v, PropertyCategory.logical, dest, context), - .@"max-inline-size" => |*v| this.propertyHelper("max_inline_size", MaxSize, v, PropertyCategory.logical, dest, context), - .unparsed => |*unparsed| { - switch (unparsed.property_id) { - .width, .height, .@"min-width", .@"max-width", .@"min-height", .@"max-height" => { - bun.bits.insert(SizeProperty, &this.flushed_properties, SizeProperty.tryFromPropertyIdTag(@as(PropertyIdTag, unparsed.property_id)).?); - dest.append(context.allocator, property.deepClone(context.allocator)) catch unreachable; - }, - .@"block-size" => this.logicalUnparsedHelper(property, unparsed, .height, logical_supported, dest, context), - .@"min-block-size" => this.logicalUnparsedHelper(property, unparsed, .@"min-height", logical_supported, dest, context), - .@"max-block-size" => this.logicalUnparsedHelper(property, unparsed, .@"max-height", logical_supported, dest, context), - .@"inline-size" => this.logicalUnparsedHelper(property, unparsed, .width, logical_supported, dest, context), - .@"min-inline-size" => this.logicalUnparsedHelper(property, unparsed, .@"min-width", logical_supported, dest, context), - .@"max-inline-size" => this.logicalUnparsedHelper(property, unparsed, .@"max-width", logical_supported, dest, context), - else => return false, - } - }, - else => return false, - } - - return true; - } - - inline fn logicalUnparsedHelper(this: *@This(), property: *const Property, unparsed: *const UnparsedProperty, comptime physical: PropertyIdTag, logical_supported: bool, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (logical_supported) { - bun.bits.insert(SizeProperty, &this.flushed_properties, SizeProperty.tryFromPropertyIdTag(@as(PropertyIdTag, unparsed.property_id)).?); - bun.handleOom(dest.append(context.allocator, property.deepClone(context.allocator))); - } else { - dest.append(context.allocator, Property{ - .unparsed = unparsed.withPropertyId( - context.allocator, - @unionInit(PropertyId, @tagName(physical), {}), - ), - }) catch |err| bun.handleOom(err); - @field(this.flushed_properties, @tagName(physical)) = true; - } - } - - inline fn propertyHelper( - this: *@This(), - comptime property: []const u8, - comptime T: type, - value: *const T, - comptime category: PropertyCategory, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - // If the category changes betweet logical and physical, - // or if the value contains syntax that isn't supported across all targets, - // preserve the previous value as a fallback. - - if (@field(PropertyCategory, @tagName(category)) != this.category or (@field(this, property) != null and context.targets.browsers != null and !value.isCompatible(context.targets.browsers.?))) { - this.flush(dest, context); - } - - @field(this, property) = value.deepClone(context.allocator); - this.category = category; - this.has_any = true; - } - - pub fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - - this.has_any = false; - const logical_supported = !context.shouldCompileLogical(Feature.logical_size); - - this.flushPropertyHelper(PropertyIdTag.width, "width", Size, dest, context); - this.flushPropertyHelper(PropertyIdTag.@"min-width", "min_width", Size, dest, context); - this.flushPropertyHelper(PropertyIdTag.@"max-width", "max_width", MaxSize, dest, context); - this.flushPropertyHelper(PropertyIdTag.height, "height", Size, dest, context); - this.flushPropertyHelper(PropertyIdTag.@"min-height", "min_height", Size, dest, context); - this.flushPropertyHelper(PropertyIdTag.@"max-height", "max_height", MaxSize, dest, context); - this.flushLogicalHelper(PropertyIdTag.@"block-size", "block_size", PropertyIdTag.height, Size, logical_supported, dest, context); - this.flushLogicalHelper(PropertyIdTag.@"min-block-size", "min_block_size", PropertyIdTag.@"min-height", Size, logical_supported, dest, context); - this.flushLogicalHelper(PropertyIdTag.@"max-block-size", "max_block_size", PropertyIdTag.@"max-height", MaxSize, logical_supported, dest, context); - this.flushLogicalHelper(PropertyIdTag.@"inline-size", "inline_size", PropertyIdTag.width, Size, logical_supported, dest, context); - this.flushLogicalHelper(PropertyIdTag.@"min-inline-size", "min_inline_size", PropertyIdTag.@"min-width", Size, logical_supported, dest, context); - this.flushLogicalHelper(PropertyIdTag.@"max-inline-size", "max_inline_size", PropertyIdTag.@"max-width", MaxSize, logical_supported, dest, context); - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - this.flushed_properties = SizeProperty{}; - } - - inline fn flushPrefixHelper( - this: *@This(), - comptime property: PropertyIdTag, - comptime SizeType: type, - comptime feature: css.prefixes.Feature, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - if (!@field(this.flushed_properties, @tagName(property))) { - const prefixes = context.targets.prefixes(css.VendorPrefix{ .none = true }, feature).difference(css.VendorPrefix{ .none = true }); - inline for (css.VendorPrefix.FIELDS) |field| { - if (@field(prefixes, field)) { - var prefix: css.VendorPrefix = .{}; - @field(prefix, field) = true; - dest.append( - context.allocator, - @unionInit( - Property, - @tagName(property), - @unionInit(SizeType, @tagName(feature), prefix), - ), - ) catch |err| bun.handleOom(err); - } - } - } - } - - inline fn flushPropertyHelper( - this: *@This(), - comptime property: PropertyIdTag, - comptime field: []const u8, - comptime SizeType: type, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - if (bun.take(&@field(this, field))) |val| { - switch (val) { - .stretch => |vp| if (vp == css.VendorPrefix{ .none = true }) { - this.flushPrefixHelper(property, SizeType, .stretch, dest, context); - }, - .min_content => |vp| if (vp == css.VendorPrefix{ .none = true }) { - this.flushPrefixHelper(property, SizeType, .min_content, dest, context); - }, - .max_content => |vp| if (vp == css.VendorPrefix{ .none = true }) { - this.flushPrefixHelper(property, SizeType, .max_content, dest, context); - }, - .fit_content => |vp| if (vp == css.VendorPrefix{ .none = true }) { - this.flushPrefixHelper(property, SizeType, .fit_content, dest, context); - }, - else => {}, - } - bun.handleOom(dest.append(context.allocator, @unionInit(Property, @tagName(property), val.deepClone(context.allocator)))); - @field(this.flushed_properties, @tagName(property)) = true; - } - } - - inline fn flushLogicalHelper( - this: *@This(), - comptime property: PropertyIdTag, - comptime field: []const u8, - comptime physical: PropertyIdTag, - comptime SizeType: type, - logical_supported: bool, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) void { - if (logical_supported) { - this.flushPropertyHelper(property, field, SizeType, dest, context); - } else { - this.flushPropertyHelper(physical, field, SizeType, dest, context); - } - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/svg.zig b/src/css/properties/svg.zig deleted file mode 100644 index 5c8e4be6bede..000000000000 --- a/src/css/properties/svg.zig +++ /dev/null @@ -1,75 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const LengthPercentage = css.css_values.length.LengthPercentage; -const CssColor = css.css_values.color.CssColor; -const Url = css.css_values.url.Url; - -/// An SVG [``](https://www.w3.org/TR/SVG2/painting.html#SpecifyingPaint) value -/// used in the `fill` and `stroke` properties. -const SVGPaint = union(enum) { - /// A URL reference to a paint server element, e.g. `linearGradient`, `radialGradient`, and `pattern`. - Url: struct { - /// The url of the paint server. - url: Url, - /// A fallback to be used in case the paint server cannot be resolved. - fallback: ?SVGPaintFallback, - }, - /// A solid color paint. - Color: CssColor, - /// Use the paint value of fill from a context element. - ContextFill, - /// Use the paint value of stroke from a context element. - ContextStroke, - /// No paint. - None, -}; - -/// A fallback for an SVG paint in case a paint server `url()` cannot be resolved. -/// -/// See [SVGPaint](SVGPaint). -const SVGPaintFallback = union(enum) { - /// No fallback. - None, - /// A solid color. - Color: CssColor, -}; - -/// A value for the [stroke-linecap](https://www.w3.org/TR/SVG2/painting.html#LineCaps) property. -pub const StrokeLinecap = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [stroke-linejoin](https://www.w3.org/TR/SVG2/painting.html#LineJoin) property. -pub const StrokeLinejoin = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [stroke-dasharray](https://www.w3.org/TR/SVG2/painting.html#StrokeDashing) property. -const StrokeDasharray = union(enum) { - /// No dashing is used. - None, - /// Specifies a dashing pattern to use. - Values: ArrayList(LengthPercentage), -}; - -/// A value for the [marker](https://www.w3.org/TR/SVG2/painting.html#VertexMarkerProperties) properties. -const Marker = union(enum) { - /// No marker. - None, - /// A url reference to a `` element. - Url: Url, -}; - -/// A value for the [color-interpolation](https://www.w3.org/TR/SVG2/painting.html#ColorInterpolation) property. -pub const ColorInterpolation = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [color-rendering](https://www.w3.org/TR/SVG2/painting.html#ColorRendering) property. -pub const ColorRendering = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [shape-rendering](https://www.w3.org/TR/SVG2/painting.html#ShapeRendering) property. -pub const ShapeRendering = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-rendering](https://www.w3.org/TR/SVG2/painting.html#TextRendering) property. -pub const TextRendering = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [image-rendering](https://www.w3.org/TR/SVG2/painting.html#ImageRendering) property. -pub const ImageRendering = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/properties/text.zig b/src/css/properties/text.zig deleted file mode 100644 index fc1489809eb5..000000000000 --- a/src/css/properties/text.zig +++ /dev/null @@ -1,272 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const LengthPercentage = css.css_values.length.LengthPercentage; -const CssColor = css.css_values.color.CssColor; -const Length = css.css_values.length.LengthValue; -const Percentage = css.css_values.percentage.Percentage; - -/// A value for the [text-transform](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-transform-property) property. -pub const TextTransform = struct { - /// How case should be transformed. - case: TextTransformCase, - /// How ideographic characters should be transformed. - other: TextTransformOther, -}; - -pub const TextTransformOther = packed struct(u8) { - /// Puts all typographic character units in full-width form. - full_width: bool = false, - /// Converts all small Kana characters to the equivalent full-size Kana. - full_size_kana: bool = false, -}; - -/// Defines how text case should be transformed in the -/// [text-transform](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-transform-property) property. -const TextTransformCase = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [white-space](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#white-space-property) property. -pub const WhiteSpace = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [word-break](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#word-break-property) property. -pub const WordBreak = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [line-break](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#line-break-property) property. -pub const LineBreak = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [hyphens](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#hyphenation) property. -pub const Hyphens = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [overflow-wrap](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#overflow-wrap-property) property. -pub const OverflowWrap = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-align](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-align-property) property. -pub const TextAlign = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-align-last](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-align-last-property) property. -pub const TextAlignLast = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-justify](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-justify-property) property. -pub const TextJustify = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [word-spacing](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#word-spacing-property) -/// and [letter-spacing](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#letter-spacing-property) properties. -pub const Spacing = union(enum) { - /// No additional spacing is applied. - normal, - /// Additional spacing between each word or letter. - length: Length, -}; - -/// A value for the [text-indent](https://www.w3.org/TR/2021/CRD-css-text-3-20210422/#text-indent-property) property. -pub const TextIndent = struct { - /// The amount to indent. - value: LengthPercentage, - /// Inverts which lines are affected. - hanging: bool, - /// Affects the first line after each hard break. - each_line: bool, -}; - -/// A value for the [text-decoration-line](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-decoration-line-property) property. -/// -/// Multiple lines may be specified by combining the flags. -pub const TextDecorationLine = packed struct(u8) { - /// Each line of text is underlined. - underline: bool = false, - /// Each line of text has a line over it. - overline: bool = false, - /// Each line of text has a line through the middle. - line_through: bool = false, - /// The text blinks. - blink: bool = false, - /// The text is decorated as a spelling error. - spelling_error: bool = false, - /// The text is decorated as a grammar error. - grammar_error: bool = false, -}; - -/// A value for the [text-decoration-style](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-decoration-style-property) property. -pub const TextDecorationStyle = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-decoration-thickness](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-decoration-width-property) property. -pub const TextDecorationThickness = union(enum) { - /// The UA chooses an appropriate thickness for text decoration lines. - auto, - /// Use the thickness defined in the current font. - from_font, - /// An explicit length. - length_percentage: LengthPercentage, -}; - -/// A value for the [text-decoration](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-decoration-property) shorthand property. -pub const TextDecoration = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-decoration-skip-ink](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-decoration-skip-ink-property) property. -pub const TextDecorationSkipInk = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A text emphasis shape for the [text-emphasis-style](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-style-property) property. -/// -/// See [TextEmphasisStyle](TextEmphasisStyle). -pub const TextEmphasisStyle = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-emphasis](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-property) shorthand property. -pub const TextEmphasis = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-emphasis-position](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-position-property) property. -pub const TextEmphasisPosition = struct { - /// The vertical position. - vertical: TextEmphasisPositionVertical, - /// The horizontal position. - horizontal: TextEmphasisPositionHorizontal, -}; - -/// A vertical position keyword for the [text-emphasis-position](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-position-property) property. -/// -/// See [TextEmphasisPosition](TextEmphasisPosition). -pub const TextEmphasisPositionVertical = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A horizontal position keyword for the [text-emphasis-position](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-emphasis-position-property) property. -/// -/// See [TextEmphasisPosition](TextEmphasisPosition). -pub const TextEmphasisPositionHorizontal = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [text-shadow](https://www.w3.org/TR/2020/WD-css-text-decor-4-20200506/#text-shadow-property) property. -pub const TextShadow = struct { - /// The color of the text shadow. - color: CssColor, - /// The x offset of the text shadow. - x_offset: Length, - /// The y offset of the text shadow. - y_offset: Length, - /// The blur radius of the text shadow. - blur: Length, - /// The spread distance of the text shadow. - spread: Length, // added in Level 4 spec - - pub fn parse(input: *css.Parser) css.Result(@This()) { - var color: ?CssColor = null; - const Lengths = struct { Length, Length, Length, Length }; - var lengths: ?Lengths = null; - - while (true) { - if (lengths == null) { - const value = input.tryParse(struct { - pub fn parseFn(i: *css.Parser) css.Result(Lengths) { - const horizontal = switch (Length.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const vertical = switch (Length.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const blur = i.tryParse(Length.parse, .{}).asValue() orelse Length.zero(); - const spread = i.tryParse(Length.parse, .{}).asValue() orelse Length.zero(); - return .{ .result = .{ horizontal, vertical, blur, spread } }; - } - }.parseFn, .{}); - - if (value.asValue()) |v| { - lengths = v; - continue; - } - } - - if (color == null) { - if (input.tryParse(CssColor.parse, .{}).asValue()) |value| { - color = value; - continue; - } - } - - break; - } - - const l = lengths orelse return .{ .err = input.newError(.qualified_rule_invalid) }; - return .{ - .result = .{ - .color = color orelse CssColor.current_color, - .x_offset = l[0], - .y_offset = l[1], - .blur = l[2], - .spread = l[3], - }, - }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - try this.x_offset.toCss(dest); - try dest.writeChar(' '); - try this.y_offset.toCss(dest); - - if (!this.blur.eql(&Length.zero()) or !this.spread.eql(&Length.zero())) { - try dest.writeChar(' '); - try this.blur.toCss(dest); - - if (!this.spread.eql(&Length.zero())) { - try dest.writeChar(' '); - try this.spread.toCss(dest); - } - } - - if (!this.color.eql(&CssColor{ .current_color = {} })) { - try dest.writeChar(' '); - try this.color.toCss(dest); - } - - return; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return this.color.isCompatible(browsers) and - this.x_offset.isCompatible(browsers) and - this.y_offset.isCompatible(browsers) and - this.blur.isCompatible(browsers) and - this.spread.isCompatible(browsers); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [text-size-adjust](https://w3c.github.io/csswg-drafts/css-size-adjust/#adjustment-control) property. -pub const TextSizeAdjust = union(enum) { - /// Use the default size adjustment when displaying on a small device. - auto, - /// No size adjustment when displaying on a small device. - none, - /// When displaying on a small device, the font size is multiplied by this percentage. - percentage: Percentage, -}; - -/// A value for the [direction](https://drafts.csswg.org/css-writing-modes-3/#direction) property. -pub const Direction = enum { - /// This value sets inline base direction (bidi directionality) to line-left-to-line-right. - ltr, - /// This value sets inline base direction (bidi directionality) to line-right-to-line-left. - rtl, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [unicode-bidi](https://drafts.csswg.org/css-writing-modes-3/#unicode-bidi) property. -pub const UnicodeBidi = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [box-decoration-break](https://www.w3.org/TR/css-break-3/#break-decoration) property. -pub const BoxDecorationBreak = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/transform.zig b/src/css/properties/transform.zig deleted file mode 100644 index 0aa023a795eb..000000000000 --- a/src/css/properties/transform.zig +++ /dev/null @@ -1,1299 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Result = css.Result; -const VendorPrefix = css.VendorPrefix; -const Property = css.css_properties.Property; - -const LengthPercentage = css.css_values.length.LengthPercentage; -const Length = css.css_values.length.LengthValue; -const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage; -const Angle = css.css_values.angle.Angle; - -/// A value for the [transform](https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/#propdef-transform) property. -pub const TransformList = struct { - v: ArrayList(Transform), - - pub fn parse(input: *css.Parser) Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"none"}).isOk()) { - return .{ .result = .{ .v = .{} } }; - } - - input.skipWhitespace(); - var results = ArrayList(Transform){}; - switch (Transform.parse(input)) { - .result => |first| bun.handleOom(results.append(input.allocator(), first)), - .err => |e| return .{ .err = e }, - } - - while (true) { - input.skipWhitespace(); - if (input.tryParse(Transform.parse, .{}).asValue()) |item| { - bun.handleOom(results.append(input.allocator(), item)); - } else { - return .{ .result = .{ .v = results } }; - } - } - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - if (this.v.items.len == 0) { - return dest.writeStr("none"); - } - - // TODO: Re-enable with a better solution - // See: https://github.com/parcel-bundler/lightningcss/issues/288 - if (dest.minify) { - var base = std.Io.Writer.Allocating.init(dest.allocator); - const base_writer = &base.writer; - - var scratchbuf = std.array_list.Managed(u8).init(dest.allocator); - defer scratchbuf.deinit(); - var p = Printer.new( - dest.allocator, - scratchbuf, - base_writer, - css.PrinterOptions.defaultWithMinify(true), - dest.import_info, - dest.local_names, - dest.symbols, - ); - defer p.deinit(); - - try this.toCssBase(&p); - - return dest.writeStr(base.written()); - } - - return this.toCssBase(dest); - } - - fn toCssBase(this: *const @This(), dest: *Printer) PrintErr!void { - for (this.v.items) |*item| { - try item.toCss(dest); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } -}; - -/// An individual transform function (https://www.w3.org/TR/2019/CR-css-transforms-1-20190214/#two-d-transform-functions). -pub const Transform = union(enum) { - /// A 2D translation. - translate: struct { - x: LengthPercentage, - y: LengthPercentage, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - /// A translation in the X direction. - translate_x: LengthPercentage, - /// A translation in the Y direction. - translate_y: LengthPercentage, - /// A translation in the Z direction. - translate_z: Length, - /// A 3D translation. - translate_3d: struct { - x: LengthPercentage, - y: LengthPercentage, - z: Length, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - /// A 2D scale. - scale: struct { - x: NumberOrPercentage, - y: NumberOrPercentage, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - /// A scale in the X direction. - scale_x: NumberOrPercentage, - /// A scale in the Y direction. - scale_y: NumberOrPercentage, - /// A scale in the Z direction. - scale_z: NumberOrPercentage, - /// A 3D scale. - scale_3d: struct { - x: NumberOrPercentage, - y: NumberOrPercentage, - z: NumberOrPercentage, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - /// A 2D rotation. - rotate: Angle, - /// A rotation around the X axis. - rotate_x: Angle, - /// A rotation around the Y axis. - rotate_y: Angle, - /// A rotation around the Z axis. - rotate_z: Angle, - /// A 3D rotation. - rotate_3d: struct { - x: f32, - y: f32, - z: f32, - angle: Angle, - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// A 2D skew. - skew: struct { - x: Angle, - y: Angle, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - /// A skew along the X axis. - skew_x: Angle, - /// A skew along the Y axis. - skew_y: Angle, - /// A perspective transform. - perspective: Length, - /// A 2D matrix transform. - matrix: Matrix(f32), - /// A 3D matrix transform. - matrix_3d: Matrix3d(f32), - - pub fn parse(input: *css.Parser) Result(Transform) { - const function = switch (input.expectFunction()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - const Closure = struct { function: []const u8 }; - return input.parseNestedBlock( - Transform, - Closure{ .function = function }, - struct { - fn parse(closure: Closure, i: *css.Parser) css.Result(Transform) { - const location = i.currentSourceLocation(); - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "matrix")) { - const a = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const b = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const c = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const d = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const e = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |ee| return .{ .err = ee }; - const f = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |ee| return .{ .err = ee }, - }; - return .{ .result = .{ .matrix = .{ .a = a, .b = b, .c = c, .d = d, .e = e, .f = f } } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "matrix3d")) { - const m11 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m12 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m13 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m14 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m21 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m22 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m23 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m24 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m31 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m32 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m33 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m34 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m41 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m42 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m43 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const m44 = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .matrix_3d = .{ - .m11 = m11, - .m12 = m12, - .m13 = m13, - .m14 = m14, - .m21 = m21, - .m22 = m22, - .m23 = m23, - .m24 = m24, - .m31 = m31, - .m32 = m32, - .m33 = m33, - .m34 = m34, - .m41 = m41, - .m42 = m42, - .m43 = m43, - .m44 = m44, - } } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translate")) { - const x = switch (LengthPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.tryParse(struct { - fn parse(p: *css.Parser) css.Result(void) { - return p.expectComma(); - } - }.parse, .{}).isOk()) { - const y = switch (LengthPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .translate = .{ .x = x, .y = y } } }; - } else { - return .{ .result = .{ .translate = .{ .x = x, .y = LengthPercentage.zero() } } }; - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translatex")) { - const x = switch (LengthPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .translate_x = x } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translatey")) { - const y = switch (LengthPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .translate_y = y } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translatez")) { - const z = switch (Length.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .translate_z = z } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "translate3d")) { - const x = switch (LengthPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const y = switch (LengthPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const z = switch (Length.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .translate_3d = .{ .x = x, .y = y, .z = z } } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scale")) { - const x = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.tryParse(struct { - fn parse(p: *css.Parser) css.Result(void) { - return p.expectComma(); - } - }.parse, .{}).isOk()) { - const y = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .scale = .{ .x = x, .y = y } } }; - } else { - return .{ .result = .{ .scale = .{ .x = x, .y = x.deepClone(i.allocator()) } } }; - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scalex")) { - const x = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .scale_x = x } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scaley")) { - const y = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .scale_y = y } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scalez")) { - const z = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .scale_z = z } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "scale3d")) { - const x = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const y = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const z = switch (NumberOrPercentage.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .scale_3d = .{ .x = x, .y = y, .z = z } } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotate")) { - const angle = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .rotate = angle } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotatex")) { - const angle = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .rotate_x = angle } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotatey")) { - const angle = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .rotate_y = angle } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotatez")) { - const angle = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .rotate_z = angle } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "rotate3d")) { - const x = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const y = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const z = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const angle = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .rotate_3d = .{ .x = x, .y = y, .z = z, .angle = angle } } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "skew")) { - const x = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (i.tryParse(struct { - fn parse(p: *css.Parser) css.Result(void) { - return p.expectComma(); - } - }.parse, .{}).isOk()) { - const y = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .skew = .{ .x = x, .y = y } } }; - } else { - return .{ .result = .{ .skew = .{ .x = x, .y = Angle{ .deg = 0.0 } } } }; - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "skewx")) { - const angle = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .skew_x = angle } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "skewy")) { - const angle = switch (Angle.parseWithUnitlessZero(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .skew_y = angle } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "perspective")) { - const len = switch (Length.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .perspective = len } }; - } else { - return .{ .err = location.newUnexpectedTokenError(.{ .ident = closure.function }) }; - } - } - }.parse, - ); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - switch (this.*) { - .translate => |t| { - if (dest.minify and t.x.isZero() and !t.y.isZero()) { - try dest.writeStr("translateY("); - try t.y.toCss(dest); - } else { - try dest.writeStr("translate("); - try t.x.toCss(dest); - if (!t.y.isZero()) { - try dest.delim(',', false); - try t.y.toCss(dest); - } - } - try dest.writeChar(')'); - }, - .translate_x => |x| { - try dest.writeStr(if (dest.minify) "translate(" else "translateX("); - try x.toCss(dest); - try dest.writeChar(')'); - }, - .translate_y => |y| { - try dest.writeStr("translateY("); - try y.toCss(dest); - try dest.writeChar(')'); - }, - .translate_z => |z| { - try dest.writeStr("translateZ("); - try z.toCss(dest); - try dest.writeChar(')'); - }, - .translate_3d => |t| { - if (dest.minify and !t.x.isZero() and t.y.isZero() and t.z.isZero()) { - try dest.writeStr("translate("); - try t.x.toCss(dest); - } else if (dest.minify and t.x.isZero() and !t.y.isZero() and t.z.isZero()) { - try dest.writeStr("translateY("); - try t.y.toCss(dest); - } else if (dest.minify and t.x.isZero() and t.y.isZero() and !t.z.isZero()) { - try dest.writeStr("translateZ("); - try t.z.toCss(dest); - } else if (dest.minify and t.z.isZero()) { - try dest.writeStr("translate("); - try t.x.toCss(dest); - try dest.delim(',', false); - try t.y.toCss(dest); - } else { - try dest.writeStr("translate3d("); - try t.x.toCss(dest); - try dest.delim(',', false); - try t.y.toCss(dest); - try dest.delim(',', false); - try t.z.toCss(dest); - } - try dest.writeChar(')'); - }, - .scale => |s| { - const x: f32 = s.x.intoF32(); - const y: f32 = s.y.intoF32(); - if (dest.minify and x == 1.0 and y != 1.0) { - try dest.writeStr("scaleY("); - try css.CSSNumberFns.toCss(&y, dest); - } else if (dest.minify and x != 1.0 and y == 1.0) { - try dest.writeStr("scaleX("); - try css.CSSNumberFns.toCss(&x, dest); - } else { - try dest.writeStr("scale("); - try css.CSSNumberFns.toCss(&x, dest); - if (y != x) { - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&y, dest); - } - } - try dest.writeChar(')'); - }, - .scale_x => |x| { - try dest.writeStr("scaleX("); - try css.CSSNumberFns.toCss(&x.intoF32(), dest); - try dest.writeChar(')'); - }, - .scale_y => |y| { - try dest.writeStr("scaleY("); - try css.CSSNumberFns.toCss(&y.intoF32(), dest); - try dest.writeChar(')'); - }, - .scale_z => |z| { - try dest.writeStr("scaleZ("); - try css.CSSNumberFns.toCss(&z.intoF32(), dest); - try dest.writeChar(')'); - }, - .scale_3d => |s| { - const x: f32 = s.x.intoF32(); - const y: f32 = s.y.intoF32(); - const z: f32 = s.z.intoF32(); - if (dest.minify and z == 1.0 and x == y) { - try dest.writeStr("scale("); - try css.CSSNumberFns.toCss(&x, dest); - } else if (dest.minify and x != 1.0 and y == 1.0 and z == 1.0) { - try dest.writeStr("scaleX("); - try css.CSSNumberFns.toCss(&x, dest); - } else if (dest.minify and x == 1.0 and y != 1.0 and z == 1.0) { - try dest.writeStr("scaleY("); - try css.CSSNumberFns.toCss(&y, dest); - } else if (dest.minify and x == 1.0 and y == 1.0 and z != 1.0) { - try dest.writeStr("scaleZ("); - try css.CSSNumberFns.toCss(&z, dest); - } else if (dest.minify and z == 1.0) { - try dest.writeStr("scale("); - try css.CSSNumberFns.toCss(&x, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&y, dest); - } else { - try dest.writeStr("scale3d("); - try css.CSSNumberFns.toCss(&x, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&y, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&z, dest); - } - try dest.writeChar(')'); - }, - .rotate => |angle| { - try dest.writeStr("rotate("); - try angle.toCssWithUnitlessZero(dest); - try dest.writeChar(')'); - }, - .rotate_x => |angle| { - try dest.writeStr("rotateX("); - try angle.toCssWithUnitlessZero(dest); - try dest.writeChar(')'); - }, - .rotate_y => |angle| { - try dest.writeStr("rotateY("); - try angle.toCssWithUnitlessZero(dest); - try dest.writeChar(')'); - }, - .rotate_z => |angle| { - try dest.writeStr(if (dest.minify) "rotate(" else "rotateZ("); - try angle.toCssWithUnitlessZero(dest); - try dest.writeChar(')'); - }, - .rotate_3d => |r| { - if (dest.minify and r.x == 1.0 and r.y == 0.0 and r.z == 0.0) { - try dest.writeStr("rotateX("); - try r.angle.toCssWithUnitlessZero(dest); - } else if (dest.minify and r.x == 0.0 and r.y == 1.0 and r.z == 0.0) { - try dest.writeStr("rotateY("); - try r.angle.toCssWithUnitlessZero(dest); - } else if (dest.minify and r.x == 0.0 and r.y == 0.0 and r.z == 1.0) { - try dest.writeStr("rotate("); - try r.angle.toCssWithUnitlessZero(dest); - } else { - try dest.writeStr("rotate3d("); - try css.CSSNumberFns.toCss(&r.x, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&r.y, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&r.z, dest); - try dest.delim(',', false); - try r.angle.toCssWithUnitlessZero(dest); - } - try dest.writeChar(')'); - }, - .skew => |s| { - if (dest.minify and s.x.isZero() and !s.y.isZero()) { - try dest.writeStr("skewY("); - try s.y.toCssWithUnitlessZero(dest); - } else { - try dest.writeStr("skew("); - try s.x.toCss(dest); - if (!s.y.isZero()) { - try dest.delim(',', false); - try s.y.toCssWithUnitlessZero(dest); - } - } - try dest.writeChar(')'); - }, - .skew_x => |angle| { - try dest.writeStr(if (dest.minify) "skew(" else "skewX("); - try angle.toCssWithUnitlessZero(dest); - try dest.writeChar(')'); - }, - .skew_y => |angle| { - try dest.writeStr("skewY("); - try angle.toCssWithUnitlessZero(dest); - try dest.writeChar(')'); - }, - .perspective => |len| { - try dest.writeStr("perspective("); - try len.toCss(dest); - try dest.writeChar(')'); - }, - .matrix => |m| { - try dest.writeStr("matrix("); - try css.CSSNumberFns.toCss(&m.a, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.b, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.c, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.d, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.e, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.f, dest); - try dest.writeChar(')'); - }, - .matrix_3d => |m| { - try dest.writeStr("matrix3d("); - try css.CSSNumberFns.toCss(&m.m11, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m12, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m13, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m14, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m21, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m22, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m23, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m24, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m31, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m32, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m33, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m34, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m41, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m42, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m43, dest); - try dest.delim(',', false); - try css.CSSNumberFns.toCss(&m.m44, dest); - try dest.writeChar(')'); - }, - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } -}; - -/// A 2D matrix. -pub fn Matrix(comptime T: type) type { - return struct { - a: T, - b: T, - c: T, - d: T, - e: T, - f: T, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - }; -} - -/// A 3D matrix. -pub fn Matrix3d(comptime T: type) type { - return struct { - m11: T, - m12: T, - m13: T, - m14: T, - m21: T, - m22: T, - m23: T, - m24: T, - m31: T, - m32: T, - m33: T, - m34: T, - m41: T, - m42: T, - m43: T, - m44: T, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - }; -} - -/// A value for the [transform-style](https://drafts.csswg.org/css-transforms-2/#transform-style-property) property. -pub const TransformStyle = enum { - flat, - @"preserve-3d", - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [transform-box](https://drafts.csswg.org/css-transforms-1/#transform-box) property. -pub const TransformBox = enum { - /// Uses the content box as reference box. - @"content-box", - /// Uses the border box as reference box. - @"border-box", - /// Uses the object bounding box as reference box. - @"fill-box", - /// Uses the stroke bounding box as reference box. - @"stroke-box", - /// Uses the nearest SVG viewport as reference box. - @"view-box", - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the [backface-visibility](https://drafts.csswg.org/css-transforms-2/#backface-visibility-property) property. -pub const BackfaceVisibility = enum { - visible, - hidden, - - const css_impl = css.DefineEnumProperty(@This()); - pub const eql = css_impl.eql; - pub const hash = css_impl.hash; - pub const parse = css_impl.parse; - pub const toCss = css_impl.toCss; - pub const deepClone = css_impl.deepClone; -}; - -/// A value for the perspective property. -pub const Perspective = union(enum) { - /// No perspective transform is applied. - none, - /// Distance to the center of projection. - length: Length, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [translate](https://drafts.csswg.org/css-transforms-2/#propdef-translate) property. -pub const Translate = union(enum) { - /// The "none" keyword. - none, - - /// The x, y, and z translations. - xyz: struct { - /// The x translation. - x: LengthPercentage, - /// The y translation. - y: LengthPercentage, - /// The z translation. - z: Length, - - pub fn __generateDeepClone() void {} - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"none"}).isOk()) { - return .{ .result = .none }; - } - - const x = switch (LengthPercentage.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const y = input.tryParse(LengthPercentage.parse, .{}); - const z = if (y.isOk()) input.tryParse(Length.parse, .{}).asValue() else null; - - return .{ - .result = Translate{ - .xyz = .{ - .x = x, - .y = y.unwrapOr(comptime LengthPercentage.zero()), - .z = z orelse Length.zero(), - }, - }, - }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) PrintErr!void { - switch (this.*) { - .none => try dest.writeStr("none"), - .xyz => |xyz| { - try xyz.x.toCss(dest); - if (!xyz.y.isZero() or !xyz.z.isZero()) { - try dest.writeChar(' '); - try xyz.y.toCss(dest); - if (!xyz.z.isZero()) { - try dest.writeChar(' '); - try xyz.z.toCss(dest); - } - } - }, - } - return; - } - - pub fn toTransform(this: *const @This(), allocator: std.mem.Allocator) Transform { - return switch (this.*) { - .none => .{ .translate_3d = .{ - .x = LengthPercentage.zero(), - .y = LengthPercentage.zero(), - .z = Length.zero(), - } }, - .xyz => |xyz| .{ .translate_3d = .{ - .x = xyz.x.deepClone(allocator), - .y = xyz.y.deepClone(allocator), - .z = xyz.z.deepClone(allocator), - } }, - }; - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [rotate](https://drafts.csswg.org/css-transforms-2/#propdef-rotate) property. -pub const Rotate = struct { - /// Rotation around the x axis. - x: f32, - /// Rotation around the y axis. - y: f32, - /// Rotation around the z axis. - z: f32, - /// The angle of rotation. - angle: Angle, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"none"}).isOk()) { - return .{ .result = .{ - .x = 0.0, - .y = 0.0, - .z = 1.0, - .angle = .{ .deg = 0.0 }, - } }; - } - - const angle = input.tryParse(Angle.parse, .{}); - - const XYZ = struct { x: f32, y: f32, z: f32 }; - const xyz = switch (input.tryParse(struct { - fn parse(i: *css.Parser) css.Result(XYZ) { - const location = i.currentSourceLocation(); - const ident = switch (i.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "x")) { - return .{ .result = .{ .x = 1.0, .y = 0.0, .z = 0.0 } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "y")) { - return .{ .result = .{ .x = 0.0, .y = 1.0, .z = 0.0 } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "z")) { - return .{ .result = .{ .x = 0.0, .y = 0.0, .z = 1.0 } }; - } - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - }.parse, .{})) { - .result => |v| v, - .err => input.tryParse(struct { - fn parse(i: *css.Parser) css.Result(XYZ) { - const x = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const y = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const z = switch (css.CSSNumberFns.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .x = x, .y = y, .z = z } }; - } - }.parse, .{}).unwrapOr(.{ .x = 0.0, .y = 0.0, .z = 1.0 }), - }; - - const final_angle = switch (angle) { - .result => |v| v, - .err => switch (Angle.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, - }; - - return .{ .result = .{ - .x = xyz.x, - .y = xyz.y, - .z = xyz.z, - .angle = final_angle, - } }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) PrintErr!void { - if (this.x == 0.0 and this.y == 0.0 and this.z == 1.0 and this.angle.isZero()) { - try dest.writeStr("none"); - return; - } - - if (this.x == 1.0 and this.y == 0.0 and this.z == 0.0) { - try dest.writeStr("x "); - } else if (this.x == 0.0 and this.y == 1.0 and this.z == 0.0) { - try dest.writeStr("y "); - } else if (!(this.x == 0.0 and this.y == 0.0 and this.z == 1.0)) { - try css.CSSNumberFns.toCss(&this.x, dest); - try dest.writeChar(' '); - try css.CSSNumberFns.toCss(&this.y, dest); - try dest.writeChar(' '); - try css.CSSNumberFns.toCss(&this.z, dest); - try dest.writeChar(' '); - } - - try this.angle.toCss(dest); - } - - /// Converts the rotation to a transform function. - pub fn toTransform(this: *const @This(), allocator: std.mem.Allocator) Transform { - return .{ .rotate_3d = .{ - .x = this.x, - .y = this.y, - .z = this.z, - .angle = this.angle.deepClone(allocator), - } }; - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [scale](https://drafts.csswg.org/css-transforms-2/#propdef-scale) property. -pub const Scale = union(enum) { - /// The "none" keyword. - none, - - /// Scale on the x, y, and z axis. - xyz: struct { - /// Scale on the x axis. - x: NumberOrPercentage, - /// Scale on the y axis. - y: NumberOrPercentage, - /// Scale on the z axis. - z: NumberOrPercentage, - - pub fn __generateDeepClone() void {} - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - - pub fn parse(input: *css.Parser) css.Result(@This()) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"none"}).isOk()) { - return .{ .result = .none }; - } - - const x = switch (NumberOrPercentage.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - const y = input.tryParse(NumberOrPercentage.parse, .{}); - const z = if (y.isOk()) input.tryParse(NumberOrPercentage.parse, .{}).asValue() else null; - - return .{ .result = .{ .xyz = .{ - .x = x, - .y = if (y.asValue()) |val| val else x, - .z = if (z) |val| val else .{ .number = 1.0 }, - } } }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) PrintErr!void { - switch (this.*) { - .none => try dest.writeStr("none"), - .xyz => |xyz| { - try xyz.x.toCss(dest); - const z_val = xyz.z.intoF32(); - if (!xyz.y.eql(&xyz.x) or z_val != 1.0) { - try dest.writeChar(' '); - try xyz.y.toCss(dest); - if (z_val != 1.0) { - try dest.writeChar(' '); - try xyz.z.toCss(dest); - } - } - }, - } - } - - pub fn toTransform(this: *const @This(), allocator: std.mem.Allocator) Transform { - return switch (this.*) { - .none => .{ .scale_3d = .{ - .x = .{ .number = 1.0 }, - .y = .{ .number = 1.0 }, - .z = .{ .number = 1.0 }, - } }, - .xyz => |xyz| .{ .scale_3d = .{ - .x = xyz.x.deepClone(allocator), - .y = xyz.y.deepClone(allocator), - .z = xyz.z.deepClone(allocator), - } }, - }; - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const TransformHandler = struct { - transform: ?struct { TransformList, VendorPrefix } = null, - translate: ?Translate = null, - rotate: ?Rotate = null, - scale: ?Scale = null, - has_any: bool = false, - - pub fn handleProperty( - this: *@This(), - property: *const css.Property, - dest: *css.DeclarationList, - context: *css.PropertyHandlerContext, - ) bool { - const individualProperty = struct { - fn individualProperty(self: *TransformHandler, allocator: std.mem.Allocator, comptime field: []const u8, val: anytype) void { - if (self.transform) |*transform| { - bun.handleOom(transform.*[0].v.append(allocator, val.toTransform(allocator))); - } else { - @field(self, field) = val.deepClone(allocator); - self.has_any = true; - } - } - }.individualProperty; - const allocator = context.allocator; - - switch (property.*) { - .transform => |val| { - const transform_val = val[0]; - const vp = val[1]; - - // If two vendor prefixes for the same property have different - // values, we need to flush what we have immediately to preserve order. - if (this.transform) |current| { - if (!current[0].eql(&transform_val) and !bun.bits.contains(css.VendorPrefix, current[1], vp)) { - this.flush(allocator, dest, context); - } - } - - // Otherwise, update the value and add the prefix. - if (this.transform) |*transform| { - transform.* = .{ transform_val.deepClone(allocator), bun.bits.@"or"(css.VendorPrefix, transform.*[1], vp) }; - } else { - this.transform = .{ transform_val.deepClone(allocator), vp }; - this.has_any = true; - } - - this.translate = null; - this.rotate = null; - this.scale = null; - }, - .translate => |val| individualProperty(this, allocator, "translate", val), - .rotate => |val| individualProperty(this, allocator, "rotate", val), - .scale => |val| individualProperty(this, allocator, "scale", val), - .unparsed => |unparsed| { - if (unparsed.property_id == .transform or - unparsed.property_id == .translate or - unparsed.property_id == .rotate or - unparsed.property_id == .scale) - { - this.flush(allocator, dest, context); - const prop = if (unparsed.property_id == .transform) - Property{ .unparsed = unparsed.getPrefixed(allocator, context.targets, css.prefixes.Feature.transform) } - else - property.deepClone(allocator); - bun.handleOom(dest.append(allocator, prop)); - } else return false; - }, - else => return false, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(context.allocator, dest, context); - } - - fn flush(this: *@This(), allocator: std.mem.Allocator, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - - this.has_any = false; - - const transform = bun.take(&this.transform); - const translate = bun.take(&this.translate); - const rotate = bun.take(&this.rotate); - const scale = bun.take(&this.scale); - - if (transform) |t| { - const prefix = context.targets.prefixes(t[1], css.prefixes.Feature.transform); - bun.handleOom(dest.append(allocator, Property{ .transform = .{ t[0], prefix } })); - } - - if (translate) |t| { - bun.handleOom(dest.append(allocator, Property{ .translate = t })); - } - - if (rotate) |r| { - bun.handleOom(dest.append(allocator, Property{ .rotate = r })); - } - - if (scale) |s| { - bun.handleOom(dest.append(allocator, Property{ .scale = s })); - } - } -}; - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/transition.zig b/src/css/properties/transition.zig deleted file mode 100644 index ac2523d41508..000000000000 --- a/src/css/properties/transition.zig +++ /dev/null @@ -1,519 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const Property = css.css_properties.Property; -const PropertyId = css.css_properties.PropertyId; -const Time = css.css_values.time.Time; -const EasingFunction = css.css_values.easing.EasingFunction; - -const VendorPrefix = css.VendorPrefix; -const Feature = css.prefixes.Feature; - -/// A value for the [transition](https://www.w3.org/TR/2018/WD-css-transitions-1-20181011/#transition-shorthand-property) property. -pub const Transition = struct { - /// The property to transition. - property: PropertyId, - /// The duration of the transition. - duration: Time, - /// The delay before the transition starts. - delay: Time, - /// The easing function for the transition. - timing_function: EasingFunction, - - pub const PropertyFieldMap = .{ - .property = css.PropertyIdTag.@"transition-property", - .duration = css.PropertyIdTag.@"transition-duration", - .delay = css.PropertyIdTag.@"transition-delay", - .timing_function = css.PropertyIdTag.@"transition-timing-function", - }; - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(comptime @This(), this, allocator); - } - - pub fn parse(parser: *css.Parser) css.Result(@This()) { - var property: ?PropertyId = null; - var duration: ?Time = null; - var delay: ?Time = null; - var timing_function: ?EasingFunction = null; - - while (true) { - if (duration == null) { - if (parser.tryParse(Time.parse, .{}).asValue()) |value| { - duration = value; - continue; - } - } - - if (timing_function == null) { - if (parser.tryParse(EasingFunction.parse, .{}).asValue()) |value| { - timing_function = value; - continue; - } - } - - if (delay == null) { - if (parser.tryParse(Time.parse, .{}).asValue()) |value| { - delay = value; - continue; - } - } - - if (property == null) { - if (parser.tryParse(PropertyId.parse, .{}).asValue()) |value| { - property = value; - continue; - } - } - - break; - } - - return .{ .result = .{ - .property = property orelse .all, - .duration = duration orelse .{ .seconds = 0.0 }, - .delay = delay orelse .{ .seconds = 0.0 }, - .timing_function = timing_function orelse .ease, - } }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - try this.property.toCss(dest); - if (!this.duration.isZero() or !this.delay.isZero()) { - try dest.writeChar(' '); - try this.duration.toCss(dest); - } - - if (!this.timing_function.isEase()) { - try dest.writeChar(' '); - try this.timing_function.toCss(dest); - } - - if (!this.delay.isZero()) { - try dest.writeChar(' '); - try this.delay.toCss(dest); - } - } -}; - -pub const TransitionHandler = struct { - properties: ?struct { SmallList(PropertyId, 1), VendorPrefix } = null, - durations: ?struct { SmallList(Time, 1), VendorPrefix } = null, - delays: ?struct { SmallList(Time, 1), VendorPrefix } = null, - timing_functions: ?struct { SmallList(EasingFunction, 1), VendorPrefix } = null, - has_any: bool = false, - - pub fn handleProperty(this: *@This(), prop: *const Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool { - switch (prop.*) { - .@"transition-property" => |*x| this.property(dest, context, Feature.transition_property, "properties", &x.*[0], x.*[1]), - .@"transition-duration" => |*x| this.property(dest, context, Feature.transition_duration, "durations", &x.*[0], x.*[1]), - .@"transition-delay" => |*x| this.property(dest, context, Feature.transition_delay, "delays", &x.*[0], x.*[1]), - .@"transition-timing-function" => |*x| this.property(dest, context, Feature.transition_timing_function, "timing_functions", &x.*[0], x.*[1]), - .transition => |*x| { - const val: *const SmallList(Transition, 1) = &x.*[0]; - const vp: VendorPrefix = x.*[1]; - - var properties = SmallList(PropertyId, 1).initCapacity(context.allocator, val.len()); - var durations = SmallList(Time, 1).initCapacity(context.allocator, val.len()); - var delays = SmallList(Time, 1).initCapacity(context.allocator, val.len()); - var timing_functions = SmallList(EasingFunction, 1).initCapacity(context.allocator, val.len()); - properties.setLen(val.len()); - durations.setLen(val.len()); - delays.setLen(val.len()); - timing_functions.setLen(val.len()); - - for (val.slice(), properties.slice_mut()) |*item, *out_prop| { - out_prop.* = item.property.deepClone(context.allocator); - } - this.maybeFlush(dest, context, "properties", &properties, vp); - - for (val.slice(), durations.slice_mut()) |*item, *out_dur| { - out_dur.* = item.duration.deepClone(context.allocator); - } - this.maybeFlush(dest, context, "durations", &durations, vp); - - for (val.slice(), delays.slice_mut()) |*item, *out_delay| { - out_delay.* = item.delay.deepClone(context.allocator); - } - this.maybeFlush(dest, context, "delays", &delays, vp); - - for (val.slice(), timing_functions.slice_mut()) |*item, *out_timing| { - out_timing.* = item.timing_function.deepClone(context.allocator); - } - this.maybeFlush(dest, context, "timing_functions", &timing_functions, vp); - - this.property(dest, context, Feature.transition_property, "properties", &properties, vp); - this.property(dest, context, Feature.transition_duration, "durations", &durations, vp); - this.property(dest, context, Feature.transition_delay, "delays", &delays, vp); - this.property(dest, context, Feature.transition_timing_function, "timing_functions", &timing_functions, vp); - }, - .unparsed => |*x| if (isTransitionProperty(&x.property_id)) { - this.flush(dest, context); - dest.append( - context.allocator, - .{ .unparsed = x.getPrefixed(context.allocator, context.targets, Feature.transition) }, - ) catch |err| bun.handleOom(err); - } else return false, - else => return false, - } - - return true; - } - - pub fn finalize(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - this.flush(dest, context); - } - - fn property(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime feature: Feature, comptime prop: []const u8, val: anytype, vp: VendorPrefix) void { - this.maybeFlush(dest, context, prop, val, vp); - - // Otherwise, update the value and add the prefix. - if (@field(this, prop)) |*p| { - const v = &p.*[0]; - const prefixes = &p.*[1]; - v.* = val.deepClone(context.allocator); - bun.bits.insert(VendorPrefix, prefixes, vp); - prefixes.* = context.targets.prefixes(prefixes.*, feature); - } else { - const prefixes = context.targets.prefixes(vp, feature); - const cloned_val = val.deepClone(context.allocator); - @field(this, prop) = .{ cloned_val, prefixes }; - this.has_any = true; - } - } - - fn maybeFlush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext, comptime prop: []const u8, val: anytype, vp: VendorPrefix) void { - // If two vendor prefixes for the same property have different - // values, we need to flush what we have immediately to preserve order. - if (@field(this, prop)) |*p| { - const v = &p.*[0]; - const prefixes = &p.*[1]; - if (!val.eql(v) and !bun.bits.contains(VendorPrefix, prefixes.*, vp)) { - this.flush(dest, context); - } - } - } - - fn flush(this: *@This(), dest: *css.DeclarationList, context: *css.PropertyHandlerContext) void { - if (!this.has_any) return; - this.has_any = false; - - var _properties: ?struct { SmallList(PropertyId, 1), VendorPrefix } = bun.take(&this.properties); - var _durations: ?struct { SmallList(Time, 1), VendorPrefix } = bun.take(&this.durations); - var _delays: ?struct { SmallList(Time, 1), VendorPrefix } = bun.take(&this.delays); - var _timing_functions: ?struct { SmallList(EasingFunction, 1), VendorPrefix } = bun.take(&this.timing_functions); - - var rtl_properties: ?SmallList(PropertyId, 1) = if (_properties) |*p| expandProperties(&p.*[0], context) else null; - - if (_properties != null and _durations != null and _delays != null and _timing_functions != null) { - const properties: *SmallList(PropertyId, 1) = &_properties.?[0]; - const property_prefixes: *VendorPrefix = &_properties.?[1]; - const durations: *SmallList(Time, 1) = &_durations.?[0]; - const duration_prefixes: *VendorPrefix = &_durations.?[1]; - const delays: *SmallList(Time, 1) = &_delays.?[0]; - const delay_prefixes: *VendorPrefix = &_delays.?[1]; - const timing_functions: *SmallList(EasingFunction, 1) = &_timing_functions.?[0]; - const timing_prefixes: *VendorPrefix = &_timing_functions.?[1]; - - // Find the intersection of prefixes with the same value. - // Remove that from the prefixes of each of the properties. The remaining - // prefixes will be handled by outputting individual properties below. - const intersection = property_prefixes.bitwiseAnd(duration_prefixes.*).bitwiseAnd(delay_prefixes.*).bitwiseAnd(timing_prefixes.*); - if (!intersection.isEmpty()) { - const transitions = getTransitions(context, properties, durations, delays, timing_functions); - - if (rtl_properties) |*rtl_properties2| { - const rtl_transitions = getTransitions(context, rtl_properties2, durations, delays, timing_functions); - context.addLogicalRule( - context.allocator, - Property{ - .transition = .{ transitions, intersection }, - }, - Property{ - .transition = .{ rtl_transitions, intersection }, - }, - ); - } else { - dest.append( - context.allocator, - Property{ .transition = .{ transitions.deepClone(context.allocator), intersection } }, - ) catch |err| bun.handleOom(err); - } - - bun.bits.remove(VendorPrefix, property_prefixes, intersection); - bun.bits.remove(VendorPrefix, duration_prefixes, intersection); - bun.bits.remove(VendorPrefix, timing_prefixes, intersection); - bun.bits.remove(VendorPrefix, delay_prefixes, intersection); - } - } - - if (_properties != null) { - const properties: SmallList(PropertyId, 1) = _properties.?[0]; - const prefix: VendorPrefix = _properties.?[1]; - _properties = null; - if (!prefix.isEmpty()) { - if (rtl_properties) |rtl_properties2| { - context.addLogicalRule( - context.allocator, - Property{ .@"transition-property" = .{ properties, prefix } }, - Property{ .@"transition-property" = .{ rtl_properties2, prefix } }, - ); - rtl_properties = null; - } else { - bun.handleOom(dest.append(context.allocator, Property{ .@"transition-property" = .{ properties, prefix } })); - } - } - } - - if (_durations != null) { - const durations: SmallList(Time, 1) = _durations.?[0]; - const prefix: VendorPrefix = _durations.?[1]; - _durations = null; - if (!prefix.isEmpty()) { - bun.handleOom(dest.append(context.allocator, Property{ .@"transition-duration" = .{ durations, prefix } })); - } - } - - if (_delays != null) { - const delays: SmallList(Time, 1) = _delays.?[0]; - const prefix: VendorPrefix = _delays.?[1]; - _delays = null; - if (!prefix.isEmpty()) { - bun.handleOom(dest.append(context.allocator, Property{ .@"transition-delay" = .{ delays, prefix } })); - } - } - - if (_timing_functions != null) { - const timing_functions: SmallList(EasingFunction, 1) = _timing_functions.?[0]; - const prefix: VendorPrefix = _timing_functions.?[1]; - _timing_functions = null; - if (!prefix.isEmpty()) { - bun.handleOom(dest.append(context.allocator, Property{ .@"transition-timing-function" = .{ timing_functions, prefix } })); - } - } - - this.reset(); - } - - inline fn getTransitions( - context: *const css.PropertyHandlerContext, - properties: *SmallList(PropertyId, 1), - durations: *SmallList(Time, 1), - delays: *SmallList(Time, 1), - timing_functions: *SmallList(EasingFunction, 1), - ) SmallList(Transition, 1) { - const cycleBump = struct { - inline fn cycleBump(idx: *u32, len: u32) void { - idx.* = (idx.* + 1) % len; - } - }.cycleBump; - - // transition-property determines the number of transitions. The values of other - // properties are repeated to match this length. - var transitions = SmallList(Transition, 1).initCapacity(context.allocator, 1); - var durations_idx: u32 = 0; - var delays_idx: u32 = 0; - var timing_idx: u32 = 0; - for (properties.slice()) |*property_id| { - const duration = if (durations.len() > durations_idx) durations.at(durations_idx).deepClone(context.allocator) else Time{ .seconds = 0.0 }; - const delay = if (delays.len() > delays_idx) delays.at(delays_idx).deepClone(context.allocator) else Time{ .seconds = 0.0 }; - const timing_function = if (timing_functions.len() > timing_idx) timing_functions.at(timing_idx).deepClone(context.allocator) else EasingFunction.ease; - cycleBump(&durations_idx, durations.len()); - cycleBump(&delays_idx, delays.len()); - cycleBump(&timing_idx, timing_functions.len()); - const transition = Transition{ - .property = property_id.deepClone(context.allocator), - .duration = duration, - .delay = delay, - .timing_function = timing_function, - }; - var cloned = false; - - const prefix_to_iter = property_id.prefix().orNone(); - // Expand vendor prefixes into multiple transitions. - inline for (VendorPrefix.FIELDS) |prefix_field| { - if (@field(prefix_to_iter, prefix_field)) { - var t = if (cloned) transition.deepClone(context.allocator) else transition; - cloned = true; - var new_prefix = VendorPrefix{}; - @field(new_prefix, prefix_field) = true; - t.property = property_id.withPrefix(new_prefix); - transitions.append(context.allocator, t); - } - } - } - return transitions; - } - - pub fn reset(this: *@This()) void { - this.properties = null; - this.durations = null; - this.delays = null; - this.timing_functions = null; - this.has_any = false; - } -}; - -fn expandProperties(properties: *css.SmallList(PropertyId, 1), context: *css.PropertyHandlerContext) ?SmallList(PropertyId, 1) { - const replace = struct { - inline fn replace(allocator: Allocator, propertiez: anytype, props: []const PropertyId, i: u32) void { - propertiez.mut(i).* = props[0].deepClone(allocator); - if (props.len > 1) { - propertiez.insertSlice(allocator, i + 1, props[1..]); - } - } - }.replace; - - var rtl_properties: ?SmallList(PropertyId, 1) = null; - var i: u32 = 0; - - // Expand logical properties in place. - while (i < properties.len()) { - const result = getLogicalProperties(properties.at(i)); - if (result == .block and context.shouldCompileLogical(result.block[0])) { - replace(context.allocator, properties, result.block[1], i); - if (rtl_properties) |*rtl| { - replace(context.allocator, rtl, result.block[1], i); - } - i += 1; - } else if (result == .@"inline" and context.shouldCompileLogical(result.@"inline"[0])) { - const ltr = result.@"inline"[1]; - const rtl = result.@"inline"[2]; - // Clone properties to create RTL version only when needed. - if (rtl_properties == null) { - rtl_properties = properties.deepClone(context.allocator); - } - - replace(context.allocator, properties, ltr, i); - if (rtl_properties) |*rtl_props| { - replace(context.allocator, rtl_props, rtl, i); - } - - i += @intCast(ltr.len); - } else { - // Expand vendor prefixes for targets. - properties.mut(i).setPrefixesForTargets(context.targets); - - // Expand mask properties, which use different vendor-prefixed names. - if (css.css_properties.masking.getWebkitMaskProperty(properties.at(i))) |property_id| { - if (context.targets.prefixes(VendorPrefix.NONE, Feature.mask_border).webkit) { - properties.insert(context.allocator, i, property_id); - i += 1; - } - } - - if (rtl_properties) |*rtl_props| { - rtl_props.mut(i).setPrefixesForTargets(context.targets); - - if (css.css_properties.masking.getWebkitMaskProperty(rtl_props.at(i))) |property_id| { - if (context.targets.prefixes(VendorPrefix.NONE, Feature.mask_border).webkit) { - rtl_props.insert(context.allocator, i, property_id); - i += 1; - } - } - } - i += 1; - } - } - - return rtl_properties; -} - -const LogicalPropertyId = union(enum) { - none, - block: struct { css.compat.Feature, []const PropertyId }, - @"inline": struct { css.compat.Feature, []const PropertyId, []const PropertyId }, -}; - -fn getLogicalProperties(property_id: *const PropertyId) LogicalPropertyId { - return switch (property_id.*) { - .@"block-size" => .{ .block = .{ .logical_size, &[_]PropertyId{.height} } }, - .@"inline-size" => .{ .@"inline" = .{ .logical_size, &[_]PropertyId{.width}, &[_]PropertyId{.height} } }, - .@"min-block-size" => .{ .block = .{ .logical_size, &[_]PropertyId{.@"min-height"} } }, - .@"max-block-size" => .{ .block = .{ .logical_size, &[_]PropertyId{.@"max-height"} } }, - .@"min-inline-size" => .{ .@"inline" = .{ .logical_size, &[_]PropertyId{.@"min-width"}, &[_]PropertyId{.@"min-height"} } }, - .@"max-inline-size" => .{ .@"inline" = .{ .logical_size, &[_]PropertyId{.@"max-width"}, &[_]PropertyId{.@"max-height"} } }, - - .@"inset-block-start" => .{ .block = .{ .logical_inset, &[_]PropertyId{.top} } }, - .@"inset-block-end" => .{ .block = .{ .logical_inset, &[_]PropertyId{.bottom} } }, - .@"inset-inline-start" => .{ .@"inline" = .{ .logical_inset, &[_]PropertyId{.left}, &[_]PropertyId{.right} } }, - .@"inset-inline-end" => .{ .@"inline" = .{ .logical_inset, &[_]PropertyId{.right}, &[_]PropertyId{.left} } }, - .@"inset-block" => .{ .block = .{ .logical_inset, &[_]PropertyId{ .top, .bottom } } }, - .@"inset-inline" => .{ .block = .{ .logical_inset, &[_]PropertyId{ .left, .right } } }, - .inset => .{ .block = .{ .logical_inset, &[_]PropertyId{ .top, .bottom, .left, .right } } }, - - .@"margin-block-start" => .{ .block = .{ .logical_margin, &[_]PropertyId{.@"margin-top"} } }, - .@"margin-block-end" => .{ .block = .{ .logical_margin, &[_]PropertyId{.@"margin-bottom"} } }, - .@"margin-inline-start" => .{ .@"inline" = .{ .logical_margin, &[_]PropertyId{.@"margin-left"}, &[_]PropertyId{.@"margin-right"} } }, - .@"margin-inline-end" => .{ .@"inline" = .{ .logical_margin, &[_]PropertyId{.@"margin-right"}, &[_]PropertyId{.@"margin-left"} } }, - .@"margin-block" => .{ .block = .{ .logical_margin, &[_]PropertyId{ .@"margin-top", .@"margin-bottom" } } }, - .@"margin-inline" => .{ .block = .{ .logical_margin, &[_]PropertyId{ .@"margin-left", .@"margin-right" } } }, - - .@"padding-block-start" => .{ .block = .{ .logical_padding, &[_]PropertyId{.@"padding-top"} } }, - .@"padding-block-end" => .{ .block = .{ .logical_padding, &[_]PropertyId{.@"padding-bottom"} } }, - .@"padding-inline-start" => .{ .@"inline" = .{ .logical_padding, &[_]PropertyId{.@"padding-left"}, &[_]PropertyId{.@"padding-right"} } }, - .@"padding-inline-end" => .{ .@"inline" = .{ .logical_padding, &[_]PropertyId{.@"padding-right"}, &[_]PropertyId{.@"padding-left"} } }, - .@"padding-block" => .{ .block = .{ .logical_padding, &[_]PropertyId{ .@"padding-top", .@"padding-bottom" } } }, - .@"padding-inline" => .{ .block = .{ .logical_padding, &[_]PropertyId{ .@"padding-left", .@"padding-right" } } }, - - .@"border-block-start" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top"} } }, - .@"border-block-start-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top-width"} } }, - .@"border-block-start-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top-color"} } }, - .@"border-block-start-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-top-style"} } }, - - .@"border-block-end" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom"} } }, - .@"border-block-end-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom-width"} } }, - .@"border-block-end-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom-color"} } }, - .@"border-block-end-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{.@"border-bottom-style"} } }, - - .@"border-inline-start" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left"}, &[_]PropertyId{.@"border-right"} } }, - .@"border-inline-start-width" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left-width"}, &[_]PropertyId{.@"border-right-width"} } }, - .@"border-inline-start-color" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left-color"}, &[_]PropertyId{.@"border-right-color"} } }, - .@"border-inline-start-style" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-left-style"}, &[_]PropertyId{.@"border-right-style"} } }, - - .@"border-inline-end" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right"}, &[_]PropertyId{.@"border-left"} } }, - .@"border-inline-end-width" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right-width"}, &[_]PropertyId{.@"border-left-width"} } }, - .@"border-inline-end-color" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right-color"}, &[_]PropertyId{.@"border-left-color"} } }, - .@"border-inline-end-style" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{.@"border-right-style"}, &[_]PropertyId{.@"border-left-style"} } }, - - .@"border-block" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top", .@"border-bottom" } } }, - .@"border-block-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top-color", .@"border-bottom-color" } } }, - .@"border-block-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top-width", .@"border-bottom-width" } } }, - .@"border-block-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-top-style", .@"border-bottom-style" } } }, - - .@"border-inline" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left", .@"border-right" } } }, - .@"border-inline-color" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left-color", .@"border-right-color" } } }, - .@"border-inline-width" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left-width", .@"border-right-width" } } }, - .@"border-inline-style" => .{ .block = .{ .logical_borders, &[_]PropertyId{ .@"border-left-style", .@"border-right-style" } } }, - - .@"border-start-start-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-top-left-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-top-right-radius" = VendorPrefix.NONE }} } }, - .@"border-start-end-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-top-right-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-top-left-radius" = VendorPrefix.NONE }} } }, - .@"border-end-start-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-bottom-left-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-bottom-right-radius" = VendorPrefix.NONE }} } }, - .@"border-end-end-radius" => .{ .@"inline" = .{ .logical_borders, &[_]PropertyId{PropertyId{ .@"border-bottom-right-radius" = VendorPrefix.NONE }}, &[_]PropertyId{PropertyId{ .@"border-bottom-left-radius" = VendorPrefix.NONE }} } }, - - else => .none, - }; -} - -fn isTransitionProperty(property_id: *const PropertyId) bool { - return switch (property_id.*) { - .@"transition-property", - .@"transition-duration", - .@"transition-delay", - .@"transition-timing-function", - .transition, - => true, - else => false, - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/properties/ui.zig b/src/css/properties/ui.zig deleted file mode 100644 index 4e274e3ee2c1..000000000000 --- a/src/css/properties/ui.zig +++ /dev/null @@ -1,212 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const SmallList = css.SmallList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -const CSSNumber = css.css_values.number.CSSNumber; -const DashedIdent = css.css_values.ident.DashedIdent; -const CssColor = css.css_values.color.CssColor; -const Url = css.css_values.url.Url; - -/// A value for the [color-scheme](https://drafts.csswg.org/css-color-adjust/#color-scheme-prop) property. -pub const ColorScheme = packed struct(u8) { - /// Indicates that the element supports a light color scheme. - light: bool = false, - /// Indicates that the element supports a dark color scheme. - dark: bool = false, - /// Forbids the user agent from overriding the color scheme for the element. - only: bool = false, - __unused: u5 = 0, - - pub fn eql(a: ColorScheme, b: ColorScheme) bool { - return a == b; - } - - const Map = bun.ComptimeEnumMap(enum { normal, only, light, dark }); - - pub fn parse(input: *css.Parser) css.Result(ColorScheme) { - var res = ColorScheme{}; - const ident = switch (input.expectIdent()) { - .result => |ident| ident, - .err => |e| return .{ .err = e }, - }; - - if (Map.get(ident)) |value| switch (value) { - .normal => return .{ .result = res }, - .only => res.only = true, - .light => res.light = true, - .dark => res.dark = true, - }; - - while (input.tryParse(css.Parser.expectIdent, .{}).asValue()) |i| { - if (Map.get(i)) |value| switch (value) { - .normal => return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - .only => { - // Only must be at the start or the end, not in the middle - if (res.only) { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - res.only = true; - return .{ .result = res }; - }, - .light => res.light = true, - .dark => res.dark = true, - }; - } - - return .{ .result = res }; - } - - pub fn toCss(this: *const ColorScheme, dest: *Printer) css.PrintErr!void { - if (this.* == ColorScheme{}) { - return dest.writeStr("normal"); - } - - if (this.light) { - try dest.writeStr("light"); - if (this.dark) { - try dest.writeChar(' '); - } - } - - if (this.dark) { - try dest.writeStr("dark"); - } - - if (this.only) { - try dest.writeStr(" only"); - } - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [resize](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#resize) property. -pub const Resize = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [cursor](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#cursor) property. -pub const Cursor = struct { - /// A list of cursor images. - images: SmallList(CursorImage), - /// A pre-defined cursor. - keyword: CursorKeyword, -}; - -/// A [cursor image](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#cursor) value, used in the `cursor` property. -/// -/// See [Cursor](Cursor). -pub const CursorImage = struct { - /// A url to the cursor image. - url: Url, - /// The location in the image where the mouse pointer appears. - hotspot: ?[2]CSSNumber, -}; - -/// A pre-defined [cursor](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#cursor) value, -/// used in the `cursor` property. -/// -/// See [Cursor](Cursor). -pub const CursorKeyword = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [caret-color](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#caret-color) property. -pub const ColorOrAuto = union(enum) { - /// The `currentColor`, adjusted by the UA to ensure contrast against the background. - auto, - /// A color. - color: CssColor, -}; - -/// A value for the [caret-shape](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#caret-shape) property. -pub const CaretShape = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [caret](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#caret) shorthand property. -pub const Caret = @compileError(css.todo_stuff.depth); - -/// A value for the [user-select](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#content-selection) property. -pub const UserSelect = css.DefineEnumProperty(@compileError(css.todo_stuff.depth)); - -/// A value for the [appearance](https://www.w3.org/TR/2021/WD-css-ui-4-20210316/#appearance-switching) property. -pub const Appearance = union(enum) { - none, - auto, - textfield, - menulist_button, - button, - checkbox, - listbox, - menulist, - meter, - progress_bar, - push_button, - radio, - searchfield, - slider_horizontal, - square_button, - textarea, - non_standard: []const u8, -}; - -pub const ColorSchemeHandler = struct { - pub fn handleProperty(_: *@This(), property: *const css.Property, dest: *css.DeclarationList, context: *css.PropertyHandlerContext) bool { - switch (property.*) { - .@"color-scheme" => |*color_scheme_| { - const color_scheme: *const ColorScheme = color_scheme_; - if (!context.targets.isCompatible(css.compat.Feature.light_dark)) { - if (color_scheme.light) { - dest.append( - context.allocator, - defineVar(context.allocator, "--buncss-light", .{ .ident = "initial" }), - ) catch |err| bun.handleOom(err); - dest.append( - context.allocator, - defineVar(context.allocator, "--buncss-dark", .{ .whitespace = " " }), - ) catch |err| bun.handleOom(err); - - if (color_scheme.dark) { - context.addDarkRule( - context.allocator, - defineVar(context.allocator, "--buncss-light", .{ .whitespace = " " }), - ); - context.addDarkRule( - context.allocator, - defineVar(context.allocator, "--buncss-dark", .{ .ident = "initial" }), - ); - } - } else if (color_scheme.dark) { - bun.handleOom(dest.append(context.allocator, defineVar(context.allocator, "--buncss-light", .{ .whitespace = " " }))); - bun.handleOom(dest.append(context.allocator, defineVar(context.allocator, "--buncss-dark", .{ .ident = "initial" }))); - } - } - bun.handleOom(dest.append(context.allocator, property.deepClone(context.allocator))); - return true; - }, - else => return false, - } - } - - pub fn finalize(_: *@This(), _: *css.DeclarationList, _: *css.PropertyHandlerContext) void {} -}; - -fn defineVar(allocator: Allocator, name: []const u8, value: css.Token) css.Property { - return css.Property{ - .custom = css.css_properties.custom.CustomProperty{ - .name = css.css_properties.custom.CustomPropertyName{ .custom = css.DashedIdent{ .v = name } }, - .value = css.TokenList{ - .v = brk: { - var list = ArrayList(css.css_properties.custom.TokenOrValue){}; - bun.handleOom(list.append(allocator, css.css_properties.custom.TokenOrValue{ .token = value })); - break :brk list; - }, - }, - }, - }; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/rules/container.zig b/src/css/rules/container.zig deleted file mode 100644 index a125ac92c2ed..000000000000 --- a/src/css/rules/container.zig +++ /dev/null @@ -1,350 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const CustomIdent = css.css_values.ident.CustomIdent; -const CustomIdentFns = css.css_values.ident.CustomIdentFns; -const QueryFeature = css.media_query.QueryFeature; -const QueryConditionFlags = css.media_query.QueryConditionFlags; -const Operator = css.media_query.Operator; - -pub const ContainerName = struct { - v: css.css_values.ident.CustomIdent, - pub fn parse(input: *css.Parser) Result(ContainerName) { - const ident = switch (CustomIdentFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - // todo_stuff.match_ignore_ascii_case; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("none", ident.v) or - bun.strings.eqlCaseInsensitiveASCIIICheckLength("and", ident.v) or - bun.strings.eqlCaseInsensitiveASCIIICheckLength("not", ident.v) or - bun.strings.eqlCaseInsensitiveASCIIICheckLength("or", ident.v)) - return .{ .err = input.newUnexpectedTokenError(.{ .ident = ident.v }) }; - - return .{ .result = ContainerName{ .v = ident } }; - } - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - return try CustomIdentFns.toCss(&this.v, dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const ContainerNameFns = ContainerName; -pub const ContainerSizeFeature = QueryFeature(ContainerSizeFeatureId); - -pub const ContainerSizeFeatureId = enum { - /// The [width](https://w3c.github.io/csswg-drafts/css-contain-3/#width) size container feature. - width, - /// The [height](https://w3c.github.io/csswg-drafts/css-contain-3/#height) size container feature. - height, - /// The [inline-size](https://w3c.github.io/csswg-drafts/css-contain-3/#inline-size) size container feature. - @"inline-size", - /// The [block-size](https://w3c.github.io/csswg-drafts/css-contain-3/#block-size) size container feature. - @"block-size", - /// The [aspect-ratio](https://w3c.github.io/csswg-drafts/css-contain-3/#aspect-ratio) size container feature. - @"aspect-ratio", - /// The [orientation](https://w3c.github.io/csswg-drafts/css-contain-3/#orientation) size container feature. - orientation, - - pub const valueType = css.DeriveValueType(@This(), ValueTypeMap).valueType; - - pub const ValueTypeMap = .{ - .width = css.MediaFeatureType.length, - .height = css.MediaFeatureType.length, - .@"inline-size" = css.MediaFeatureType.length, - .@"block-size" = css.MediaFeatureType.length, - .@"aspect-ratio" = css.MediaFeatureType.ratio, - .orientation = css.MediaFeatureType.ident, - }; - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn toCssWithPrefix(this: *const @This(), prefix: []const u8, dest: *Printer) PrintErr!void { - try dest.writeStr(prefix); - try this.toCss(dest); - } -}; - -/// Represents a style query within a container condition. -pub const StyleQuery = union(enum) { - /// A style feature, implicitly parenthesized. - feature: css.Property, - - /// A negation of a condition. - not: *StyleQuery, - - /// A set of joint operations. - operation: struct { - /// The operator for the conditions. - operator: css.media_query.Operator, - /// The conditions for the operator. - conditions: ArrayList(StyleQuery), - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - - pub fn toCss(this: *const StyleQuery, dest: *Printer) PrintErr!void { - switch (this.*) { - .feature => |f| try f.toCss(dest, false), - .not => |c| { - try dest.writeStr("not "); - return try css.media_query.toCssWithParensIfNeeded( - c, - dest, - c.needsParens(null, &dest.targets), - ); - }, - .operation => |op| return css.media_query.operationToCss( - StyleQuery, - op.operator, - &op.conditions, - dest, - ), - } - } - - pub fn parseFeature(input: *css.Parser) Result(StyleQuery) { - const property_id = switch (css.PropertyId.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectColon().asErr()) |e| return .{ .err = e }; - input.skipWhitespace(); - const opts = css.ParserOptions.default(input.allocator(), null); - const feature: StyleQuery = .{ - .feature = switch (css.Property.parse( - property_id, - input, - &opts, - )) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - }; - _ = input.tryParse(css.parseImportant, .{}); - return .{ .result = feature }; - } - - pub fn createNegation(condition: *StyleQuery) StyleQuery { - return .{ .not = condition }; - } - - pub fn createOperation(operator: Operator, conditions: ArrayList(StyleQuery)) StyleQuery { - return .{ - .operation = .{ - .operator = operator, - .conditions = conditions, - }, - }; - } - - pub fn needsParens( - this: *const StyleQuery, - parent_operator: ?Operator, - _: *const css.Targets, - ) bool { - return switch (this.*) { - .not => true, - .operation => |op| op.operator == parent_operator, - .feature => true, - }; - } - - pub fn parseStyleQuery(input: *css.Parser) Result(@This()) { - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const ContainerCondition = union(enum) { - /// A size container feature, implicitly parenthesized. - feature: ContainerSizeFeature, - /// A negation of a condition. - not: *ContainerCondition, - /// A set of joint operations. - operation: struct { - /// The operator for the conditions. - operator: css.media_query.Operator, - /// The conditions for the operator. - conditions: ArrayList(ContainerCondition), - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - /// A style query. - style: StyleQuery, - - const This = @This(); - - pub fn parse(input: *css.Parser) Result(ContainerCondition) { - return css.media_query.parseQueryCondition( - ContainerCondition, - input, - QueryConditionFlags{ - .allow_or = true, - .allow_style = true, - }, - ); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - switch (this.*) { - .feature => |f| try f.toCss(dest), - .not => |c| { - try dest.writeStr("not "); - return try css.media_query.toCssWithParensIfNeeded( - c, - dest, - c.needsParens(null, &dest.targets), - ); - }, - .operation => |op| try css.media_query.operationToCss(ContainerCondition, op.operator, &op.conditions, dest), - .style => |query| { - try dest.writeStr("style("); - try query.toCss(dest); - try dest.writeChar(')'); - }, - } - } - - pub fn parseFeature(input: *css.Parser) Result(ContainerCondition) { - const feature = switch (QueryFeature(ContainerSizeFeatureId).parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .feature = feature } }; - } - - pub fn createNegation(condition: *ContainerCondition) ContainerCondition { - return .{ .not = condition }; - } - - pub fn createOperation(operator: Operator, conditions: ArrayList(ContainerCondition)) ContainerCondition { - return .{ - .operation = .{ - .operator = operator, - .conditions = conditions, - }, - }; - } - - pub fn parseStyleQuery(input: *css.Parser) Result(ContainerCondition) { - const Fns = struct { - pub inline fn adaptedParseQueryCondition(i: *css.Parser, flags: QueryConditionFlags) Result(StyleQuery) { - return css.media_query.parseQueryCondition(StyleQuery, i, flags); - } - - pub fn parseNestedBlockFn(_: void, i: *css.Parser) Result(ContainerCondition) { - if (i.tryParse( - @This().adaptedParseQueryCondition, - .{ - QueryConditionFlags{ .allow_or = true }, - }, - ).asValue()) |res| { - return .{ .result = .{ .style = res } }; - } - - return .{ .result = .{ - .style = switch (StyleQuery.parseFeature(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - } }; - } - }; - return input.parseNestedBlock(ContainerCondition, {}, Fns.parseNestedBlockFn); - } - - pub fn needsParens( - this: *const ContainerCondition, - parent_operator: ?Operator, - targets: *const css.Targets, - ) bool { - return switch (this.*) { - .not => true, - .operation => |op| op.operator == parent_operator, - .feature => |f| f.needsParens(parent_operator, targets), - .style => false, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [@container](https://drafts.csswg.org/css-contain-3/#container-rule) rule. -pub fn ContainerRule(comptime R: type) type { - return struct { - /// The name of the container. - name: ?ContainerName, - /// The container condition. - condition: ContainerCondition, - /// The rules within the `@container` rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@container "); - if (this.name) |*name| { - try name.toCss(dest); - try dest.writeChar(' '); - } - - // Don't downlevel range syntax in container queries. - const exclude = dest.targets.exclude; - bun.bits.insert(css.targets.Features, &dest.targets.exclude, .media_queries); - try this.condition.toCss(dest); - dest.targets.exclude = exclude; - - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - try this.rules.toCss(dest); - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/counter_style.zig b/src/css/rules/counter_style.zig deleted file mode 100644 index b1212986cb82..000000000000 --- a/src/css/rules/counter_style.zig +++ /dev/null @@ -1,31 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; - -/// A [@counter-style](https://drafts.csswg.org/css-counter-styles/#the-counter-style-rule) rule. -pub const CounterStyleRule = struct { - /// The name of the counter style to declare. - name: css.css_values.ident.CustomIdent, - /// Declarations in the `@counter-style` rule. - declarations: css.DeclarationBlock, - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@counter-style"); - try css.css_values.ident.CustomIdentFns.toCss(&this.name, dest); - try this.declarations.toCssBlock(dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const std = @import("std"); diff --git a/src/css/rules/custom_media.zig b/src/css/rules/custom_media.zig deleted file mode 100644 index eb5cf66c665e..000000000000 --- a/src/css/rules/custom_media.zig +++ /dev/null @@ -1,38 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const css_values = @import("../values/values.zig"); -pub const Error = css.Error; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -/// A [@custom-media](https://drafts.csswg.org/mediaqueries-5/#custom-mq) rule. -pub const CustomMediaRule = struct { - /// The name of the declared media query. - name: css_values.ident.DashedIdent, - /// The media query to declare. - query: css.MediaList, - /// The location of the rule in the source file. - loc: css.Location, - - const This = @This(); - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return This{ - .name = this.name, - .query = this.query.deepClone(allocator), - .loc = this.loc, - }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - try dest.writeStr("@custom-media "); - try css_values.ident.DashedIdentFns.toCss(&this.name, dest); - try dest.writeChar(' '); - try this.query.toCss(dest); - try dest.writeChar(';'); - } -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/rules/document.zig b/src/css/rules/document.zig deleted file mode 100644 index e007ab14dc71..000000000000 --- a/src/css/rules/document.zig +++ /dev/null @@ -1,39 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; - -/// A [@-moz-document](https://www.w3.org/TR/2012/WD-css3-conditional-20120911/#at-document) rule. -/// -/// Note that only the `url-prefix()` function with no arguments is supported, and only the `-moz` prefix -/// is allowed since Firefox was the only browser that ever implemented this rule. -pub fn MozDocumentRule(comptime R: type) type { - return struct { - /// Nested rules within the `@-moz-document` rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - try dest.writeStr("@-moz-document url-prefix()"); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - try this.rules.toCss(dest); - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -const std = @import("std"); diff --git a/src/css/rules/font_face.zig b/src/css/rules/font_face.zig deleted file mode 100644 index 1622f2ad403f..000000000000 --- a/src/css/rules/font_face.zig +++ /dev/null @@ -1,738 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const Maybe = css.Maybe; -const PrintErr = css.PrintErr; -const Url = css.css_values.url.Url; -const Size2D = css.css_values.size.Size2D; -const fontprops = css.css_properties.font; -const Location = css.css_rules.Location; -const Angle = css.css_values.angle.Angle; -const FontStyleProperty = css.css_properties.font.FontStyle; -const FontFamily = css.css_properties.font.FontFamily; -const FontWeight = css.css_properties.font.FontWeight; -const FontStretch = css.css_properties.font.FontStretch; -const CustomProperty = css.css_properties.custom.CustomProperty; -const CustomPropertyName = css.css_properties.custom.CustomPropertyName; -const Result = css.Result; - -/// A property within an `@font-face` rule. -/// -/// See [FontFaceRule](FontFaceRule). -pub const FontFaceProperty = union(enum) { - /// The `src` property. - source: ArrayList(Source), - - /// The `font-family` property. - font_family: fontprops.FontFamily, - - /// The `font-style` property. - font_style: FontStyle, - - /// The `font-weight` property. - font_weight: Size2D(fontprops.FontWeight), - - /// The `font-stretch` property. - font_stretch: Size2D(fontprops.FontStretch), - - /// The `unicode-range` property. - unicode_range: ArrayList(UnicodeRange), - - /// An unknown or unsupported property. - custom: css.css_properties.custom.CustomProperty, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - const Helpers = struct { - pub fn writeProperty( - d: *Printer, - comptime prop: []const u8, - value: anytype, - comptime multi: bool, - ) PrintErr!void { - try d.writeStr(prop); - try d.delim(':', false); - if (comptime multi) { - const len = value.items.len; - for (value.items, 0..) |*val, idx| { - try val.toCss(d); - if (idx < len - 1) { - try d.delim(',', false); - } - } - } else { - try value.toCss(d); - } - } - }; - return switch (this.*) { - .source => |value| Helpers.writeProperty(dest, "src", value, true), - .font_family => |value| Helpers.writeProperty(dest, "font-family", value, false), - .font_style => |value| Helpers.writeProperty(dest, "font-style", value, false), - .font_weight => |value| Helpers.writeProperty(dest, "font-weight", value, false), - .font_stretch => |value| Helpers.writeProperty(dest, "font-stretch", value, false), - .unicode_range => |value| Helpers.writeProperty(dest, "unicode-range", value, true), - .custom => |custom| { - try dest.writeStr(this.custom.name.asStr()); - try dest.delim(':', false); - return custom.value.toCss(dest, true); - }, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A contiguous range of Unicode code points. -/// -/// Cannot be empty. Can represent a single code point when start == end. -pub const UnicodeRange = struct { - /// Inclusive start of the range. In [0, end]. - start: u32, - - /// Inclusive end of the range. In [0, 0x10FFFF]. - end: u32, - - pub fn toCss(this: *const UnicodeRange, dest: *Printer) PrintErr!void { - // Attempt to optimize the range to use question mark syntax. - if (this.start != this.end) { - // Find the first hex digit that differs between the start and end values. - var shift: u5 = 24; - var mask: u32 = @as(u32, 0xf) << shift; - while (shift > 0) { - const c1 = this.start & mask; - const c2 = this.end & mask; - if (c1 != c2) { - break; - } - - mask = mask >> 4; - shift -= 4; - } - - // Get the remainder of the value. This must be 0x0 to 0xf for the rest - // of the value to use the question mark syntax. - shift += 4; - const remainder_mask: u32 = (@as(u32, 1) << shift) - @as(u32, 1); - const start_remainder = this.start & remainder_mask; - const end_remainder = this.end & remainder_mask; - - if (start_remainder == 0 and end_remainder == remainder_mask) { - const start = (this.start & ~remainder_mask) >> shift; - if (start != 0) { - try dest.writeFmt("U+{x}", .{start}); - } else { - try dest.writeStr("U+"); - } - - while (shift > 0) { - try dest.writeChar('?'); - shift -= 4; - } - - return; - } - } - - try dest.writeFmt("U+{x}", .{this.start}); - if (this.end != this.start) { - try dest.writeFmt("-{x}", .{this.end}); - } - } - - /// https://drafts.csswg.org/css-syntax/#urange-syntax - pub fn parse(input: *css.Parser) Result(UnicodeRange) { - // = - // u '+' '?'* | - // u '?'* | - // u '?'* | - // u | - // u | - // u '+' '?'+ - - if (input.expectIdentMatching("u").asErr()) |e| return .{ .err = e }; - const after_u = input.position(); - if (parseTokens(input).asErr()) |e| return .{ .err = e }; - - // This deviates from the spec in case there are CSS comments - // between tokens in the middle of one , - // but oh well… - const concatenated_tokens = input.sliceFrom(after_u); - - const range = if (parseConcatenated(concatenated_tokens).asValue()) |range| - range - else - return .{ .err = input.newBasicUnexpectedTokenError(.{ .ident = concatenated_tokens }) }; - - if (range.end > 0x10FFFF or range.start > range.end) { - return .{ .err = input.newBasicUnexpectedTokenError(.{ .ident = concatenated_tokens }) }; - } - - return .{ .result = range }; - } - - fn parseTokens(input: *css.Parser) Result(void) { - const tok = switch (input.nextIncludingWhitespace()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - switch (tok.*) { - .dimension => return parseQuestionMarks(input), - .number => { - const after_number = input.state(); - const token = switch (input.nextIncludingWhitespace()) { - .result => |vv| vv, - .err => { - input.reset(&after_number); - return .success; - }, - }; - - if (token.* == .delim and token.delim == '?') return parseQuestionMarks(input); - if (token.* == .delim or token.* == .number) return .success; - return .success; - }, - .delim => |c| { - if (c == '+') { - const next = switch (input.nextIncludingWhitespace()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (!(next.* == .ident or (next.* == .delim and next.delim == '?'))) { - return .{ .err = input.newBasicUnexpectedTokenError(next.*) }; - } - return parseQuestionMarks(input); - } - }, - else => {}, - } - return .{ .err = input.newBasicUnexpectedTokenError(tok.*) }; - } - - /// Consume as many '?' as possible - fn parseQuestionMarks(input: *css.Parser) Result(void) { - while (true) { - const start = input.state(); - if (input.nextIncludingWhitespace().asValue()) |tok| if (tok.* == .delim and tok.delim == '?') continue; - input.reset(&start); - return .success; - } - } - - fn parseConcatenated(_text: []const u8) css.Maybe(UnicodeRange, void) { - var text = if (_text.len > 0 and _text[0] == '+') _text[1..] else { - return .{ .err = {} }; - }; - const first_hex_value, const hex_digit_count = consumeHex(&text); - const question_marks = consumeQuestionMarks(&text); - const consumed = hex_digit_count + question_marks; - - if (consumed == 0 or consumed > 6) { - return .{ .err = {} }; - } - - if (question_marks > 0) { - if (text.len == 0) return .{ .result = UnicodeRange{ - .start = first_hex_value << @intCast(question_marks * 4), - .end = ((first_hex_value + 1) << @intCast(question_marks * 4)) - 1, - } }; - } else if (text.len == 0) { - return .{ .result = UnicodeRange{ - .start = first_hex_value, - .end = first_hex_value, - } }; - } else { - if (text.len > 0 and text[0] == '-') { - text = text[1..]; - const second_hex_value, const hex_digit_count2 = consumeHex(&text); - if (hex_digit_count2 > 0 and hex_digit_count2 <= 6 and text.len == 0) { - return .{ .result = UnicodeRange{ - .start = first_hex_value, - .end = second_hex_value, - } }; - } - } - } - return .{ .err = {} }; - } - - fn consumeQuestionMarks(text: *[]const u8) usize { - var question_marks: usize = 0; - while (bun.strings.splitFirstWithExpected(text.*, '?')) |rest| { - question_marks += 1; - text.* = rest; - } - return question_marks; - } - - fn consumeHex(text: *[]const u8) struct { u32, usize } { - var value: u32 = 0; - var digits: usize = 0; - while (bun.strings.splitFirst(text.*)) |result| { - if (toHexDigit(result.first)) |digit_value| { - value = value * 0x10 + digit_value; - digits += 1; - text.* = result.rest; - } else { - break; - } - } - return .{ value, digits }; - } - - fn toHexDigit(b: u8) ?u32 { - var digit = @as(u32, b) -% @as(u32, '0'); - if (digit < 10) return digit; - // Force the 6th bit to be set to ensure ascii is lower case. - // digit = (@as(u32, b) | 0b10_0000).wrapping_sub('a' as u32).saturating_add(10); - digit = ((@as(u32, b) | 0b10_0000) -% @as(u32, 'a')) +| 10; - return if (digit < 16) digit else null; - } -}; - -pub const FontStyle = union(enum) { - /// Normal font style. - normal, - - /// Italic font style. - italic, - - /// Oblique font style, with a custom angle. - oblique: Size2D(css.css_values.angle.Angle), - - pub fn parse(input: *css.Parser) Result(FontStyle) { - const property = switch (FontStyleProperty.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = switch (property) { - .normal => .normal, - .italic => .italic, - .oblique => |angle| { - const second_angle = if (input.tryParse(css.css_values.angle.Angle.parse, .{}).asValue()) |a| a else angle; - return .{ .result = .{ - .oblique = .{ .a = angle, .b = second_angle }, - } }; - }, - }, - }; - } - - pub fn toCss(this: *const FontStyle, dest: *Printer) PrintErr!void { - switch (this.*) { - .normal => try dest.writeStr("normal"), - .italic => try dest.writeStr("italic"), - .oblique => |angle| { - try dest.writeStr("oblique"); - if (!angle.eql(&FontStyle.defaultObliqueAngle())) { - try dest.writeChar(' '); - try angle.toCss(dest); - } - }, - } - } - - fn defaultObliqueAngle() Size2D(Angle) { - return Size2D(Angle){ - .a = FontStyleProperty.defaultObliqueAngle(), - .b = FontStyleProperty.defaultObliqueAngle(), - }; - } -}; - -/// A font format keyword in the `format()` function of the -/// [src](https://drafts.csswg.org/css-fonts/#src-desc) -/// property of an `@font-face` rule. -pub const FontFormat = union(enum) { - /// A WOFF 1.0 font. - woff, - - /// A WOFF 2.0 font. - woff2, - - /// A TrueType font. - truetype, - - /// An OpenType font. - opentype, - - /// An Embedded OpenType (.eot) font. - embedded_opentype, - - /// OpenType Collection. - collection, - - /// An SVG font. - svg, - - /// An unknown format. - string: []const u8, - - pub fn parse(input: *css.Parser) Result(FontFormat) { - const s = switch (input.expectIdentOrString()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("woff", s)) { - return .{ .result = .woff }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("woff2", s)) { - return .{ .result = .woff2 }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("truetype", s)) { - return .{ .result = .truetype }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("opentype", s)) { - return .{ .result = .opentype }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("embedded-opentype", s)) { - return .{ .result = .embedded_opentype }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("collection", s)) { - return .{ .result = .collection }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("svg", s)) { - return .{ .result = .svg }; - } else { - return .{ .result = .{ .string = s } }; - } - } - - pub fn toCss(this: *const FontFormat, dest: *Printer) PrintErr!void { - // Browser support for keywords rather than strings is very limited. - // https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src - switch (this.*) { - .woff => try dest.writeStr("woff"), - .woff2 => try dest.writeStr("woff2"), - .truetype => try dest.writeStr("truetype"), - .opentype => try dest.writeStr("opentype"), - .embedded_opentype => try dest.writeStr("embedded-opentype"), - .collection => try dest.writeStr("collection"), - .svg => try dest.writeStr("svg"), - .string => try dest.writeStr(this.string), - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [src](https://drafts.csswg.org/css-fonts/#src-desc) -/// property in an `@font-face` rule. -pub const Source = union(enum) { - /// A `url()` with optional format metadata. - url: UrlSource, - - /// The `local()` function. - local: fontprops.FontFamily, - - pub fn parse(input: *css.Parser) Result(Source) { - switch (input.tryParse(UrlSource.parse, .{})) { - .result => |url| .{ .result = return .{ .result = .{ .url = url } } }, - .err => |e| { - if (e.kind == .basic and e.kind.basic == .at_rule_body_invalid) { - return .{ .err = e }; - } - }, - } - - if (input.expectFunctionMatching("local").asErr()) |e| return .{ .err = e }; - - const Fn = struct { - pub fn parseNestedBlock(_: void, i: *css.Parser) Result(fontprops.FontFamily) { - return fontprops.FontFamily.parse(i); - } - }; - const local = switch (input.parseNestedBlock(fontprops.FontFamily, {}, Fn.parseNestedBlock)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .local = local } }; - } - - pub fn toCss(this: *const Source, dest: *Printer) PrintErr!void { - switch (this.*) { - .url => try this.url.toCss(dest), - .local => { - try dest.writeStr("local("); - try this.local.toCss(dest); - try dest.writeChar(')'); - }, - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const FontTechnology = enum { - /// A font format keyword in the `format()` function of the - /// [src](https://drafts.csswg.org/css-fonts/#src-desc) - /// property of an `@font-face` rule. - /// A font features tech descriptor in the `tech()`function of the - /// [src](https://drafts.csswg.org/css-fonts/#font-features-tech-values) - /// property of an `@font-face` rule. - /// Supports OpenType Features. - /// https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist - @"features-opentype", - - /// Supports Apple Advanced Typography Font Features. - /// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM09/AppendixF.html - @"features-aat", - - /// Supports Graphite Table Format. - /// https://scripts.sil.org/cms/scripts/render_download.php?site_id=nrsi&format=file&media_id=GraphiteBinaryFormat_3_0&filename=GraphiteBinaryFormat_3_0.pdf - @"features-graphite", - - /// A color font tech descriptor in the `tech()`function of the - /// [src](https://drafts.csswg.org/css-fonts/#src-desc) - /// property of an `@font-face` rule. - /// Supports the `COLR` v0 table. - @"color-colrv0", - - /// Supports the `COLR` v1 table. - @"color-colrv1", - - /// Supports the `SVG` table. - @"color-svg", - - /// Supports the `sbix` table. - @"color-sbix", - - /// Supports the `CBDT` table. - @"color-cbdt", - - /// Supports Variations - /// The variations tech refers to the support of font variations - variations, - - /// Supports Palettes - /// The palettes tech refers to support for font palettes - palettes, - - /// Supports Incremental - /// The incremental tech refers to client support for incremental font loading, using either the range-request or the patch-subset method - incremental, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -/// A `url()` value for the [src](https://drafts.csswg.org/css-fonts/#src-desc) -/// property in an `@font-face` rule. -pub const UrlSource = struct { - /// The URL. - url: Url, - - /// Optional `format()` function. - format: ?FontFormat, - - /// Optional `tech()` function. - tech: ArrayList(FontTechnology), - - pub fn parse(input: *css.Parser) Result(UrlSource) { - const url = switch (Url.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const format = if (input.tryParse(css.Parser.expectFunctionMatching, .{"format"}).isOk()) format: { - switch (input.parseNestedBlock(FontFormat, {}, css.voidWrap(FontFormat, FontFormat.parse))) { - .result => |vv| break :format vv, - .err => |e| return .{ .err = e }, - } - } else null; - - const tech = if (input.tryParse(css.Parser.expectFunctionMatching, .{"tech"}).isOk()) tech: { - const Fn = struct { - pub fn parseNestedBlockFn(_: void, i: *css.Parser) Result(ArrayList(FontTechnology)) { - return i.parseList(FontTechnology, FontTechnology.parse); - } - }; - break :tech switch (input.parseNestedBlock(ArrayList(FontTechnology), {}, Fn.parseNestedBlockFn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - } else ArrayList(FontTechnology){}; - - return .{ - .result = UrlSource{ .url = url, .format = format, .tech = tech }, - }; - } - - pub fn toCss(this: *const UrlSource, dest: *Printer) PrintErr!void { - try this.url.toCss(dest); - if (this.format) |*format| { - try dest.whitespace(); - try dest.writeStr("format("); - try format.toCss(dest); - try dest.writeChar(')'); - } - - if (this.tech.items.len != 0) { - try dest.whitespace(); - try dest.writeStr("tech("); - try css.to_css.fromList(FontTechnology, this.tech.items, dest); - try dest.writeChar(')'); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [@font-face](https://drafts.csswg.org/css-fonts/#font-face-rule) rule. -pub const FontFaceRule = struct { - /// Declarations in the `@font-face` rule. - properties: ArrayList(FontFaceProperty), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@font-face"); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - const len = this.properties.items.len; - for (this.properties.items, 0..) |*prop, i| { - try dest.newline(); - try prop.toCss(dest); - if (i != len - 1 or !dest.minify) { - try dest.writeChar(';'); - } - } - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const FontFaceDeclarationParser = struct { - const This = @This(); - - pub const AtRuleParser = struct { - pub const Prelude = void; - pub const AtRule = FontFaceProperty; - - pub fn parsePrelude(_: *This, name: []const u8, input: *css.Parser) Result(Prelude) { - return .{ - .err = input.newError(css.BasicParseErrorKind{ .at_rule_invalid = name }), - }; - } - - pub fn parseBlock(_: *This, _: Prelude, _: *const css.ParserState, input: *css.Parser) Result(AtRule) { - return .{ .err = input.newError(css.BasicParseErrorKind{ .at_rule_body_invalid = {} }) }; - } - - pub fn ruleWithoutBlock(_: *This, _: Prelude, _: *const css.ParserState) css.Maybe(AtRule, void) { - return .{ .err = {} }; - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = void; - pub const QualifiedRule = FontFaceProperty; - - pub fn parsePrelude(_: *This, input: *css.Parser) Result(Prelude) { - return .{ .err = input.newError(css.BasicParseErrorKind{ .qualified_rule_invalid = {} }) }; - } - - pub fn parseBlock(_: *This, _: Prelude, _: *const css.ParserState, input: *css.Parser) Result(QualifiedRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - }; - - pub const DeclarationParser = struct { - pub const Declaration = FontFaceProperty; - - pub fn parseValue(this: *This, name: []const u8, input: *css.Parser) Result(Declaration) { - _ = this; // autofix - const state = input.state(); - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "src")) { - if (input.parseCommaSeparated(Source, Source.parse).asValue()) |sources| { - return .{ .result = .{ .source = sources } }; - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "font-family")) { - if (FontFamily.parse(input).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .font_family = c } }; - } - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "font-weight")) { - if (Size2D(FontWeight).parse(input).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .font_weight = c } }; - } - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "font-style")) { - if (FontStyle.parse(input).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .font_style = c } }; - } - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "font-stretch")) { - if (Size2D(FontStretch).parse(input).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .font_stretch = c } }; - } - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "unicode-range")) { - if (input.parseList(UnicodeRange, UnicodeRange.parse).asValue()) |c| { - if (input.expectExhausted().isOk()) { - return .{ .result = .{ .unicode_range = c } }; - } - } - } else { - // - } - - input.reset(&state); - const opts = css.ParserOptions.default(input.allocator(), null); - return .{ - .result = .{ - .custom = switch (CustomProperty.parse(CustomPropertyName.fromStr(name), input, &opts)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, - }, - }; - } - }; - - pub const RuleBodyItemParser = struct { - pub fn parseQualified(this: *This) bool { - _ = this; // autofix - return false; - } - - pub fn parseDeclarations(this: *This) bool { - _ = this; // autofix - return true; - } - }; -}; - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/font_palette_values.zig b/src/css/rules/font_palette_values.zig deleted file mode 100644 index 27c250bcab70..000000000000 --- a/src/css/rules/font_palette_values.zig +++ /dev/null @@ -1,294 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const Maybe = css.Maybe; -const PrintErr = css.PrintErr; -const fontprops = css.css_properties.font; -const Location = css.css_rules.Location; -const CustomProperty = css.css_properties.custom.CustomProperty; -const CustomPropertyName = css.css_properties.custom.CustomPropertyName; -const DashedIdent = css.css_values.ident.DashedIdent; -const FontFamily = css.css_properties.font.FontFamily; - -/// A [@font-palette-values](https://drafts.csswg.org/css-fonts-4/#font-palette-values) rule. -pub const FontPaletteValuesRule = struct { - /// The name of the font palette. - name: css.css_values.ident.DashedIdent, - /// Declarations in the `@font-palette-values` rule. - properties: ArrayList(FontPaletteValuesProperty), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn parse(name: DashedIdent, input: *css.Parser, loc: Location) Result(FontPaletteValuesRule) { - var decl_parser = FontPaletteValuesDeclarationParser{}; - var parser = css.RuleBodyParser(FontPaletteValuesDeclarationParser).new(input, &decl_parser); - var properties = ArrayList(FontPaletteValuesProperty){}; - while (parser.next()) |result| { - if (result.asValue()) |decl| { - properties.append( - input.allocator(), - decl, - ) catch unreachable; - } - } - - return .{ .result = FontPaletteValuesRule{ - .name = name, - .properties = properties, - .loc = loc, - } }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@font-palette-values "); - try css.css_values.ident.DashedIdentFns.toCss(&this.name, dest); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - const len = this.properties.items.len; - for (this.properties.items, 0..) |*prop, i| { - try dest.newline(); - try prop.toCss(dest); - if (i != len - 1 or !dest.minify) { - try dest.writeChar(';'); - } - } - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const FontPaletteValuesProperty = union(enum) { - /// The `font-family` property. - font_family: fontprops.FontFamily, - - /// The `base-palette` property. - base_palette: BasePalette, - - /// The `override-colors` property. - override_colors: ArrayList(OverrideColors), - - /// An unknown or unsupported property. - custom: css.css_properties.custom.CustomProperty, - - /// A property within an `@font-palette-values` rule. - /// - /// See [FontPaletteValuesRule](FontPaletteValuesRule). - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - switch (this.*) { - .font_family => |*f| { - try dest.writeStr("font-family"); - try dest.delim(':', false); - try f.toCss(dest); - }, - .base_palette => |*b| { - try dest.writeStr("base-palette"); - try dest.delim(':', false); - try b.toCss(dest); - }, - .override_colors => |*o| { - try dest.writeStr("override-colors"); - try dest.delim(':', false); - try css.to_css.fromList(OverrideColors, o.items, dest); - }, - .custom => |*custom| { - try dest.writeStr(custom.name.asStr()); - try dest.delim(':', false); - try custom.value.toCss(dest, true); - }, - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [override-colors](https://drafts.csswg.org/css-fonts-4/#override-color) -/// property in an `@font-palette-values` rule. -pub const OverrideColors = struct { - /// The index of the color within the palette to override. - index: u16, - - /// The replacement color. - color: css.css_values.color.CssColor, - - pub fn parse(input: *css.Parser) Result(OverrideColors) { - const index = switch (css.CSSIntegerFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (index < 0) return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - - const color = switch (css.CssColor.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (color == .current_color) return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - - return .{ - .result = OverrideColors{ - .index = @intCast(index), - .color = color, - }, - }; - } - - pub fn toCss(this: *const OverrideColors, dest: *Printer) PrintErr!void { - try css.CSSIntegerFns.toCss(&@as(i32, @intCast(this.index)), dest); - try dest.writeChar(' '); - try this.color.toCss(dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A value for the [base-palette](https://drafts.csswg.org/css-fonts-4/#base-palette-desc) -/// property in an `@font-palette-values` rule. -pub const BasePalette = union(enum) { - /// A light color palette as defined within the font. - light, - - /// A dark color palette as defined within the font. - dark, - - /// A palette index within the font. - integer: u16, - - pub fn parse(input: *css.Parser) Result(BasePalette) { - if (input.tryParse(css.CSSIntegerFns.parse, .{}).asValue()) |i| { - if (i < 0) return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - return .{ .result = .{ .integer = @intCast(i) } }; - } - - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("light", ident)) { - return .{ .result = .light }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("dark", ident)) { - return .{ .result = .dark }; - } else return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - pub fn toCss(this: *const BasePalette, dest: *Printer) PrintErr!void { - switch (this.*) { - .light => try dest.writeStr("light"), - .dark => try dest.writeStr("dark"), - .integer => try css.CSSIntegerFns.toCss(&@as(i32, @intCast(this.integer)), dest), - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const FontPaletteValuesDeclarationParser = struct { - const This = @This(); - - pub const DeclarationParser = struct { - pub const Declaration = FontPaletteValuesProperty; - - pub fn parseValue(this: *This, name: []const u8, input: *css.Parser) Result(Declaration) { - _ = this; // autofix - const state = input.state(); - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("font-family", name)) { - // https://drafts.csswg.org/css-fonts-4/#font-family-2-desc - if (FontFamily.parse(input).asValue()) |font_family| { - if (font_family == .generic) { - return .{ .err = input.newCustomError(css.ParserError.invalid_declaration) }; - } - return .{ .result = .{ .font_family = font_family } }; - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("base-palette", name)) { - // https://drafts.csswg.org/css-fonts-4/#base-palette-desc - if (BasePalette.parse(input).asValue()) |base_palette| { - return .{ .result = .{ .base_palette = base_palette } }; - } - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("override-colors", name)) { - // https://drafts.csswg.org/css-fonts-4/#override-color - if (input.parseCommaSeparated(OverrideColors, OverrideColors.parse).asValue()) |override_colors| { - return .{ .result = .{ .override_colors = override_colors } }; - } - } else { - return .{ .err = input.newCustomError(css.ParserError.invalid_declaration) }; - } - - input.reset(&state); - const opts = css.ParserOptions.default(input.allocator(), null); - return .{ .result = .{ - .custom = switch (CustomProperty.parse( - CustomPropertyName.fromStr(name), - input, - &opts, - )) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, - } }; - } - }; - - pub const RuleBodyItemParser = struct { - pub fn parseQualified(_: *This) bool { - return false; - } - - pub fn parseDeclarations(_: *This) bool { - return true; - } - }; - - pub const AtRuleParser = struct { - pub const Prelude = void; - pub const AtRule = FontPaletteValuesProperty; - - pub fn parsePrelude(_: *This, name: []const u8, input: *css.Parser) Result(Prelude) { - return .{ .err = input.newError(css.BasicParseErrorKind{ .at_rule_invalid = name }) }; - } - - pub fn parseBlock(_: *This, _: AtRuleParser.Prelude, _: *const css.ParserState, input: *css.Parser) Result(AtRuleParser.AtRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.at_rule_body_invalid) }; - } - - pub fn ruleWithoutBlock(_: *This, _: AtRuleParser.Prelude, _: *const css.ParserState) css.Maybe(AtRuleParser.AtRule, void) { - return .{ .err = {} }; - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = void; - pub const QualifiedRule = FontPaletteValuesProperty; - - pub fn parsePrelude(_: *This, input: *css.Parser) Result(Prelude) { - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - - pub fn parseBlock(_: *This, _: Prelude, _: *const css.ParserState, input: *css.Parser) Result(QualifiedRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - }; -}; - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/import.zig b/src/css/rules/import.zig deleted file mode 100644 index df3d1e7ceb22..000000000000 --- a/src/css/rules/import.zig +++ /dev/null @@ -1,268 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const MediaList = css.MediaList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Dependency = css.Dependency; -const dependencies = css.dependencies; -const LayerName = css.css_rules.layer.LayerName; -const SupportsCondition = css.css_rules.supports.SupportsCondition; -const Location = css.css_rules.Location; - -/// TODO: change this to be field on ImportRule -/// The fields of this struct need to match the fields of ImportRule -/// because we cast between them -pub const ImportConditions = struct { - /// An optional cascade layer name, or `None` for an anonymous layer. - layer: ?struct { - /// PERF: null pointer optimizaiton, nullable - v: ?LayerName, - - pub fn eql(this: *const @This(), other: *const @This()) bool { - if (this.v == null and other.v == null) return true; - if (this.v == null or other.v == null) return false; - return this.v.?.eql(&other.v.?); - } - } = null, - - /// An optional `supports()` condition. - supports: ?SupportsCondition = null, - - /// A media query. - media: css.MediaList = .{}, - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn hasAnonymousLayer(this: *const @This()) bool { - return this.layer != null and this.layer.?.v == null; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) ImportConditions { - return ImportConditions{ - .layer = if (this.layer) |*l| if (l.v) |layer| .{ .v = layer.deepClone(allocator) } else .{ .v = null } else null, - .supports = if (this.supports) |*s| s.deepClone(allocator) else null, - .media = this.media.deepClone(allocator), - }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - if (this.layer) |*lyr| { - try dest.writeStr(" layer"); - if (lyr.v) |l| { - try dest.writeChar('('); - try l.toCss(dest); - try dest.writeChar(')'); - } - } - - if (this.supports) |*sup| { - try dest.writeStr(" supports"); - if (sup.* == .declaration) { - try sup.toCss(dest); - } else { - try dest.writeChar('('); - try sup.toCss(dest); - try dest.writeChar(')'); - } - } - - if (this.media.media_queries.items.len > 0) { - try dest.writeChar(' '); - try this.media.toCss(dest); - } - } - - /// This code does the same thing as `deepClone` right now, but might change in the future so keeping this separate. - /// - /// So this code is used when we wrap a CSS file in import conditions in the final output chunk: - /// ```css - /// @layer foo { - /// /* css file contents */ - /// } - /// ``` - /// - /// However, the *prelude* of the condition /could/ contain a URL token: - /// ```css - /// @supports (background-image: url('example.png')) { - /// /* css file contents */ - /// } - /// ``` - /// - /// In this case, the URL token's import record actually belongs to the /parent/ of the current CSS file (the one who imported it). - /// Therefore, we need to copy this import record from the parent into the import record list of this current CSS file. - /// - /// In actuality, the css parser doesn't create an import record for URL tokens in `@supports` because that's pointless in the context of hte - /// @supports rule. - /// - /// Furthermore, a URL token is not valid in `@media` or `@layer` rules. - /// - /// But this could change in the future, so still keeping this function. - /// - pub fn cloneWithImportRecords(this: *const @This(), allocator: std.mem.Allocator, import_records: *bun.BabyList(bun.ImportRecord)) ImportConditions { - return ImportConditions{ - .layer = if (this.layer) |layer| if (layer.v) |l| .{ .v = l.cloneWithImportRecords(allocator, import_records) } else .{ .v = null } else null, - .supports = if (this.supports) |*supp| supp.cloneWithImportRecords(allocator, import_records) else null, - .media = this.media.cloneWithImportRecords(allocator, import_records), - }; - } - - pub fn layersEql(lhs: *const @This(), rhs: *const @This()) bool { - if (lhs.layer == null and rhs.layer == null) return true; - if (lhs.layer == null or rhs.layer == null) return false; - return lhs.layer.?.eql(&rhs.layer.?); - } - - pub fn supportsEql(lhs: *const @This(), rhs: *const @This()) bool { - if (lhs.supports == null and rhs.supports == null) return true; - if (lhs.supports == null or rhs.supports == null) return false; - - return lhs.supports.?.eql(&rhs.supports.?); - } -}; - -/// A [@import](https://drafts.csswg.org/css-cascade/#at-import) rule. -pub const ImportRule = struct { - /// The url to import. - url: []const u8, - - /// An optional cascade layer name, or `None` for an anonymous layer. - layer: ?struct { - /// PERF: null pointer optimizaiton, nullable - v: ?LayerName, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - } = null, - - /// An optional `supports()` condition. - supports: ?SupportsCondition = null, - - /// A media query. - media: css.MediaList = .{}, - - /// This is default initialized to 2^32 - 1 when parsing. - /// If we are bundling, this will be set to the index of the corresponding ImportRecord - /// created for this import rule. - import_record_idx: u32 = std.math.maxInt(u32), - - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn fromUrl(url: []const u8) This { - return .{ - .url = url, - .layer = null, - .supports = null, - .media = MediaList{ .media_queries = .{} }, - .import_record_idx = std.math.maxInt(u32), - .loc = Location.dummy(), - }; - } - - pub fn fromUrlAndImportRecordIdx(url: []const u8, import_record_idx: u32) This { - return .{ - .url = url, - .layer = null, - .supports = null, - .media = MediaList{ .media_queries = .{} }, - .import_record_idx = import_record_idx, - .loc = Location.dummy(), - }; - } - - pub fn fromConditionsAndUrl(url: []const u8, conds: ImportConditions) This { - return ImportRule{ - .url = url, - .layer = if (conds.layer) |layer| if (layer.v) |ly| .{ .v = ly } else .{ .v = null } else null, - .supports = conds.supports, - .media = conds.media, - .import_record_idx = std.math.maxInt(u32), - .loc = Location.dummy(), - }; - } - - pub fn conditions(this: *const @This()) *const ImportConditions { - return @ptrCast(&this.layer); - } - - pub fn conditionsMut(this: *@This()) *ImportConditions { - return @ptrCast(&this.layer); - } - - /// The `import_records` here is preserved from esbuild in the case that we do need it, it doesn't seem necessary now - pub fn conditionsWithImportRecords(this: *const This, allocator: std.mem.Allocator, import_records: *bun.BabyList(bun.ImportRecord)) ImportConditions { - return ImportConditions{ - .layer = if (this.layer) |layer| if (layer.v) |l| .{ .v = l.cloneWithImportRecords(allocator, import_records) } else .{ .v = null } else null, - .supports = if (this.supports) |*supp| supp.cloneWithImportRecords(allocator, import_records) else null, - .media = this.media.cloneWithImportRecords(allocator, import_records), - }; - } - - pub fn hasConditions(this: *const This) bool { - return this.layer != null or this.supports != null or this.media.media_queries.items.len > 0; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - const dep = if (dest.dependencies != null) dependencies.ImportDependency.new( - dest.allocator, - this, - dest.filename(), - dest.local_names, - dest.symbols, - ) else null; - - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@import "); - if (dep) |d| { - css.serializer.serializeString(d.placeholder, dest) catch return dest.addFmtError(); - - if (dest.dependencies) |*deps| { - deps.append( - dest.allocator, - Dependency{ .import = d }, - ) catch unreachable; - } - } else { - css.serializer.serializeString(this.url, dest) catch return dest.addFmtError(); - } - - if (this.layer) |*lyr| { - try dest.writeStr(" layer"); - if (lyr.v) |l| { - try dest.writeChar('('); - try l.toCss(dest); - try dest.writeChar(')'); - } - } - - if (this.supports) |*sup| { - try dest.writeStr(" supports"); - if (sup.* == .declaration) { - try sup.toCss(dest); - } else { - try dest.writeChar('('); - try sup.toCss(dest); - try dest.writeChar(')'); - } - } - - if (this.media.media_queries.items.len > 0) { - try dest.writeChar(' '); - try this.media.toCss(dest); - } - try dest.writeStr(";"); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/rules/keyframes.zig b/src/css/rules/keyframes.zig deleted file mode 100644 index 8a5f3f504819..000000000000 --- a/src/css/rules/keyframes.zig +++ /dev/null @@ -1,303 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const Maybe = css.Maybe; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const Result = css.Result; - -pub const KeyframesListParser = struct { - const This = @This(); - - pub const DeclarationParser = struct { - pub const Declaration = Keyframe; - - pub fn parseValue(_: *This, name: []const u8, input: *css.Parser) Result(Declaration) { - return .{ .err = input.newError(css.BasicParseErrorKind{ .unexpected_token = .{ .ident = name } }) }; - } - }; - - pub const RuleBodyItemParser = struct { - pub fn parseQualified(_: *This) bool { - return true; - } - - pub fn parseDeclarations(_: *This) bool { - return false; - } - }; - - pub const AtRuleParser = struct { - pub const Prelude = void; - pub const AtRule = Keyframe; - - pub fn parsePrelude(_: *This, name: []const u8, input: *css.Parser) Result(Prelude) { - return .{ .err = input.newError(css.BasicParseErrorKind{ .at_rule_invalid = name }) }; - } - - pub fn parseBlock(_: *This, _: AtRuleParser.Prelude, _: *const css.ParserState, input: *css.Parser) Result(AtRuleParser.AtRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.at_rule_body_invalid) }; - } - - pub fn ruleWithoutBlock(_: *This, _: AtRuleParser.Prelude, _: *const css.ParserState) css.Maybe(AtRuleParser.AtRule, void) { - return .{ .err = {} }; - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = ArrayList(KeyframeSelector); - pub const QualifiedRule = Keyframe; - - pub fn parsePrelude(_: *This, input: *css.Parser) Result(Prelude) { - return input.parseCommaSeparated(KeyframeSelector, KeyframeSelector.parse); - } - - pub fn parseBlock(_: *This, prelude: Prelude, _: *const css.ParserState, input: *css.Parser) Result(QualifiedRule) { - // For now there are no options that apply within @keyframes - const options = css.ParserOptions.default(input.allocator(), null); - return .{ - .result = Keyframe{ - .selectors = prelude, - .declarations = switch (css.DeclarationBlock.parse(input, &options)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - }, - }; - } - }; -}; - -/// KeyframesName -pub const KeyframesName = union(enum) { - /// `` of a `@keyframes` name. - ident: css.css_values.ident.CustomIdent, - /// `` of a `@keyframes` name. - custom: []const u8, - - const This = @This(); - - pub fn HashMap(comptime V: type) type { - return std.ArrayHashMapUnmanaged(KeyframesName, V, struct { - pub fn hash(_: @This(), key: KeyframesName) u32 { - return switch (key) { - .ident => std.array_hash_map.hashString(key.ident.v), - .custom => std.array_hash_map.hashString(key.custom), - }; - } - - pub fn eql(_: @This(), a: KeyframesName, b: KeyframesName, _: usize) bool { - return switch (a) { - .ident => switch (b) { - .ident => bun.strings.eql(a.ident.v, b.ident.v), - .custom => false, - }, - .custom => switch (b) { - .ident => false, - .custom => bun.strings.eql(a.custom, b.custom), - }, - }; - } - }, false); - } - - pub fn parse(input: *css.Parser) Result(KeyframesName) { - switch (switch (input.next()) { - .result => |v| v.*, - .err => |e| return .{ .err = e }, - }) { - .ident => |s| { - // todo_stuff.match_ignore_ascii_case - // CSS-wide keywords without quotes throws an error. - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "none") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "initial") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "inherit") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "unset") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "default") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "revert") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "revert-layer")) - { - return .{ .err = input.newUnexpectedTokenError(.{ .ident = s }) }; - } else { - return .{ .result = .{ .ident = .{ .v = s } } }; - } - }, - .quoted_string => |s| return .{ .result = .{ .custom = s } }, - else => |t| { - return .{ .err = input.newUnexpectedTokenError(t) }; - }, - } - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - const css_module_aimation_enabled = if (dest.css_module) |css_module| css_module.config.animation else false; - - switch (this.*) { - .ident => |ident| { - try dest.writeIdent(ident.v, css_module_aimation_enabled); - }, - .custom => |s| { - // todo_stuff.match_ignore_ascii_case - // CSS-wide keywords and `none` cannot remove quotes. - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "none") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "initial") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "inherit") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "unset") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "default") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "revert") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(s, "revert-layer")) - { - css.serializer.serializeString(s, dest) catch return dest.addFmtError(); - } else { - try dest.writeIdent(s, css_module_aimation_enabled); - } - }, - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const KeyframeSelector = union(enum) { - /// An explicit percentage. - percentage: css.css_values.percentage.Percentage, - /// The `from` keyword. Equivalent to 0%. - from, - /// The `to` keyword. Equivalent to 100%. - to, - - // TODO: implement this - pub const parse = css.DeriveParse(@This()).parse; - - // pub fn parse(input: *css.Parser) Result(KeyframeSelector) { - // _ = input; // autofix - // @panic(css.todo_stuff.depth); - // } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - switch (this.*) { - .percentage => |p| { - if (dest.minify and p.v == 1.0) { - try dest.writeStr("to"); - } else { - try p.toCss(dest); - } - }, - .from => { - if (dest.minify) { - try dest.writeStr("0%"); - } else { - try dest.writeStr("from"); - } - }, - .to => { - try dest.writeStr("to"); - }, - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// An individual keyframe within an `@keyframes` rule. -/// -/// See [KeyframesRule](KeyframesRule). -pub const Keyframe = struct { - /// A list of keyframe selectors to associate with the declarations in this keyframe. - selectors: ArrayList(KeyframeSelector), - /// The declarations for this keyframe. - declarations: css.DeclarationBlock, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - var first = true; - for (this.selectors.items) |sel| { - if (!first) { - try dest.delim(',', false); - } - first = false; - try sel.toCss(dest); - } - - try this.declarations.toCssBlock(dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const KeyframesRule = struct { - /// The animation name. - /// = | - name: KeyframesName, - /// A list of keyframes in the animation. - keyframes: ArrayList(Keyframe), - /// A vendor prefix for the rule, e.g. `@-webkit-keyframes`. - vendor_prefix: css.VendorPrefix, - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - var first_rule = true; - - inline for (.{ "webkit", "moz", "ms", "o", "none" }) |prefix_name| { - if (@field(this.vendor_prefix, prefix_name)) { - if (first_rule) { - first_rule = false; - } else { - if (!dest.minify) { - try dest.writeChar('\n'); // no indent - } - try dest.newline(); - } - - try dest.writeChar('@'); - try css.VendorPrefix.fromName(prefix_name).toCss(dest); - try dest.writeStr("keyframes "); - try this.name.toCss(dest); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - - var first = true; - for (this.keyframes.items) |*keyframe| { - if (first) { - first = false; - } else if (!dest.minify) { - try dest.writeChar('\n'); // no indent - } - try dest.newline(); - try keyframe.toCss(dest); - } - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - } - } - - pub fn getFallbacks(this: *This, comptime T: type, targets: *const css.targets.Targets) []css.CssRule(T) { - _ = this; // autofix - _ = targets; // autofix - @compileError(css.todo_stuff.depth); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/layer.zig b/src/css/rules/layer.zig deleted file mode 100644 index 89f0b54c30f0..000000000000 --- a/src/css/rules/layer.zig +++ /dev/null @@ -1,210 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const Result = css.Result; - -/// Stored as a list of strings as dot notation can be used -/// to create sublayers -pub const LayerName = struct { - v: css.SmallList([]const u8, 1) = .{}, - - pub fn HashMap(comptime V: type) type { - return std.ArrayHashMapUnmanaged(LayerName, V, struct { - pub fn hash(_: @This(), key: LayerName) u32 { - var hasher = std.hash.Wyhash.init(0); - for (key.v.items) |part| { - hasher.update(part); - } - return hasher.final(); - } - - pub fn eql(_: @This(), a: LayerName, b: LayerName, _: usize) bool { - if (a.v.len != b.v.len) return false; - for (a.v.items, 0..) |part, i| { - if (!bun.strings.eql(part, b.v.items[i])) return false; - } - return true; - } - }, false); - } - - pub fn hash(this: *const LayerName, hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn cloneWithImportRecords( - this: *const @This(), - allocator: std.mem.Allocator, - _: *bun.BabyList(bun.ImportRecord), - ) @This() { - return LayerName{ .v = this.v.deepClone(allocator) }; - } - - pub fn deepClone(this: *const LayerName, allocator: std.mem.Allocator) LayerName { - return LayerName{ - .v = this.v.clone(allocator), - }; - } - - pub fn eql(lhs: *const LayerName, rhs: *const LayerName) bool { - if (lhs.v.len() != rhs.v.len()) return false; - for (lhs.v.slice(), rhs.v.slice()) |l, r| { - if (!bun.strings.eql(l, r)) return false; - } - return true; - } - - pub fn parse(input: *css.Parser) Result(LayerName) { - var parts: css.SmallList([]const u8, 1) = .{}; - const ident = switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - parts.append( - input.allocator(), - ident, - ); - - while (true) { - const Fn = struct { - pub fn tryParseFn( - i: *css.Parser, - ) Result([]const u8) { - const name = name: { - out: { - const start_location = i.currentSourceLocation(); - const tok = switch (i.nextIncludingWhitespace()) { - .err => |e| return .{ .err = e }, - .result => |vvv| vvv, - }; - if (tok.* == .delim and tok.delim == '.') { - break :out; - } - return .{ .err = start_location.newBasicUnexpectedTokenError(tok.*) }; - } - - const start_location = i.currentSourceLocation(); - const tok = switch (i.nextIncludingWhitespace()) { - .err => |e| return .{ .err = e }, - .result => |vvv| vvv, - }; - if (tok.* == .ident) { - break :name tok.ident; - } - return .{ .err = start_location.newBasicUnexpectedTokenError(tok.*) }; - }; - return .{ .result = name }; - } - }; - - while (true) { - const name = switch (input.tryParse(Fn.tryParseFn, .{})) { - .err => break, - .result => |vvv| vvv, - }; - parts.append( - input.allocator(), - name, - ); - } - - return .{ .result = LayerName{ .v = parts } }; - } - } - - pub fn toCss(this: *const LayerName, dest: *css.Printer) css.PrintErr!void { - var first = true; - for (this.v.slice()) |name| { - if (first) { - first = false; - } else { - try dest.writeChar('.'); - } - - css.serializer.serializeIdentifier(name, dest) catch return dest.addFmtError(); - } - } - - pub fn format(this: *const LayerName, writer: *std.Io.Writer) !void { - var first = true; - for (this.v.slice()) |name| { - if (first) { - first = false; - } else { - try writer.writeAll("."); - } - try writer.writeAll(name); - } - } -}; - -/// A [@layer block](https://drafts.csswg.org/css-cascade-5/#layer-block) rule. -pub fn LayerBlockRule(comptime R: type) type { - return struct { - /// PERF: null pointer optimizaiton, nullable - /// The name of the layer to declare, or `None` to declare an anonymous layer. - name: ?LayerName, - /// The rules within the `@layer` rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@layer"); - if (this.name) |*name| { - try dest.writeChar(' '); - try name.toCss(dest); - } - - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - try this.rules.toCss(dest); - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -/// A [@layer statement](https://drafts.csswg.org/css-cascade-5/#layer-empty) rule. -/// -/// See also [LayerBlockRule](LayerBlockRule). -pub const LayerStatementRule = struct { - /// The layer names to declare. - names: bun.css.SmallList(LayerName, 1), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - if (this.names.len() > 0) { - try dest.writeStr("@layer "); - try css.to_css.fromList(LayerName, this.names.slice(), dest); - try dest.writeChar(';'); - } else { - try dest.writeStr("@layer;"); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/rules/media.zig b/src/css/rules/media.zig deleted file mode 100644 index da3d45728821..000000000000 --- a/src/css/rules/media.zig +++ /dev/null @@ -1,51 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const MediaList = css.MediaList; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const CssRuleList = css.CssRuleList; - -pub fn MediaRule(comptime R: type) type { - return struct { - /// The media query list. - query: css.MediaList, - /// The rules within the `@media` rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn minify(this: *This, context: *css.MinifyContext, parent_is_unused: bool) css.MinifyErr!bool { - try this.rules.minify(context, parent_is_unused); - - return this.rules.v.items.len == 0 or this.query.neverMatches(); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - if (dest.minify and this.query.alwaysMatches()) { - try this.rules.toCss(dest); - return; - } - // #[cfg(feature = "sourcemap")] - // dest.addMapping(this.loc); - - try dest.writeStr("@media "); - try this.query.toCss(dest); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - try this.rules.toCss(dest); - dest.dedent(); - try dest.newline(); - return dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -const std = @import("std"); diff --git a/src/css/rules/namespace.zig b/src/css/rules/namespace.zig deleted file mode 100644 index dea4837580e2..000000000000 --- a/src/css/rules/namespace.zig +++ /dev/null @@ -1,38 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const css_values = @import("../values/values.zig"); -pub const Error = css.Error; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -/// A [@namespace](https://drafts.csswg.org/css-namespaces/#declaration) rule. -pub const NamespaceRule = struct { - /// An optional namespace prefix to declare, or `None` to declare the default namespace. - prefix: ?css.Ident, - /// The url of the namespace. - url: css.CSSString, - /// The location of the rule in the source file. - loc: css.Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@namespace "); - if (this.prefix) |*prefix| { - try css.css_values.ident.IdentFns.toCss(prefix, dest); - try dest.writeChar(' '); - } - - try css.css_values.string.CSSStringFns.toCss(&this.url, dest); - try dest.writeChar(';'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/rules/nesting.zig b/src/css/rules/nesting.zig deleted file mode 100644 index 9bb43de70a8d..000000000000 --- a/src/css/rules/nesting.zig +++ /dev/null @@ -1,32 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const style = css.css_rules.style; - -/// A [@nest](https://www.w3.org/TR/css-nesting-1/#at-nest) rule. -pub fn NestingRule(comptime R: type) type { - return struct { - /// The style rule that defines the selector and declarations for the `@nest` rule. - style: style.StyleRule(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - if (dest.context() == null) { - try dest.writeStr("@nest "); - } - return try this.style.toCss(dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -const std = @import("std"); diff --git a/src/css/rules/page.zig b/src/css/rules/page.zig deleted file mode 100644 index 0575f59f3b06..000000000000 --- a/src/css/rules/page.zig +++ /dev/null @@ -1,384 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const Maybe = css.Maybe; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; - -/// A [page selector](https://www.w3.org/TR/css-page-3/#typedef-page-selector) -/// within a `@page` rule. -/// -/// Either a name or at least one pseudo class is required. -pub const PageSelector = struct { - /// An optional named page type. - name: ?[]const u8, - /// A list of page pseudo classes. - pseudo_classes: ArrayList(PagePseudoClass), - - pub fn parse(input: *css.Parser) Result(PageSelector) { - const name = if (input.tryParse(css.Parser.expectIdent, .{}).asValue()) |name| name else null; - var pseudo_classes = ArrayList(PagePseudoClass){}; - - while (true) { - // Whitespace is not allowed between pseudo classes - const state = input.state(); - if (switch (input.nextIncludingWhitespace()) { - .result => |tok| tok.* == .colon, - .err => |e| return .{ .err = e }, - }) { - pseudo_classes.append( - input.allocator(), - switch (PagePseudoClass.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - ) catch |err| bun.handleOom(err); - } else { - input.reset(&state); - break; - } - } - - if (name == null and pseudo_classes.items.len == 0) { - return .{ .err = input.newCustomError(css.ParserError.invalid_page_selector) }; - } - - return .{ - .result = PageSelector{ - .name = name, - .pseudo_classes = pseudo_classes, - }, - }; - } - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - if (this.name) |name| { - try dest.writeStr(name); - } - - for (this.pseudo_classes.items) |*pseudo| { - try dest.writeChar(':'); - try pseudo.toCss(dest); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const PageMarginRule = struct { - /// The margin box identifier for this rule. - margin_box: PageMarginBox, - /// The declarations within the rule. - declarations: css.DeclarationBlock, - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeChar('@'); - try this.margin_box.toCss(dest); - try this.declarations.toCssBlock(dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [@page](https://www.w3.org/TR/css-page-3/#at-page-rule) rule. -pub const PageRule = struct { - /// A list of page selectors. - selectors: ArrayList(PageSelector), - /// The declarations within the `@page` rule. - declarations: css.DeclarationBlock, - /// The nested margin rules. - rules: ArrayList(PageMarginRule), - /// The location of the rule in the source file. - loc: Location, - - pub fn parse(selectors: ArrayList(PageSelector), input: *css.Parser, loc: Location, options: *const css.ParserOptions) Result(PageRule) { - var declarations = css.DeclarationBlock{}; - var rules = ArrayList(PageMarginRule){}; - var rule_parser = PageRuleParser{ - .declarations = &declarations, - .rules = &rules, - .options = options, - }; - var parser = css.RuleBodyParser(PageRuleParser).new(input, &rule_parser); - - while (parser.next()) |decl| { - if (decl.asErr()) |e| { - if (parser.parser.options.error_recovery) { - parser.parser.options.warn(e); - continue; - } - - return .{ .err = e }; - } - } - - return .{ .result = PageRule{ - .selectors = selectors, - .declarations = declarations, - .rules = rules, - .loc = loc, - } }; - } - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - try dest.writeStr("@page"); - if (this.selectors.items.len >= 1) { - const firstsel = &this.selectors.items[0]; - // Space is only required if the first selector has a name. - if (!dest.minify and firstsel.name != null) { - try dest.writeChar(' '); - } - var first = true; - for (this.selectors.items) |selector| { - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - try selector.toCss(dest); - } - } - - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - - var i: usize = 0; - const len = this.declarations.len() + this.rules.items.len; - - const DECLS = .{ "declarations", "important_declarations" }; - inline for (DECLS) |decl_field_name| { - const decls: *const ArrayList(css.Property) = &@field(this.declarations, decl_field_name); - const important = comptime std.mem.eql(u8, decl_field_name, "important_declarations"); - for (decls.items) |*decl| { - try dest.newline(); - try decl.toCss(dest, important); - if (i != len - 1 or !dest.minify) { - try dest.writeChar(';'); - } - i += 1; - } - } - - if (this.rules.items.len > 0) { - if (!dest.minify and this.declarations.len() > 0) { - try dest.writeChar('\n'); - } - try dest.newline(); - - var first = true; - for (this.rules.items) |*rule| { - if (first) { - first = false; - } else { - if (!dest.minify) { - try dest.writeChar('\n'); - } - try dest.newline(); - } - try rule.toCss(dest); - } - } - - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A page pseudo class within an `@page` selector. -/// -/// See [PageSelector](PageSelector). -pub const PagePseudoClass = enum { - /// The `:left` pseudo class. - left, - /// The `:right` pseudo class. - right, - /// The `:first` pseudo class. - first, - /// The `:last` pseudo class. - last, - /// The `:blank` pseudo class. - blank, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [page margin box](https://www.w3.org/TR/css-page-3/#margin-boxes). -pub const PageMarginBox = enum { - /// A fixed-size box defined by the intersection of the top and left margins of the page box. - @"top-left-corner", - /// A variable-width box filling the top page margin between the top-left-corner and top-center page-margin boxes. - @"top-left", - /// A variable-width box centered horizontally between the page’s left and right border edges and filling the - /// page top margin between the top-left and top-right page-margin boxes. - @"top-center", - /// A variable-width box filling the top page margin between the top-center and top-right-corner page-margin boxes. - @"top-right", - /// A fixed-size box defined by the intersection of the top and right margins of the page box. - @"top-right-corner", - /// A variable-height box filling the left page margin between the top-left-corner and left-middle page-margin boxes. - @"left-top", - /// A variable-height box centered vertically between the page’s top and bottom border edges and filling the - /// left page margin between the left-top and left-bottom page-margin boxes. - @"left-middle", - /// A variable-height box filling the left page margin between the left-middle and bottom-left-corner page-margin boxes. - @"left-bottom", - /// A variable-height box filling the right page margin between the top-right-corner and right-middle page-margin boxes. - @"right-top", - /// A variable-height box centered vertically between the page’s top and bottom border edges and filling the right - /// page margin between the right-top and right-bottom page-margin boxes. - @"right-middle", - /// A variable-height box filling the right page margin between the right-middle and bottom-right-corner page-margin boxes. - @"right-bottom", - /// A fixed-size box defined by the intersection of the bottom and left margins of the page box. - @"bottom-left-corner", - /// A variable-width box filling the bottom page margin between the bottom-left-corner and bottom-center page-margin boxes. - @"bottom-left", - /// A variable-width box centered horizontally between the page’s left and right border edges and filling the bottom - /// page margin between the bottom-left and bottom-right page-margin boxes. - @"bottom-center", - /// A variable-width box filling the bottom page margin between the bottom-center and bottom-right-corner page-margin boxes. - @"bottom-right", - /// A fixed-size box defined by the intersection of the bottom and right margins of the page box. - @"bottom-right-corner", - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -pub const PageRuleParser = struct { - declarations: *css.DeclarationBlock, - rules: *ArrayList(PageMarginRule), - options: *const css.ParserOptions, - - const This = @This(); - - pub const DeclarationParser = struct { - pub const Declaration = void; - - pub fn parseValue(this: *This, name: []const u8, input: *css.Parser) Result(Declaration) { - return css.declaration.parse_declaration( - name, - input, - &this.declarations.declarations, - &this.declarations.important_declarations, - this.options, - ); - } - }; - - pub const RuleBodyItemParser = struct { - pub fn parseQualified(_: *This) bool { - return false; - } - - pub fn parseDeclarations(_: *This) bool { - return true; - } - }; - - pub const AtRuleParser = struct { - pub const Prelude = PageMarginBox; - pub const AtRule = void; - - pub fn parsePrelude(_: *This, name: []const u8, input: *css.Parser) Result(Prelude) { - const loc = input.currentSourceLocation(); - return switch (css.parse_utility.parseString( - input.allocator(), - PageMarginBox, - name, - PageMarginBox.parse, - )) { - .result => |v| return .{ .result = v }, - .err => { - return .{ .err = loc.newCustomError(css.ParserError{ .at_rule_invalid = name }) }; - }, - }; - } - - pub fn parseBlock(this: *This, prelude: AtRuleParser.Prelude, start: *const css.ParserState, input: *css.Parser) Result(AtRuleParser.AtRule) { - const loc = start.sourceLocation(); - const declarations = switch (css.DeclarationBlock.parse(input, this.options)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - this.rules.append(input.allocator(), PageMarginRule{ - .margin_box = prelude, - .declarations = declarations, - .loc = Location{ - .source_index = this.options.source_index, - .line = loc.line, - .column = loc.column, - }, - }) catch |err| bun.handleOom(err); - return .success; - } - - pub fn ruleWithoutBlock(_: *This, _: AtRuleParser.Prelude, _: *const css.ParserState) css.Maybe(AtRuleParser.AtRule, void) { - return .{ .err = {} }; - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = void; - pub const QualifiedRule = void; - - pub fn parsePrelude(_: *This, input: *css.Parser) Result(Prelude) { - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - - pub fn parseBlock(_: *This, _: Prelude, _: *const css.ParserState, input: *css.Parser) Result(QualifiedRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - }; -}; - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/property.zig b/src/css/rules/property.zig deleted file mode 100644 index c62c9214860d..000000000000 --- a/src/css/rules/property.zig +++ /dev/null @@ -1,225 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const Maybe = css.Maybe; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const SyntaxString = css.css_values.syntax.SyntaxString; -const ParsedComponent = css.css_values.syntax.ParsedComponent; - -pub const PropertyRule = struct { - name: css.css_values.ident.DashedIdent, - syntax: SyntaxString, - inherits: bool, - initial_value: ?css.css_values.syntax.ParsedComponent, - loc: Location, - - pub fn parse(name: css.css_values.ident.DashedIdent, input: *css.Parser, loc: Location) Result(PropertyRule) { - var p = PropertyRuleDeclarationParser{ - .syntax = null, - .inherits = null, - .initial_value = null, - }; - - var decl_parser = css.RuleBodyParser(PropertyRuleDeclarationParser).new(input, &p); - while (decl_parser.next()) |decl| { - if (decl.asErr()) |e| { - return .{ .err = e }; - } - } - - // `syntax` and `inherits` are always required. - const parser = decl_parser.parser; - // TODO(zack): source clones these two, but I omitted here becaues it seems 100% unnecessary - const syntax: SyntaxString = parser.syntax orelse return .{ .err = decl_parser.input.newCustomError(css.ParserError.at_rule_body_invalid) }; - const inherits: bool = parser.inherits orelse return .{ .err = decl_parser.input.newCustomError(css.ParserError.at_rule_body_invalid) }; - - // `initial-value` is required unless the syntax is a universal definition. - const initial_value = switch (syntax) { - .universal => if (parser.initial_value) |val| brk: { - var i = css.ParserInput.new(input.allocator(), val); - var p2 = css.Parser.new(&i, null, .{}, null); - - if (p2.isExhausted()) { - break :brk ParsedComponent{ - .token_list = css.TokenList{ - .v = .{}, - }, - }; - } - break :brk switch (syntax.parseValue(&p2)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - } else null, - else => brk: { - const val = parser.initial_value orelse return .{ .err = input.newCustomError(css.ParserError.at_rule_body_invalid) }; - var i = css.ParserInput.new(input.allocator(), val); - var p2 = css.Parser.new(&i, null, .{}, null); - break :brk switch (syntax.parseValue(&p2)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - }, - }; - - return .{ - .result = PropertyRule{ - .name = name, - .syntax = syntax, - .inherits = inherits, - .initial_value = initial_value, - .loc = loc, - }, - }; - } - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@property "); - try css.css_values.ident.DashedIdentFns.toCss(&this.name, dest); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - - try dest.writeStr("syntax:"); - try dest.whitespace(); - try this.syntax.toCss(dest); - try dest.writeChar(';'); - try dest.newline(); - - try dest.writeStr("inherits:"); - try dest.whitespace(); - if (this.inherits) { - try dest.writeStr("true"); - } else { - try dest.writeStr("false"); - } - - if (this.initial_value) |*initial_value| { - try dest.writeChar(';'); - try dest.newline(); - - try dest.writeStr("initial-value:"); - try dest.whitespace(); - try initial_value.toCss(dest); - - if (!dest.minify) { - try dest.writeChar(';'); - } - } - - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const PropertyRuleDeclarationParser = struct { - syntax: ?SyntaxString, - inherits: ?bool, - initial_value: ?[]const u8, - - const This = @This(); - - pub const DeclarationParser = struct { - pub const Declaration = void; - const Map = bun.ComptimeStringMap(std.meta.FieldEnum(PropertyRuleDeclarationParser), .{ - .{ "syntax", .syntax }, - .{ "inherits", .inherits }, - .{ "initial-value", .initial_value }, - }); - - pub fn parseValue(this: *This, name: []const u8, input: *css.Parser) Result(Declaration) { - // todo_stuff.match_ignore_ascii_case - - // if (Map.getASCIIICaseInsensitive( - // name)) |field| { - // return switch (field) { - // .syntax => |syntax| { - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("syntax", name)) { - const syntax = switch (SyntaxString.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - this.syntax = syntax; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("inherits", name)) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const inherits = if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("true", ident)) - true - else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("false", ident)) - false - else - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - this.inherits = inherits; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("initial-value", name)) { - // Buffer the value into a string. We will parse it later. - const start = input.position(); - while (input.next().isOk()) {} - const initial_value = input.sliceFrom(start); - this.initial_value = initial_value; - } else { - return .{ .err = input.newCustomError(css.ParserError.invalid_declaration) }; - } - - return .success; - } - }; - - pub const RuleBodyItemParser = struct { - pub fn parseQualified(_: *This) bool { - return false; - } - - pub fn parseDeclarations(_: *This) bool { - return true; - } - }; - - pub const AtRuleParser = struct { - pub const Prelude = void; - pub const AtRule = void; - - pub fn parsePrelude(_: *This, name: []const u8, input: *css.Parser) Result(Prelude) { - return .{ .err = input.newError(css.BasicParseErrorKind{ .at_rule_invalid = name }) }; - } - - pub fn parseBlock(_: *This, _: AtRuleParser.Prelude, _: *const css.ParserState, input: *css.Parser) Result(AtRuleParser.AtRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.at_rule_body_invalid) }; - } - - pub fn ruleWithoutBlock(_: *This, _: AtRuleParser.Prelude, _: *const css.ParserState) css.Maybe(AtRuleParser.AtRule, void) { - return .{ .err = {} }; - } - }; - - pub const QualifiedRuleParser = struct { - pub const Prelude = void; - pub const QualifiedRule = void; - - pub fn parsePrelude(_: *This, input: *css.Parser) Result(Prelude) { - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - - pub fn parseBlock(_: *This, _: Prelude, _: *const css.ParserState, input: *css.Parser) Result(QualifiedRule) { - return .{ .err = input.newError(css.BasicParseErrorKind.qualified_rule_invalid) }; - } - }; -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/rules/rules.zig b/src/css/rules/rules.zig deleted file mode 100644 index 8c3fe5dd72b5..000000000000 --- a/src/css/rules/rules.zig +++ /dev/null @@ -1,681 +0,0 @@ -pub const css = @import("../css_parser.zig"); - -const CustomMedia = css.CustomMedia; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Dependency = css.Dependency; -const dependencies = css.dependencies; - -pub const import = @import("./import.zig"); -pub const layer = @import("./layer.zig"); -pub const style = @import("./style.zig"); -pub const keyframes = @import("./keyframes.zig"); -pub const font_face = @import("./font_face.zig"); -pub const font_palette_values = @import("./font_palette_values.zig"); -pub const page = @import("./page.zig"); -pub const supports = @import("./supports.zig"); -pub const counter_style = @import("./counter_style.zig"); -pub const custom_media = @import("./custom_media.zig"); -pub const namespace = @import("./namespace.zig"); -pub const unknown = @import("./unknown.zig"); -pub const document = @import("./document.zig"); -pub const nesting = @import("./nesting.zig"); -pub const viewport = @import("./viewport.zig"); -pub const property = @import("./property.zig"); -pub const container = @import("./container.zig"); -pub const scope = @import("./scope.zig"); -pub const media = @import("./media.zig"); -pub const starting_style = @import("./starting_style.zig"); - -pub const tailwind = @import("./tailwind.zig"); - -const debug = bun.Output.scoped(.CSS_MINIFY, .visible); - -pub fn CssRule(comptime Rule: type) type { - return union(enum) { - /// A `@media` rule. - media: media.MediaRule(Rule), - /// An `@import` rule. - import: import.ImportRule, - /// A style rule. - style: style.StyleRule(Rule), - /// A `@keyframes` rule. - keyframes: keyframes.KeyframesRule, - /// A `@font-face` rule. - font_face: font_face.FontFaceRule, - /// A `@font-palette-values` rule. - font_palette_values: font_palette_values.FontPaletteValuesRule, - /// A `@page` rule. - page: page.PageRule, - /// A `@supports` rule. - supports: supports.SupportsRule(Rule), - /// A `@counter-style` rule. - counter_style: counter_style.CounterStyleRule, - /// A `@namespace` rule. - namespace: namespace.NamespaceRule, - /// A `@-moz-document` rule. - moz_document: document.MozDocumentRule(Rule), - /// A `@nest` rule. - nesting: nesting.NestingRule(Rule), - /// A `@viewport` rule. - viewport: viewport.ViewportRule, - /// A `@custom-media` rule. - custom_media: CustomMedia, - /// A `@layer` statement rule. - layer_statement: layer.LayerStatementRule, - /// A `@layer` block rule. - layer_block: layer.LayerBlockRule(Rule), - /// A `@property` rule. - property: property.PropertyRule, - /// A `@container` rule. - container: container.ContainerRule(Rule), - /// A `@scope` rule. - scope: scope.ScopeRule(Rule), - /// A `@starting-style` rule. - starting_style: starting_style.StartingStyleRule(Rule), - /// A placeholder for a rule that was removed. - ignored, - /// An unknown at-rule. - unknown: unknown.UnknownAtRule, - /// A custom at-rule. - custom: Rule, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - return switch (this.*) { - .media => |x| x.toCss(dest), - .import => |x| x.toCss(dest), - .style => |x| x.toCss(dest), - .keyframes => |x| x.toCss(dest), - .font_face => |x| x.toCss(dest), - .font_palette_values => |x| x.toCss(dest), - .page => |x| x.toCss(dest), - .supports => |x| x.toCss(dest), - .counter_style => |x| x.toCss(dest), - .namespace => |x| x.toCss(dest), - .moz_document => |x| x.toCss(dest), - .nesting => |x| x.toCss(dest), - .viewport => |x| x.toCss(dest), - .custom_media => |x| x.toCss(dest), - .layer_statement => |x| x.toCss(dest), - .layer_block => |x| x.toCss(dest), - .property => |x| x.toCss(dest), - .starting_style => |x| x.toCss(dest), - .container => |x| x.toCss(dest), - .scope => |x| x.toCss(dest), - .unknown => |x| x.toCss(dest), - .custom => |x| x.toCss(dest) catch return dest.addFmtError(), - .ignored => {}, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -pub fn CssRuleList(comptime AtRule: type) type { - return struct { - v: ArrayList(CssRule(AtRule)) = .{}, - - const This = @This(); - - pub fn minify(this: *This, context: *MinifyContext, parent_is_unused: bool) css.MinifyErr!void { - // var keyframe_rules: keyframes.KeyframesName.HashMap(usize) = .{}; - // _ = keyframe_rules; // autofix - // const layer_rules: layer.LayerName.HashMap(usize) = .{}; - // _ = layer_rules; // autofix - // const property_rules: css.css_values.ident.DashedIdent.HashMap(usize) = .{}; - // _ = property_rules; // autofix - var style_rules = StyleRuleKey(AtRule).HashMap(usize){}; - // _ = style_rules; // autofix - var rules = ArrayList(CssRule(AtRule)){}; - - for (this.v.items) |*rule| { - // NOTE Anytime you append to `rules` with this `rule`, you must set `moved_rule` to true. - var moved_rule = false; - defer if (moved_rule) { - // PERF calling deinit here might allow mimalloc to reuse the freed memory - rule.* = .ignored; - }; - - switch (rule.*) { - .keyframes => |*keyframez| { - _ = keyframez; // autofix - // if (context.unused_symbols.contains(switch (keyframez.name) { - // .ident => |ident| ident.v, - // .custom => |custom| custom, - // })) { - // continue; - // } - - // keyframez.minify(context); - - // // Merge @keyframes rules with the same name. - // if (keyframe_rules.get(keyframez.name)) |existing_idx| { - // if (existing_idx < rules.items.len and rules.items[existing_idx] == .keyframes) { - // var existing = &rules.items[existing_idx].keyframes; - // // If the existing rule has the same vendor prefixes, replace it with this rule. - // if (existing.vendor_prefix.eq(keyframez.vendor_prefix)) { - // existing.* = keyframez.clone(context.allocator); - // continue; - // } - // // Otherwise, if the keyframes are identical, merge the prefixes. - // if (existing.keyframes == keyframez.keyframes) { - // existing.vendor_prefix |= keyframez.vendor_prefix; - // existing.vendor_prefix = context.targets.prefixes(existing.vendor_prefix, css.prefixes.Feature.at_keyframes); - // continue; - // } - // } - // } - - // keyframez.vendor_prefix = context.targets.prefixes(keyframez.vendor_prefix, css.prefixes.Feature.at_keyframes); - // bun.handleOom(keyframe_rules.put(context.allocator, keyframez.name, rules.items.len)); - - // const fallbacks = keyframez.getFallbacks(AtRule, context.targets); - // moved_rule = true; - // bun.handleOom(rules.append(context.allocator, rule.*)); - // bun.handleOom(rules.appendSlice(context.allocator, fallbacks)); - // continue; - debug("TODO: KeyframesRule", .{}); - }, - .custom_media => { - if (context.custom_media != null) { - continue; - } - }, - .media => |*med| { - moved_rule = false; - if (rules.items.len > 0 and rules.items[rules.items.len - 1] == .media) { - var last_rule = &rules.items[rules.items.len - 1].media; - if (last_rule.query.eql(&med.query)) { - bun.handleOom(last_rule.rules.v.appendSlice(context.allocator, med.rules.v.items)); - _ = try last_rule.minify(context, parent_is_unused); - continue; - } - } - if (try med.minify(context, parent_is_unused)) { - continue; - } - }, - .supports => |*supp| { - if (rules.items.len > 0 and rules.items[rules.items.len - 1] == .supports) { - var last_rule = &rules.items[rules.items.len - 1].supports; - if (last_rule.condition.eql(&supp.condition)) { - continue; - } - } - - try supp.minify(context, parent_is_unused); - if (supp.rules.v.items.len == 0) continue; - }, - .container => |*cont| { - _ = cont; // autofix - debug("TODO: ContainerRule", .{}); - }, - .layer_block => |*lay| { - try lay.rules.minify(context, parent_is_unused); - if (lay.rules.v.items.len == 0) continue; - }, - .layer_statement => |*lay| { - _ = lay; // autofix - debug("TODO: LayerStatementRule", .{}); - }, - .moz_document => |*doc| { - _ = doc; // autofix - debug("TODO: MozDocumentRule", .{}); - }, - .style => |*sty| { - const Selector = css.selector.Selector; - const SelectorList = css.selector.SelectorList; - const Component = css.selector.Component; - debug("Input style:\n Selectors: {f}\n Decls: {f}\n", .{ sty.selectors.debug(), sty.declarations.debug() }); - if (parent_is_unused or try sty.minify(context, parent_is_unused)) { - continue; - } - - // If some of the selectors in this rule are not compatible with the targets, - // we need to either wrap in :is() or split them into multiple rules. - var incompatible: css.SmallList(css.selector.parser.Selector, 1) = if (sty.selectors.v.len() > 1 and - context.targets.shouldCompileSelectors() and - !sty.isCompatible(context.targets.*)) - incompatible: { - debug("Making incompatible!\n", .{}); - // The :is() selector accepts a forgiving selector list, so use that if possible. - // Note that :is() does not allow pseudo elements, so we need to check for that. - // In addition, :is() takes the highest specificity of its arguments, so if the selectors - // have different weights, we need to split them into separate rules as well. - if (context.targets.isCompatible(css.compat.Feature.is_selector) and !sty.selectors.anyHasPseudoElement() and sty.selectors.specifitiesAllEqual()) { - const component = Component{ .is = sty.selectors.v.toOwnedSlice(context.allocator) }; - var list = css.SmallList(css.selector.parser.Selector, 1){}; - list.append(context.allocator, Selector.fromComponent(context.allocator, component)); - sty.selectors = SelectorList{ - .v = list, - }; - break :incompatible css.SmallList(Selector, 1){}; - } else { - // Otherwise, partition the selectors and keep the compatible ones in this rule. - // We will generate additional rules for incompatible selectors later. - var incompatible = css.SmallList(Selector, 1){}; - var i: u32 = 0; - while (i < sty.selectors.v.len()) { - if (css.selector.isCompatible(sty.selectors.v.slice()[i .. i + 1], context.targets.*)) { - i += 1; - } else { - // Move the selector to the incompatible list. - incompatible.append( - context.allocator, - sty.selectors.v.orderedRemove(i), - ); - } - } - break :incompatible incompatible; - } - } else .{}; - - sty.updatePrefix(context); - - // Attempt to merge the new rule with the last rule we added. - var merged = false; - if (rules.items.len > 0 and rules.items[rules.items.len - 1] == .style) { - const last_style_rule = &rules.items[rules.items.len - 1].style; - if (mergeStyleRules(AtRule, sty, last_style_rule, context)) { - // If that was successful, then the last rule has been updated to include the - // selectors/declarations of the new rule. This might mean that we can merge it - // with the previous rule, so continue trying while we have style rules available. - while (rules.items.len >= 2) { - const len = rules.items.len; - var a, var b = bun.splitAtMut(CssRule(AtRule), rules.items, len - 1); - if (b[0] == .style and a[len - 2] == .style) { - if (mergeStyleRules(AtRule, &b[0].style, &a[len - 2].style, context)) { - // If we were able to merge the last rule into the previous one, remove the last. - const popped = rules.pop(); - _ = popped; // autofix - // TODO: deinit? - // popped.deinit(contet.allocator); - continue; - } - } - // If we didn't see a style rule, or were unable to merge, stop. - break; - } - merged = true; - } - } - - // Create additional rules for logical properties, @supports overrides, and incompatible selectors. - const supps = context.handler_context.getSupportsRules(AtRule, sty); - const logical = context.handler_context.getAdditionalRules(AtRule, sty); - debug("LOGICAL: {d}\n", .{logical.items.len}); - const StyleRule = style.StyleRule(AtRule); - - const IncompatibleRuleEntry = struct { rule: StyleRule, supports: ArrayList(css.CssRule(AtRule)), logical: ArrayList(css.CssRule(AtRule)) }; - var incompatible_rules: css.SmallList(IncompatibleRuleEntry, 1) = incompatible_rules: { - var incompatible_rules = css.SmallList(IncompatibleRuleEntry, 1).initCapacity( - context.allocator, - incompatible.len(), - ); - - for (incompatible.slice_mut()) |sel| { - // Create a clone of the rule with only the one incompatible selector. - const list = SelectorList{ .v = css.SmallList(Selector, 1).withOne(sel) }; - var clone: StyleRule = .{ - .selectors = list, - .vendor_prefix = sty.vendor_prefix, - .declarations = sty.declarations.deepClone(context.allocator), - .rules = sty.rules.deepClone(context.allocator), - .loc = sty.loc, - }; - clone.updatePrefix(context); - - // Also add rules for logical properties and @supports overrides. - const s = context.handler_context.getSupportsRules(AtRule, &clone); - const l = context.handler_context.getAdditionalRules(AtRule, &clone); - incompatible_rules.append(context.allocator, IncompatibleRuleEntry{ - .rule = clone, - .supports = s, - .logical = l, - }); - } - - break :incompatible_rules incompatible_rules; - }; - debug("Incompatible rules: {d}\n", .{incompatible_rules.len()}); - defer incompatible.deinit(context.allocator); - defer incompatible_rules.deinit(context.allocator); - - context.handler_context.reset(); - - // If the rule has nested rules, and we have extra rules to insert such as for logical properties, - // we need to split the rule in two so we can insert the extra rules in between the declarations from - // the main rule and the nested rules. - const nested_rule: ?StyleRule = if (sty.rules.v.items.len > 0 and - // can happen if there are no compatible rules, above. - sty.selectors.v.len() > 0 and - (logical.items.len > 0 or supps.items.len > 0 or !incompatible_rules.isEmpty())) - brk: { - var rulesss: CssRuleList(AtRule) = .{}; - std.mem.swap(CssRuleList(AtRule), &sty.rules, &rulesss); - break :brk StyleRule{ - .selectors = sty.selectors.deepClone(context.allocator), - .declarations = css.DeclarationBlock{}, - .rules = rulesss, - .vendor_prefix = sty.vendor_prefix, - .loc = sty.loc, - }; - } else null; - - if (!merged and !sty.isEmpty()) { - const source_index = sty.loc.source_index; - const has_no_rules = sty.rules.v.items.len == 0; - const idx = rules.items.len; - - bun.handleOom(rules.append(context.allocator, rule.*)); - moved_rule = true; - - // Check if this rule is a duplicate of an earlier rule, meaning it has - // the same selectors and defines the same properties. If so, remove the - // earlier rule because this one completely overrides it. - if (has_no_rules) { - const key = StyleRuleKey(AtRule).new(&rules, idx); - if (idx > 0) { - if (style_rules.fetchSwapRemove(key)) |i_| { - const i = i_.value; - if (i < rules.items.len and rules.items[i] == .style) { - const other = &rules.items[i].style; - // Don't remove the rule if this is a CSS module and the other rule came from a different file. - if (!context.css_modules or source_index == other.loc.source_index) { - // Only mark the rule as ignored so we don't need to change all of the indices. - rules.items[i] = .ignored; - } - } - } - } - - bun.handleOom(style_rules.put(context.allocator, key, idx)); - } - } - - if (logical.items.len > 0) { - if (bun.Environment.isDebug and logical.items[0] == .style) { - debug("Adding logical: {f}\n", .{logical.items[0].style.selectors.debug()}); - } - var log = CssRuleList(AtRule){ .v = logical }; - try log.minify(context, parent_is_unused); - bun.handleOom(rules.appendSlice(context.allocator, log.v.items)); - } - bun.handleOom(rules.appendSlice(context.allocator, supps.items)); - for (incompatible_rules.slice_mut()) |incompatible_entry| { - if (!incompatible_entry.rule.isEmpty()) { - bun.handleOom(rules.append(context.allocator, .{ .style = incompatible_entry.rule })); - } - if (incompatible_entry.logical.items.len > 0) { - var log = CssRuleList(AtRule){ .v = incompatible_entry.logical }; - try log.minify(context, parent_is_unused); - bun.handleOom(rules.appendSlice(context.allocator, log.v.items)); - } - bun.handleOom(rules.appendSlice(context.allocator, incompatible_entry.supports.items)); - } - if (nested_rule) |nested| { - bun.handleOom(rules.append(context.allocator, .{ .style = nested })); - } - - continue; - }, - .counter_style => |*cntr| { - _ = cntr; // autofix - debug("TODO: CounterStyleRule", .{}); - }, - .scope => |*scpe| { - _ = scpe; // autofix - debug("TODO: ScopeRule", .{}); - }, - .nesting => |*nst| { - _ = nst; // autofix - debug("TODO: NestingRule", .{}); - }, - .starting_style => |*rl| { - _ = rl; // autofix - debug("TODO: StartingStyleRule", .{}); - }, - .font_palette_values => |*f| { - _ = f; // autofix - debug("TODO: FontPaletteValuesRule", .{}); - }, - .property => |*prop| { - _ = prop; // autofix - debug("TODO: PropertyRule", .{}); - }, - else => {}, - } - - bun.handleOom(rules.append(context.allocator, rule.*)); - moved_rule = true; - - // Non-style rules (e.g. @property, @keyframes) act as a barrier for - // style rule deduplication. We cannot safely merge identical style rules - // across such boundaries because the intervening at-rule may affect how - // the declarations are interpreted (e.g. @property defines a custom - // property that a :root rule above may set differently than one below). - style_rules.clearRetainingCapacity(); - } - - // MISSING SHIT HERE - - css.deepDeinit(CssRule(AtRule), context.allocator, &this.v); - this.v = rules; - return; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - var first = true; - var last_without_block = false; - - for (this.v.items) |*rule| { - if (rule.* == .ignored) continue; - - // Skip @import rules if collecting dependencies. - if (rule.* == .import) { - if (dest.remove_imports) { - const dep = if (dest.dependencies != null) Dependency{ - .import = dependencies.ImportDependency.new(dest.allocator, &rule.import, dest.filename(), dest.local_names, dest.symbols), - } else null; - - if (dest.dependencies) |*deps| { - deps.append(dest.allocator, dep.?) catch unreachable; - continue; - } - } - } - - if (first) { - first = false; - } else { - if (!dest.minify and - !(last_without_block and - (rule.* == .import or rule.* == .namespace or rule.* == .layer_statement))) - { - try dest.writeChar('\n'); - } - try dest.newline(); - } - try rule.toCss(dest); - last_without_block = rule.* == .import or rule.* == .namespace or rule.* == .layer_statement; - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -pub const MinifyContext = struct { - /// NOTE: this should the same allocator the AST was allocated with - allocator: std.mem.Allocator, - targets: *const css.targets.Targets, - handler: *css.DeclarationHandler, - important_handler: *css.DeclarationHandler, - handler_context: css.PropertyHandlerContext, - unused_symbols: *const std.StringArrayHashMapUnmanaged(void), - custom_media: ?std.StringArrayHashMapUnmanaged(custom_media.CustomMediaRule), - extra: *const css.StylesheetExtra, - css_modules: bool, - err: ?css.MinifyError = null, -}; - -pub const Location = struct { - /// The index of the source file within the source map. - source_index: u32, - /// The line number, starting at 0. - line: u32, - /// The column number within a line, starting at 1 for first the character of the line. - /// Column numbers are counted in UTF-16 code units. - column: u32, - - pub fn dummy() Location { - return .{ - .source_index = std.math.maxInt(u32), - .line = std.math.maxInt(u32), - .column = std.math.maxInt(u32), - }; - } -}; - -pub const StyleContext = struct { - selectors: *const css.SelectorList, - parent: ?*const StyleContext, -}; - -/// A key to a StyleRule meant for use in a HashMap for quickly detecting duplicates. -/// It stores a reference to a list and an index so it can access items without cloning -/// even when the list is reallocated. A hash is also pre-computed for fast lookups. -pub fn StyleRuleKey(comptime R: type) type { - return struct { - list: *const ArrayList(CssRule(R)), - index: usize, - // TODO: store in the hashmap by setting `store_hash` to true - hash: u64, - - const This = @This(); - - pub fn HashMap(comptime V: type) type { - return std.ArrayHashMapUnmanaged( - StyleRuleKey(R), - V, - struct { - pub fn hash(_: @This(), key: This) u32 { - return @truncate(key.hash); - } - - pub fn eql(_: @This(), a: This, b: This, _: usize) bool { - return a.eql(&b); - } - }, - // TODO: make this true - false, - ); - } - - pub fn new(list: *const ArrayList(CssRule(R)), index: usize) This { - const rule = &list.items[index].style; - return This{ - .list = list, - .index = index, - .hash = rule.hashKey(), - }; - } - - pub fn eql(this: *const This, other: *const This) bool { - const rule = if (this.index < this.list.items.len and this.list.items[this.index] == .style) - &this.list.items[this.index].style - else - return false; - - const other_rule = if (other.index < other.list.items.len and other.list.items[other.index] == .style) - &other.list.items[other.index].style - else - return false; - - return rule.isDuplicate(other_rule); - } - }; -} - -fn mergeStyleRules( - comptime T: type, - sty: *style.StyleRule(T), - last_style_rule: *style.StyleRule(T), - context: *MinifyContext, -) bool { - // Merge declarations if the selectors are equivalent, and both are compatible with all targets. - // Does not apply if css modules are enabled - if (sty.selectors.eql(&last_style_rule.selectors) and - sty.isCompatible(context.targets.*) and - last_style_rule.isCompatible(context.targets.*) and - sty.rules.v.items.len == 0 and - last_style_rule.rules.v.items.len == 0 and - (!context.css_modules or sty.loc.source_index == last_style_rule.loc.source_index)) - { - last_style_rule.declarations.declarations.appendSlice( - context.allocator, - sty.declarations.declarations.items, - ) catch |err| bun.handleOom(err); - sty.declarations.declarations.clearRetainingCapacity(); - - last_style_rule.declarations.important_declarations.appendSlice( - context.allocator, - sty.declarations.important_declarations.items, - ) catch |err| bun.handleOom(err); - sty.declarations.important_declarations.clearRetainingCapacity(); - - last_style_rule.declarations.minify( - context.handler, - context.important_handler, - &context.handler_context, - ); - return true; - } else if (sty.declarations.eql(&last_style_rule.declarations) and - sty.rules.v.items.len == 0 and - last_style_rule.rules.v.items.len == 0) - { - // If both selectors are potentially vendor prefixable, and they are - // equivalent minus prefixes, add the prefix to the last rule. - if (!sty.vendor_prefix.isEmpty() and - !last_style_rule.vendor_prefix.isEmpty() and - css.selector.isEquivalent(sty.selectors.v.slice(), last_style_rule.selectors.v.slice())) - { - // If the new rule is unprefixed, replace the prefixes of the last rule. - // Otherwise, add the new prefix. - if (sty.vendor_prefix.none and context.targets.shouldCompileSelectors()) { - last_style_rule.vendor_prefix = sty.vendor_prefix; - } else { - bun.bits.insert(css.VendorPrefix, &last_style_rule.vendor_prefix, sty.vendor_prefix); - } - return true; - } - - // Append the selectors to the last rule if the declarations are the same, and all selectors are compatible. - if (sty.isCompatible(context.targets.*) and last_style_rule.isCompatible(context.targets.*)) { - last_style_rule.selectors.v.appendSlice( - context.allocator, - sty.selectors.v.slice(), - ); - sty.selectors.v.clearRetainingCapacity(); - if (sty.vendor_prefix.none and context.targets.shouldCompileSelectors()) { - last_style_rule.vendor_prefix = sty.vendor_prefix; - } else { - bun.bits.insert(css.VendorPrefix, &last_style_rule.vendor_prefix, sty.vendor_prefix); - } - return true; - } - } - return false; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/scope.zig b/src/css/rules/scope.zig deleted file mode 100644 index 436ea792eaa0..000000000000 --- a/src/css/rules/scope.zig +++ /dev/null @@ -1,76 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const style = css.css_rules.style; -const CssRuleList = css.CssRuleList; - -/// A [@scope](https://drafts.csswg.org/css-cascade-6/#scope-atrule) rule. -/// -/// @scope () [to ()]? { -/// -/// } -pub fn ScopeRule(comptime R: type) type { - return struct { - /// A selector list used to identify the scoping root(s). - scope_start: ?css.selector.parser.SelectorList, - /// A selector list used to identify any scoping limits. - scope_end: ?css.selector.parser.SelectorList, - /// Nested rules within the `@scope` rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@scope"); - try dest.whitespace(); - if (this.scope_start) |*scope_start| { - try dest.writeChar('('); - // try scope_start.toCss(dest); - try css.selector.serialize.serializeSelectorList(scope_start.v.slice(), dest, dest.context(), false); - try dest.writeChar(')'); - try dest.whitespace(); - } - if (this.scope_end) |*scope_end| { - if (dest.minify) { - try dest.writeChar(' '); - } - try dest.writeStr("to ("); - // is treated as an ancestor of scope end. - // https://drafts.csswg.org/css-nesting/#nesting-at-scope - if (this.scope_start) |*scope_start| { - try dest.withContext(scope_start, scope_end, struct { - pub fn toCssFn(scope_end_: *const css.selector.parser.SelectorList, d: *Printer) PrintErr!void { - return css.selector.serialize.serializeSelectorList(scope_end_.v.slice(), d, d.context(), false); - } - }.toCssFn); - } else { - return css.selector.serialize.serializeSelectorList(scope_end.v.slice(), dest, dest.context(), false); - } - try dest.writeChar(')'); - try dest.whitespace(); - } - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - // Nested style rules within @scope are implicitly relative to the - // so clear our style context while printing them to avoid replacing & ourselves. - // https://drafts.csswg.org/css-cascade-6/#scoped-rules - try dest.withClearedContext(&this.rules, CssRuleList(R).toCss); - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -const std = @import("std"); diff --git a/src/css/rules/starting_style.zig b/src/css/rules/starting_style.zig deleted file mode 100644 index 543362646b72..000000000000 --- a/src/css/rules/starting_style.zig +++ /dev/null @@ -1,39 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; -const style = css.css_rules.style; -const CssRuleList = css.CssRuleList; - -/// A [@starting-style](https://drafts.csswg.org/css-transitions-2/#defining-before-change-style-the-starting-style-rule) rule. -pub fn StartingStyleRule(comptime R: type) type { - return struct { - /// Nested rules within the `@starting-style` rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@starting-style"); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - try this.rules.toCss(dest); - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -const std = @import("std"); diff --git a/src/css/rules/style.zig b/src/css/rules/style.zig deleted file mode 100644 index 3893251310a7..000000000000 --- a/src/css/rules/style.zig +++ /dev/null @@ -1,249 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; - -pub fn StyleRule(comptime R: type) type { - return struct { - /// The selectors for the style rule. - selectors: css.selector.parser.SelectorList, - /// A vendor prefix override, used during selector printing. - vendor_prefix: css.VendorPrefix, - /// The declarations within the style rule. - declarations: css.DeclarationBlock, - /// Nested rules within the style rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: css.Location, - - const This = @This(); - - /// Returns whether the rule is empty. - pub fn isEmpty(this: *const This) bool { - return this.selectors.v.isEmpty() or (this.declarations.isEmpty() and this.rules.v.items.len == 0); - } - - /// Returns a hash of this rule for use when deduplicating. - /// Includes the selectors and properties. - pub fn hashKey(this: *const This) u64 { - var hasher = std.hash.Wyhash.init(0); - this.selectors.hash(&hasher); - this.declarations.hashPropertyIds(&hasher); - return hasher.final(); - } - - pub fn deepClone(this: *const This, allocator: std.mem.Allocator) This { - return This{ - .selectors = this.selectors.deepClone(allocator), - .vendor_prefix = this.vendor_prefix, - .declarations = this.declarations.deepClone(allocator), - .rules = this.rules.deepClone(allocator), - .loc = this.loc, - }; - } - - pub fn updatePrefix(this: *This, context: *css.MinifyContext) void { - this.vendor_prefix = css.selector.getPrefix(&this.selectors); - if (this.vendor_prefix.none and - context.targets.shouldCompileSelectors()) - { - this.vendor_prefix = css.selector.downlevelSelectors(context.allocator, this.selectors.v.slice_mut(), context.targets.*); - } - } - - pub fn isCompatible(this: *const This, targets: css.targets.Targets) bool { - return css.selector.isCompatible(this.selectors.v.slice(), targets); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - if (this.vendor_prefix.isEmpty()) { - try this.toCssBase(dest); - } else { - var first_rule = true; - inline for (css.VendorPrefix.FIELDS) |field| { - if (@field(this.vendor_prefix, field)) { - if (first_rule) { - first_rule = false; - } else { - if (!dest.minify) { - try dest.writeChar('\n'); // no indent - } - try dest.newline(); - } - - const prefix = css.VendorPrefix.fromName(field); - dest.vendor_prefix = prefix; - try this.toCssBase(dest); - } - } - - dest.vendor_prefix = .{}; - } - } - - fn toCssBase(this: *const This, dest: *Printer) PrintErr!void { - // If supported, or there are no targets, preserve nesting. Otherwise, write nested rules after parent. - const supports_nesting = this.rules.v.items.len == 0 or - !css.Targets.shouldCompileSame( - &dest.targets, - .nesting, - ); - - const len = this.declarations.declarations.items.len + this.declarations.important_declarations.items.len; - const has_declarations = supports_nesting or len > 0 or this.rules.v.items.len == 0; - - if (has_declarations) { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try css.selector.serialize.serializeSelectorList(this.selectors.v.slice(), dest, dest.context(), false); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - - var i: usize = 0; - const DECLS = .{ "declarations", "important_declarations" }; - inline for (DECLS) |decl_field_name| { - const important = comptime std.mem.eql(u8, decl_field_name, "important_declarations"); - const decls: *const ArrayList(css.Property) = &@field(this.declarations, decl_field_name); - - for (decls.items) |*decl| { - // The CSS modules `composes` property is handled specially, and omitted during printing. - // We need to add the classes it references to the list for the selectors in this rule. - if (decl.* == .composes) { - const composes = &decl.composes; - if (dest.isNested() and dest.css_module != null) { - return dest.newError(css.PrinterErrorKind.invalid_composes_nesting, composes.cssparser_loc); - } - - if (dest.css_module) |*css_module| { - if (css_module.handleComposes( - dest, - &this.selectors, - composes, - this.loc.source_index, - ).asErr()) |error_kind| { - return dest.newError(error_kind, composes.cssparser_loc); - } - continue; - } - } - - try dest.newline(); - try decl.toCss(dest, important); - if (i != len - 1 or !dest.minify or (supports_nesting and this.rules.v.items.len > 0)) { - try dest.writeChar(';'); - } - - i += 1; - } - } - } - - const Helpers = struct { - pub fn newline( - self: *const This, - d: *Printer, - supports_nesting2: bool, - len1: usize, - ) PrintErr!void { - if (!d.minify and (supports_nesting2 or len1 > 0) and self.rules.v.items.len > 0) { - if (len1 > 0) { - try d.writeChar('\n'); - } - try d.newline(); - } - } - - pub fn end(d: *Printer, has_decls: bool) PrintErr!void { - if (has_decls) { - d.dedent(); - try d.newline(); - try d.writeChar('}'); - } - } - }; - - // Write nested rules after the parent. - if (supports_nesting) { - try Helpers.newline(this, dest, supports_nesting, len); - try this.rules.toCss(dest); - try Helpers.end(dest, has_declarations); - } else { - try Helpers.end(dest, has_declarations); - try Helpers.newline(this, dest, supports_nesting, len); - try dest.withContext(&this.selectors, this, struct { - pub fn toCss(self: *const This, d: *Printer) PrintErr!void { - return self.rules.toCss(d); - } - }.toCss); - } - } - - pub fn minify(this: *This, context: *css.MinifyContext, parent_is_unused: bool) css.MinifyErr!bool { - var unused = false; - if (context.unused_symbols.count() > 0) { - if (css.selector.isUnused(this.selectors.v.slice(), context.unused_symbols, &context.extra.symbols, parent_is_unused)) { - if (this.rules.v.items.len == 0) { - return true; - } - - this.declarations.declarations.clearRetainingCapacity(); - this.declarations.important_declarations.clearRetainingCapacity(); - unused = true; - } - } - - // TODO: this - // let pure_css_modules = context.pure_css_modules; - // if context.pure_css_modules { - // if !self.selectors.0.iter().all(is_pure_css_modules_selector) { - // return Err(MinifyError { - // kind: crate::error::MinifyErrorKind::ImpureCSSModuleSelector, - // loc: self.loc, - // }); - // } - - // // Parent rule contained id or class, so child rules don't need to. - // context.pure_css_modules = false; - // } - - context.handler_context.context = .style_rule; - this.declarations.minify(context.handler, context.important_handler, &context.handler_context); - context.handler_context.context = .none; - - if (this.rules.v.items.len > 0) { - var handler_context = context.handler_context.child(.style_rule); - std.mem.swap(css.PropertyHandlerContext, &context.handler_context, &handler_context); - try this.rules.minify(context, unused); - std.mem.swap(css.PropertyHandlerContext, &context.handler_context, &handler_context); - if (unused and this.rules.v.items.len == 0) { - return true; - } - } - - return false; - } - - /// Returns whether this rule is a duplicate of another rule. - /// This means it has the same selectors and properties. - pub inline fn isDuplicate(this: *const This, other: *const This) bool { - return this.declarations.len() == other.declarations.len() and - this.selectors.eql(&other.selectors) and - brk: { - var len = @min(this.declarations.declarations.items.len, other.declarations.declarations.items.len); - for (this.declarations.declarations.items[0..len], other.declarations.declarations.items[0..len]) |*a, *b| { - if (!a.propertyId().eql(&b.propertyId())) break :brk false; - } - len = @min(this.declarations.important_declarations.items.len, other.declarations.important_declarations.items.len); - for (this.declarations.important_declarations.items[0..len], other.declarations.important_declarations.items[0..len]) |*a, *b| { - if (!a.propertyId().eql(&b.propertyId())) break :brk false; - } - break :brk true; - }; - } - }; -} - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/supports.zig b/src/css/rules/supports.zig deleted file mode 100644 index de7d5edfe49f..000000000000 --- a/src/css/rules/supports.zig +++ /dev/null @@ -1,419 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; - -/// A [``](https://drafts.csswg.org/css-conditional-3/#typedef-supports-condition), -/// as used in the `@supports` and `@import` rules. -pub const SupportsCondition = union(enum) { - /// A `not` expression. - not: *SupportsCondition, - - /// An `and` expression. - @"and": ArrayList(SupportsCondition), - - /// An `or` expression. - @"or": ArrayList(SupportsCondition), - - /// A declaration to evaluate. - declaration: struct { - /// The property id for the declaration. - property_id: css.PropertyId, - /// The raw value of the declaration. - /// - /// What happens if the value is a URL? A URL in this context does nothing - /// e.g. `@supports (background-image: url('example.png'))` - value: []const u8, - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }, - - /// A selector to evaluate. - selector: []const u8, - - /// An unknown condition. - unknown: []const u8, - - pub fn deinit(this: *@This(), allocator: std.mem.Allocator) void { - switch (this.*) { - .not => |not| { - not.deinit(allocator); - allocator.destroy(not); - }, - inline .@"and", .@"or" => |*list| { - css.deepDeinit(SupportsCondition, allocator, list); - }, - .declaration => {}, - .selector => {}, - .unknown => {}, - } - } - - pub fn cloneWithImportRecords( - this: *const @This(), - allocator: std.mem.Allocator, - _: *bun.BabyList(bun.ImportRecord), - ) @This() { - return deepClone(this, allocator); - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn eql(this: *const SupportsCondition, other: *const SupportsCondition) bool { - return css.implementEql(SupportsCondition, this, other); - } - - pub fn deepClone(this: *const SupportsCondition, allocator: std.mem.Allocator) SupportsCondition { - return css.implementDeepClone(SupportsCondition, this, allocator); - } - - fn needsParens(this: *const SupportsCondition, parent: *const SupportsCondition) bool { - return switch (this.*) { - .not => true, - .@"and" => parent.* != .@"and", - .@"or" => parent.* != .@"or", - else => false, - }; - } - - const SeenDeclKey = struct { - css.PropertyId, - []const u8, - }; - - pub fn parse(input: *css.Parser) Result(SupportsCondition) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"not"}).isOk()) { - const in_parens = switch (SupportsCondition.parseInParens(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = .{ - .not = bun.create( - input.allocator(), - SupportsCondition, - in_parens, - ), - }, - }; - } - - const in_parens: SupportsCondition = switch (SupportsCondition.parseInParens(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - var expected_type: ?i32 = null; - var conditions = ArrayList(SupportsCondition){}; - const mapalloc: std.mem.Allocator = input.allocator(); - var seen_declarations = std.ArrayHashMap( - SeenDeclKey, - usize, - struct { - pub fn hash(self: @This(), s: SeenDeclKey) u32 { - _ = self; // autofix - return std.array_hash_map.hashString(s[1]) +% @intFromEnum(s[0]); - } - pub fn eql(self: @This(), a: SeenDeclKey, b: SeenDeclKey, b_index: usize) bool { - _ = self; // autofix - _ = b_index; // autofix - return seenDeclKeyEql(a, b); - } - - pub inline fn seenDeclKeyEql(this: SeenDeclKey, that: SeenDeclKey) bool { - return @intFromEnum(this[0]) == @intFromEnum(that[0]) and bun.strings.eql(this[1], that[1]); - } - }, - false, - ).init(mapalloc); - defer seen_declarations.deinit(); - - while (true) { - const Closure = struct { - expected_type: *?i32, - pub fn tryParseFn(i: *css.Parser, this: *@This()) Result(SupportsCondition) { - const location = i.currentSourceLocation(); - const s = switch (i.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const found_type: i32 = found_type: { - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("and", s)) break :found_type 1; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("or", s)) break :found_type 2; - return .{ .err = location.newUnexpectedTokenError(.{ .ident = s }) }; - }; - - if (this.expected_type.*) |expected| { - if (found_type != expected) { - return .{ .err = location.newUnexpectedTokenError(.{ .ident = s }) }; - } - } else { - this.expected_type.* = found_type; - } - - return SupportsCondition.parseInParens(i); - } - }; - var closure = Closure{ - .expected_type = &expected_type, - }; - const _condition = input.tryParse(Closure.tryParseFn, .{&closure}); - - switch (_condition) { - .result => |condition| { - if (conditions.items.len == 0) { - bun.handleOom(conditions.append(input.allocator(), in_parens.deepClone(input.allocator()))); - if (in_parens == .declaration) { - const property_id = in_parens.declaration.property_id; - const value = in_parens.declaration.value; - seen_declarations.put( - .{ property_id.withPrefix(css.VendorPrefix{ .none = true }), value }, - 0, - ) catch |err| bun.handleOom(err); - } - } - - if (condition == .declaration) { - // Merge multiple declarations with the same property id (minus prefix) and value together. - const property_id_ = condition.declaration.property_id; - const value = condition.declaration.value; - - const property_id = property_id_.withPrefix(css.VendorPrefix{ .none = true }); - const key = SeenDeclKey{ property_id, value }; - if (seen_declarations.get(key)) |index| { - const cond = &conditions.items[index]; - if (cond.* == .declaration) { - cond.declaration.property_id.addPrefix(property_id.prefix()); - } - } else { - bun.handleOom(seen_declarations.put(key, conditions.items.len)); - conditions.append(input.allocator(), SupportsCondition{ .declaration = .{ - .property_id = property_id, - .value = value, - } }) catch |err| bun.handleOom(err); - } - } else { - conditions.append( - input.allocator(), - condition, - ) catch |err| bun.handleOom(err); - } - }, - else => break, - } - } - - if (conditions.items.len == 1) { - const ret = conditions.pop().?; - defer conditions.deinit(input.allocator()); - return .{ .result = ret }; - } - - if (expected_type == 1) return .{ .result = .{ .@"and" = conditions } }; - if (expected_type == 2) return .{ .result = .{ .@"or" = conditions } }; - return .{ .result = in_parens }; - } - - pub fn parseDeclaration(input: *css.Parser) Result(SupportsCondition) { - const property_id = switch (css.PropertyId.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (input.expectColon().asErr()) |e| return .{ .err = e }; - input.skipWhitespace(); - const pos = input.position(); - if (input.expectNoErrorToken().asErr()) |e| return .{ .err = e }; - return .{ .result = SupportsCondition{ - .declaration = .{ - .property_id = property_id, - .value = input.sliceFrom(pos), - }, - } }; - } - - fn parseInParens(input: *css.Parser) Result(SupportsCondition) { - input.skipWhitespace(); - const location = input.currentSourceLocation(); - const pos = input.position(); - const tok = switch (input.next()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - switch (tok.*) { - .function => |f| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("selector", f)) { - const Fn = struct { - pub fn tryParseFn(i: *css.Parser) Result(SupportsCondition) { - return i.parseNestedBlock(SupportsCondition, {}, @This().parseNestedBlockFn); - } - pub fn parseNestedBlockFn(_: void, i: *css.Parser) Result(SupportsCondition) { - const p = i.position(); - if (i.expectNoErrorToken().asErr()) |e| return .{ .err = e }; - return .{ .result = SupportsCondition{ .selector = i.sliceFrom(p) } }; - } - }; - const res = input.tryParse(Fn.tryParseFn, .{}); - if (res.isOk()) return res; - } - }, - .open_paren => { - const res = input.tryParse(struct { - pub fn parseFn(i: *css.Parser) Result(SupportsCondition) { - return i.parseNestedBlock(SupportsCondition, {}, css.voidWrap(SupportsCondition, parse)); - } - }.parseFn, .{}); - if (res.isOk()) return res; - }, - else => return .{ .err = location.newUnexpectedTokenError(tok.*) }, - } - - if (input.parseNestedBlock(void, {}, struct { - pub fn parseFn(_: void, i: *css.Parser) Result(void) { - return i.expectNoErrorToken(); - } - }.parseFn).asErr()) |err| { - return .{ .err = err }; - } - - return .{ .result = SupportsCondition{ .unknown = input.sliceFrom(pos) } }; - } - - pub fn toCss(this: *const SupportsCondition, dest: *css.Printer) css.PrintErr!void { - switch (this.*) { - .not => |condition| { - try dest.writeStr(" not "); - try condition.toCssWithParensIfNeeded(dest, condition.needsParens(this)); - }, - .@"and" => |conditions| { - var first = true; - for (conditions.items) |*cond| { - if (first) { - first = false; - } else { - try dest.writeStr(" and "); - } - try cond.toCssWithParensIfNeeded(dest, cond.needsParens(this)); - } - }, - .@"or" => |conditions| { - var first = true; - for (conditions.items) |*cond| { - if (first) { - first = false; - } else { - try dest.writeStr(" or "); - } - try cond.toCssWithParensIfNeeded(dest, cond.needsParens(this)); - } - }, - .declaration => |decl| { - const property_id = decl.property_id; - const value = decl.value; - - try dest.writeChar('('); - - const prefix: css.VendorPrefix = property_id.prefix().orNone(); - if (prefix != css.VendorPrefix{ .none = true }) { - try dest.writeChar('('); - } - - const name = property_id.name(); - var first = true; - inline for (css.VendorPrefix.FIELDS) |field| { - if (@field(prefix, field)) { - if (first) { - first = false; - } else { - try dest.writeStr(") or ("); - } - - var p = css.VendorPrefix{}; - @field(p, field) = true; - css.serializer.serializeName(name, dest) catch return dest.addFmtError(); - try dest.delim(':', false); - try dest.writeStr(value); - } - } - - if (prefix != css.VendorPrefix{ .none = true }) { - try dest.writeChar(')'); - } - try dest.writeChar(')'); - }, - .selector => |sel| { - try dest.writeStr("selector("); - try dest.writeStr(sel); - try dest.writeChar(')'); - }, - .unknown => |unk| { - try dest.writeStr(unk); - }, - } - } - - pub fn toCssWithParensIfNeeded( - this: *const SupportsCondition, - dest: *css.Printer, - needs_parens: bool, - ) css.PrintErr!void { - if (needs_parens) try dest.writeStr("("); - try this.toCss(dest); - if (needs_parens) try dest.writeStr(")"); - } -}; - -/// A [@supports](https://drafts.csswg.org/css-conditional-3/#at-supports) rule. -pub fn SupportsRule(comptime R: type) type { - return struct { - /// The supports condition. - condition: SupportsCondition, - /// The rules within the `@supports` rule. - rules: css.CssRuleList(R), - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeStr("@supports "); - try this.condition.toCss(dest); - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - try this.rules.toCss(dest); - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } - - pub fn minify(this: *This, context: *css.MinifyContext, parent_is_unused: bool) css.MinifyErr!void { - _ = this; // autofix - _ = context; // autofix - _ = parent_is_unused; // autofix - // TODO: Implement this - return; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - }; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/rules/tailwind.zig b/src/css/rules/tailwind.zig deleted file mode 100644 index 4ac5022af088..000000000000 --- a/src/css/rules/tailwind.zig +++ /dev/null @@ -1,57 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const css_values = @import("../values/values.zig"); -pub const Error = css.Error; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -/// @tailwind -/// https://github.com/tailwindlabs/tailwindcss.com/blob/4d6ac11425d96bc963f936e0157df460a364c43b/src/pages/docs/functions-and-directives.mdx?plain=1#L13 -pub const TailwindAtRule = struct { - style_name: TailwindStyleName, - /// The location of the rule in the source file. - loc: css.Location, - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - try dest.writeStr("@tailwind"); - try dest.whitespace(); - try this.style_name.toCss(dest); - try dest.writeChar(';'); - } - - pub fn deepClone(this: *const @This(), _: std.mem.Allocator) @This() { - return this.*; - } -}; - -pub const TailwindStyleName = enum { - /// This injects Tailwind's base styles and any base styles registered by - /// plugins. - base, - /// This injects Tailwind's component classes and any component classes - /// registered by plugins. - components, - /// This injects Tailwind's utility classes and any utility classes registered - /// by plugins. - utilities, - /// Use this directive to control where Tailwind injects the hover, focus, - /// responsive, dark mode, and other variants of each class. - /// - /// If omitted, Tailwind will append these classes to the very end of - /// your stylesheet by default. - variants, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) css.Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/rules/unknown.zig b/src/css/rules/unknown.zig deleted file mode 100644 index 7141ffa3580c..000000000000 --- a/src/css/rules/unknown.zig +++ /dev/null @@ -1,52 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const css_values = @import("../values/values.zig"); -pub const Error = css.Error; -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -/// An unknown at-rule, stored as raw tokens. -pub const UnknownAtRule = struct { - /// The name of the at-rule (without the @). - name: []const u8, - /// The prelude of the rule. - prelude: css.TokenList, - /// The contents of the block, if any. - block: ?css.TokenList, - /// The location of the rule in the source file. - loc: css.Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - - try dest.writeChar('@'); - try dest.writeStr(this.name); - - if (this.prelude.v.items.len > 0) { - try dest.writeChar(' '); - try this.prelude.toCss(dest, false); - } - - if (this.block) |*block| { - try dest.whitespace(); - try dest.writeChar('{'); - dest.indent(); - try dest.newline(); - try block.toCss(dest, false); - dest.dedent(); - try dest.newline(); - try dest.writeChar('}'); - } else { - try dest.writeChar(';'); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/rules/viewport.zig b/src/css/rules/viewport.zig deleted file mode 100644 index b9386d1eaa21..000000000000 --- a/src/css/rules/viewport.zig +++ /dev/null @@ -1,31 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Location = css.css_rules.Location; - -/// A [@viewport](https://drafts.csswg.org/css-device-adapt/#atviewport-rule) rule. -pub const ViewportRule = struct { - /// The vendor prefix for this rule, e.g. `@-ms-viewport`. - vendor_prefix: css.VendorPrefix, - /// The declarations within the `@viewport` rule. - declarations: css.DeclarationBlock, - /// The location of the rule in the source file. - loc: Location, - - const This = @This(); - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // #[cfg(feature = "sourcemap")] - // dest.add_mapping(self.loc); - try dest.writeChar('@'); - try this.vendor_prefix.toCss(dest); - try dest.writeStr("viewport"); - try this.declarations.toCssBlock(dest); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const std = @import("std"); diff --git a/src/css/selectors/builder.zig b/src/css/selectors/builder.zig deleted file mode 100644 index a2e68e44b1c3..000000000000 --- a/src/css/selectors/builder.zig +++ /dev/null @@ -1,203 +0,0 @@ -//! This is the selector builder module ported from the copypasted implementation from -//! servo in lightningcss. -//! -//! -- original comment from servo -- -//! Helper module to build up a selector safely and efficiently. -//! -//! Our selector representation is designed to optimize matching, and has -//! several requirements: -//! * All simple selectors and combinators are stored inline in the same buffer -//! as Component instances. -//! * We store the top-level compound selectors from right to left, i.e. in -//! matching order. -//! * We store the simple selectors for each combinator from left to right, so -//! that we match the cheaper simple selectors first. -//! -//! Meeting all these constraints without extra memmove traffic during parsing -//! is non-trivial. This module encapsulates those details and presents an -//! easy-to-use API for the parser. - -pub const css = @import("../css_parser.zig"); - -pub const Printer = css.Printer; -pub const PrintErr = css.PrintErr; - -const parser = css.selector.parser; - -const ValidSelectorImpl = parser.ValidSelectorImpl; -const GenericComponent = parser.GenericComponent; -const Combinator = parser.Combinator; -const SpecificityAndFlags = parser.SpecificityAndFlags; -const compute_specificity = parser.compute_specificity; -const SelectorFlags = parser.SelectorFlags; - -/// Top-level SelectorBuilder struct. This should be stack-allocated by the -/// consumer and never moved (because it contains a lot of inline data that -/// would be slow to memmov). -/// -/// After instantiation, callers may call the push_simple_selector() and -/// push_combinator() methods to append selector data as it is encountered -/// (from left to right). Once the process is complete, callers should invoke -/// build(), which transforms the contents of the SelectorBuilder into a heap- -/// allocated Selector and leaves the builder in a drained state. -pub fn SelectorBuilder(comptime Impl: type) type { - ValidSelectorImpl(Impl); - - return struct { - /// The entire sequence of simple selectors, from left to right, without combinators. - /// - /// We make this large because the result of parsing a selector is fed into a new - /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also, - /// Components are large enough that we don't have much cache locality benefit - /// from reserving stack space for fewer of them. - /// - simple_selectors: css.SmallList(GenericComponent(Impl), 32) = .{}, - - /// The combinators, and the length of the compound selector to their left. - /// - combinators: css.SmallList(struct { Combinator, usize }, 32) = .{}, - - /// The length of the current compound selector. - current_len: usize = 0, - - allocator: Allocator, - - const This = @This(); - - const BuildResult = struct { - specificity_and_flags: SpecificityAndFlags, - components: ArrayList(GenericComponent(Impl)), - }; - - pub inline fn init(allocator: Allocator) This { - return This{ - .allocator = allocator, - }; - } - - /// Returns true if combinators have ever been pushed to this builder. - pub inline fn hasCombinators(this: *This) bool { - return this.combinators.len() > 0; - } - - /// Completes the current compound selector and starts a new one, delimited - /// by the given combinator. - pub inline fn pushCombinator(this: *This, combinator: Combinator) void { - this.combinators.append(this.allocator, .{ combinator, this.current_len }); - this.current_len = 0; - } - - /// Pushes a simple selector onto the current compound selector. - pub fn pushSimpleSelector(this: *This, ss: GenericComponent(Impl)) void { - bun.assert(!ss.isCombinator()); - this.simple_selectors.append(this.allocator, ss); - this.current_len += 1; - } - - pub fn addNestingPrefix(this: *This) void { - this.combinators.insert(this.allocator, 0, .{ Combinator.descendant, 1 }); - this.simple_selectors.insert(this.allocator, 0, .nesting); - } - - pub fn deinit(this: *This) void { - this.simple_selectors.deinit(this.allocator); - this.combinators.deinit(this.allocator); - } - - /// Consumes the builder, producing a Selector. - /// - /// *NOTE*: This will free all allocated memory in the builder - pub fn build( - this: *This, - parsed_pseudo: bool, - parsed_slotted: bool, - parsed_part: bool, - ) BuildResult { - const specificity = compute_specificity(Impl, this.simple_selectors.slice()); - const flags: SelectorFlags = .{ - .has_pseudo = parsed_pseudo, - .has_slotted = parsed_slotted, - .has_part = parsed_part, - }; - // `buildWithSpecificityAndFlags()` will - defer this.deinit(); - return this.buildWithSpecificityAndFlags(SpecificityAndFlags{ .specificity = specificity, .flags = flags }); - } - - /// Builds a selector with the given specificity and flags. - /// - /// PERF: - /// Recall that this code is ported from servo, which optimizes for matching speed, so - /// the final AST has the components of the selector stored in reverse order, which is - /// optimized for matching. - /// - /// We don't really care about matching selectors, and storing the components in reverse - /// order requires additional allocations, and undoing the reversal when serializing the - /// selector. So we could just change this code to store the components in the same order - /// as the source. - pub fn buildWithSpecificityAndFlags(this: *This, spec: SpecificityAndFlags) BuildResult { - const T = GenericComponent(Impl); - const rest: []const T, const current: []const T = splitFromEnd(T, this.simple_selectors.slice(), this.current_len); - const combinators = this.combinators.slice(); - defer { - // This function should take every component from `this.simple_selectors` - // and place it into `components` and return it. - // - // This means that we shouldn't leak any `GenericComponent(Impl)`, so - // it is safe to just set the length to 0. - // - // Combinators don't need to be deinitialized because they are simple enums. - this.simple_selectors.setLen(0); - this.combinators.setLen(0); - } - - var components = ArrayList(T){}; - - var current_simple_selectors_i: usize = 0; - var combinator_i: i64 = @as(i64, @intCast(this.combinators.len())) - 1; - var rest_of_simple_selectors = rest; - var current_simple_selectors = current; - - while (true) { - if (current_simple_selectors_i < current_simple_selectors.len) { - components.append( - this.allocator, - current_simple_selectors[current_simple_selectors_i], - ) catch unreachable; - current_simple_selectors_i += 1; - } else { - if (combinator_i >= 0) { - const combo: Combinator, const len: usize = combinators[@intCast(combinator_i)]; - const rest2, const current2 = splitFromEnd(GenericComponent(Impl), rest_of_simple_selectors, len); - rest_of_simple_selectors = rest2; - current_simple_selectors_i = 0; - current_simple_selectors = current2; - combinator_i -= 1; - components.append( - this.allocator, - .{ .combinator = combo }, - ) catch unreachable; - continue; - } - break; - } - } - - return .{ .specificity_and_flags = spec, .components = components }; - } - - pub fn splitFromEnd(comptime T: type, s: []const T, at: usize) struct { []const T, []const T } { - const midpoint = s.len - at; - return .{ - s[0..midpoint], - s[midpoint..], - }; - } - }; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/selectors/parser.zig b/src/css/selectors/parser.zig deleted file mode 100644 index 18f9ee38cd6a..000000000000 --- a/src/css/selectors/parser.zig +++ /dev/null @@ -1,3664 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const CSSStringFns = css.CSSStringFns; - -pub const Printer = css.Printer; -pub const PrintErr = css.PrintErr; - -const Result = css.Result; -const SmallList = css.SmallList; - -const impl = css.selector.impl; -const serialize = css.selector.serialize; - -/// Instantiation of generic selector structs using our implementation of the `SelectorImpl` trait. -pub const Component = GenericComponent(impl.Selectors); -pub const Selector = GenericSelector(impl.Selectors); -pub const SelectorList = GenericSelectorList(impl.Selectors); - -pub const ToCssCtx = enum { - lightning, - servo, -}; - -/// The definition of whitespace per CSS Selectors Level 3 § 4. -pub const SELECTOR_WHITESPACE: []const u8 = &[_]u8{ ' ', '\t', '\n', '\r', 0x0C }; - -pub fn ValidSelectorImpl(comptime T: type) void { - _ = T.SelectorImpl.ExtraMatchingData; - _ = T.SelectorImpl.AttrValue; - _ = T.SelectorImpl.Identifier; - _ = T.SelectorImpl.LocalName; - _ = T.SelectorImpl.NamespaceUrl; - _ = T.SelectorImpl.NamespacePrefix; - _ = T.SelectorImpl.BorrowedNamespaceUrl; - _ = T.SelectorImpl.BorrowedLocalName; - - _ = T.SelectorImpl.NonTSPseudoClass; - _ = T.SelectorImpl.VendorPrefix; - _ = T.SelectorImpl.PseudoElement; -} - -pub const attrs = struct { - pub fn NamespaceUrl(comptime Impl: type) type { - return struct { - prefix: Impl.SelectorImpl.NamespacePrefix, - url: Impl.SelectorImpl.NamespaceUrl, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - }; - } - - pub fn AttrSelectorWithOptionalNamespace(comptime Impl: type) type { - return struct { - namespace: ?NamespaceConstraint(NamespaceUrl(Impl)), - local_name: Impl.SelectorImpl.LocalName, - local_name_lower: Impl.SelectorImpl.LocalName, - operation: ParsedAttrSelectorOperation(Impl.SelectorImpl.AttrValue), - never_matches: bool, - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - try dest.writeChar('['); - if (this.namespace) |nsp| switch (nsp) { - .specific => |v| { - try css.IdentFns.toCss(&v.prefix, dest); - try dest.writeChar('|'); - }, - .any => { - try dest.writeStr("*|"); - }, - }; - try css.IdentFns.toCss(&this.local_name, dest); - switch (this.operation) { - .exists => {}, - .with_value => |v| { - try v.operator.toCss(dest); - // try v.expected_value.toCss(dest); - try CSSStringFns.toCss(&v.expected_value, dest); - switch (v.case_sensitivity) { - .case_sensitive, .ascii_case_insensitive_if_in_html_element_in_html_document => {}, - .ascii_case_insensitive => { - try dest.writeStr(" i"); - }, - .explicit_case_sensitive => { - try dest.writeStr(" s"); - }, - } - }, - } - return dest.writeChar(']'); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - }; - } - - pub fn NamespaceConstraint(comptime NamespaceUrl_: type) type { - return union(enum) { - any, - /// Empty string for no namespace - specific: NamespaceUrl_, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - }; - } - - pub fn ParsedAttrSelectorOperation(comptime AttrValue: type) type { - return union(enum) { - exists, - with_value: struct { - operator: AttrSelectorOperator, - case_sensitivity: ParsedCaseSensitivity, - expected_value: AttrValue, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - }; - } - - pub const AttrSelectorOperator = enum { - equal, - includes, - dash_match, - prefix, - substring, - suffix, - - const This = @This(); - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - // https://drafts.csswg.org/cssom/#serializing-selectors - // See "attribute selector". - return dest.writeStr(switch (this.*) { - .equal => "=", - .includes => "~=", - .dash_match => "|=", - .prefix => "^=", - .substring => "*=", - .suffix => "$=", - }); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - }; - - pub const AttrSelectorOperation = enum { - equal, - includes, - dash_match, - prefix, - substring, - suffix, - }; - - pub const ParsedCaseSensitivity = enum { - // 's' was specified. - explicit_case_sensitive, - // 'i' was specified. - ascii_case_insensitive, - // No flags were specified and HTML says this is a case-sensitive attribute. - case_sensitive, - // No flags were specified and HTML says this is a case-insensitive attribute. - ascii_case_insensitive_if_in_html_element_in_html_document, - }; -}; - -pub const Specificity = struct { - id_selectors: u32 = 0, - class_like_selectors: u32 = 0, - element_selectors: u32 = 0, - - const MAX_10BIT: u32 = (1 << 10) - 1; - - pub fn toU32(this: Specificity) u32 { - return @as(u32, @as(u32, @min(this.id_selectors, MAX_10BIT)) << @as(u32, 20)) | - @as(u32, @as(u32, @min(this.class_like_selectors, MAX_10BIT)) << @as(u32, 10)) | - @min(this.element_selectors, MAX_10BIT); - } - - pub fn fromU32(value: u32) Specificity { - bun.assert(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT); - return Specificity{ - .id_selectors = value >> 20, - .class_like_selectors = (value >> 10) & MAX_10BIT, - .element_selectors = value & MAX_10BIT, - }; - } - - pub fn add(lhs: *Specificity, rhs: Specificity) void { - lhs.id_selectors += rhs.id_selectors; - lhs.element_selectors += rhs.element_selectors; - lhs.class_like_selectors += rhs.class_like_selectors; - } -}; - -pub fn compute_specificity(comptime Impl: type, iter: []const GenericComponent(Impl)) u32 { - const spec = compute_complex_selector_specificity(Impl, iter); - return spec.toU32(); -} - -fn compute_complex_selector_specificity(comptime Impl: type, iter: []const GenericComponent(Impl)) Specificity { - var specificity: Specificity = .{}; - - for (iter) |*simple_selector| { - compute_simple_selector_specificity(Impl, simple_selector, &specificity); - } - - return specificity; -} - -fn compute_simple_selector_specificity( - comptime Impl: type, - simple_selector: *const GenericComponent(Impl), - specificity: *Specificity, -) void { - switch (simple_selector.*) { - .combinator => { - bun.unreachablePanic("Found combinator in simple selectors vector?", .{}); - }, - .part, .pseudo_element, .local_name => { - specificity.element_selectors += 1; - }, - .slotted => |selector| { - specificity.element_selectors += 1; - // Note that due to the way ::slotted works we only compete with - // other ::slotted rules, so the above rule doesn't really - // matter, but we do it still for consistency with other - // pseudo-elements. - // - // See: https://github.com/w3c/csswg-drafts/issues/1915 - specificity.add(Specificity.fromU32(selector.specificity())); - }, - .host => |maybe_selector| { - specificity.class_like_selectors += 1; - if (maybe_selector) |*selector| { - // See: https://github.com/w3c/csswg-drafts/issues/1915 - specificity.add(Specificity.fromU32(selector.specificity())); - } - }, - .id => { - specificity.id_selectors += 1; - }, - .class, - .attribute_in_no_namespace, - .attribute_in_no_namespace_exists, - .attribute_other, - .root, - .empty, - .scope, - .nth, - .non_ts_pseudo_class, - => { - specificity.class_like_selectors += 1; - }, - .nth_of => |nth_of_data| { - // https://drafts.csswg.org/selectors/#specificity-rules: - // - // The specificity of the :nth-last-child() pseudo-class, - // like the :nth-child() pseudo-class, combines the - // specificity of a regular pseudo-class with that of its - // selector argument S. - specificity.class_like_selectors += 1; - var max: u32 = 0; - for (nth_of_data.selectors) |*selector| { - max = @max(selector.specificity(), max); - } - specificity.add(Specificity.fromU32(max)); - }, - .negation, .is, .any => { - // https://drafts.csswg.org/selectors/#specificity-rules: - // - // The specificity of an :is() pseudo-class is replaced by the - // specificity of the most specific complex selector in its - // selector list argument. - const list: []GenericSelector(Impl) = switch (simple_selector.*) { - .negation => |list| list, - .is => |list| list, - .any => |a| a.selectors, - else => unreachable, - }; - var max: u32 = 0; - for (list) |*selector| { - max = @max(selector.specificity(), max); - } - specificity.add(Specificity.fromU32(max)); - }, - .where, - .has, - .explicit_universal_type, - .explicit_any_namespace, - .explicit_no_namespace, - .default_namespace, - .namespace, - => { - // Does not affect specificity - }, - .nesting => { - // TODO - }, - } -} - -/// Build up a Selector. -/// selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ; -/// -/// `Err` means invalid selector. -fn parse_selector( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, - nesting_requirement: NestingRequirement, -) Result(GenericSelector(Impl)) { - if (nesting_requirement == .prefixed) { - const parser_state = input.state(); - if (!input.expectDelim('&').isOk()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.missing_nesting_prefix)) }; - } - input.reset(&parser_state); - } - - // PERF: allocations here - var builder = selector_builder.SelectorBuilder(Impl){ - .allocator = input.allocator(), - }; - - outer_loop: while (true) { - // Parse a sequence of simple selectors. - const empty = switch (parse_compound_selector(Impl, parser, state, input, &builder)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (empty) { - const kind: SelectorParseErrorKind = if (builder.hasCombinators()) - .dangling_combinator - else - .empty_selector; - - return .{ .err = input.newCustomError(kind.intoDefaultParserError()) }; - } - - if (state.afterAnyPseudo()) { - const source_location = input.currentSourceLocation(); - if (input.next().asValue()) |next| { - return .{ .err = source_location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_selector_after_pseudo_element = next.* })) }; - } - break; - } - - // Parse a combinator - var combinator: Combinator = undefined; - var any_whitespace = false; - while (true) { - const before_this_token = input.state(); - const tok: *css.Token = switch (input.nextIncludingWhitespace()) { - .result => |vv| vv, - .err => break :outer_loop, - }; - switch (tok.*) { - .whitespace => { - any_whitespace = true; - continue; - }, - .delim => |d| { - switch (d) { - '>' => { - if (parser.deepCombinatorEnabled() and input.tryParse(struct { - pub fn parseFn(i: *css.Parser) Result(void) { - if (i.expectDelim('>').asErr()) |e| return .{ .err = e }; - return i.expectDelim('>'); - } - }.parseFn, .{}).isOk()) { - combinator = Combinator.deep_descendant; - } else { - combinator = Combinator.child; - } - break; - }, - '+' => { - combinator = .next_sibling; - break; - }, - '~' => { - combinator = .later_sibling; - break; - }, - '/' => { - if (parser.deepCombinatorEnabled()) { - if (input.tryParse(struct { - pub fn parseFn(i: *css.Parser) Result(void) { - if (i.expectIdentMatching("deep").asErr()) |e| return .{ .err = e }; - return i.expectDelim('/'); - } - }.parseFn, .{}).isOk()) { - combinator = .deep; - break; - } else { - break :outer_loop; - } - } - }, - else => {}, - } - }, - else => {}, - } - - input.reset(&before_this_token); - - if (any_whitespace) { - combinator = .descendant; - break; - } else { - break :outer_loop; - } - } - - if (!state.allowsCombinators()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - - builder.pushCombinator(combinator); - } - - if (!state.after_nesting) { - switch (nesting_requirement) { - .implicit => { - builder.addNestingPrefix(); - }, - .contained, .prefixed => { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.missing_nesting_selector)) }; - }, - else => {}, - } - } - - const has_pseudo_element = state.after_pseudo_element or state.after_unknown_pseudo_element; - const slotted = state.after_slotted; - const part = state.after_part; - const result = builder.build(has_pseudo_element, slotted, part); - return .{ .result = Selector{ - .specificity_and_flags = result.specificity_and_flags, - .components = result.components, - } }; -} - -/// simple_selector_sequence -/// : [ type_selector | universal ] [ HASH | class | attrib | pseudo | negation ]* -/// | [ HASH | class | attrib | pseudo | negation ]+ -/// -/// `Err(())` means invalid selector. -/// `Ok(true)` is an empty selector -fn parse_compound_selector( - comptime Impl: type, - parser: *SelectorParser, - state: *SelectorParsingState, - input: *css.Parser, - builder: *SelectorBuilder(Impl), -) Result(bool) { - input.skipWhitespace(); - - var empty: bool = true; - if (parser.isNestingAllowed() and if (input.tryParse(css.Parser.expectDelim, .{'&'}).isOk()) true else false) { - state.after_nesting = true; - builder.pushSimpleSelector(.nesting); - empty = false; - } - - if (parse_type_selector(Impl, parser, input, state.*, builder).asValue()) |_| { - empty = false; - } - - while (true) { - const result: SimpleSelectorParseResult(Impl) = result: { - const ret = switch (parse_one_simple_selector(Impl, parser, input, state)) { - .result => |r| r, - .err => |e| return .{ .err = e }, - }; - if (ret) |result| { - break :result result; - } - break; - }; - - if (empty) { - if (parser.defaultNamespace()) |url| { - // If there was no explicit type selector, but there is a - // default namespace, there is an implicit "|*" type - // selector. Except for :host() or :not() / :is() / :where(), - // where we ignore it. - // - // https://drafts.csswg.org/css-scoping/#host-element-in-tree: - // - // When considered within its own shadow trees, the shadow - // host is featureless. Only the :host, :host(), and - // :host-context() pseudo-classes are allowed to match it. - // - // https://drafts.csswg.org/selectors-4/#featureless: - // - // A featureless element does not match any selector at all, - // except those it is explicitly defined to match. If a - // given selector is allowed to match a featureless element, - // it must do so while ignoring the default namespace. - // - // https://drafts.csswg.org/selectors-4/#matches - // - // Default namespace declarations do not affect the compound - // selector representing the subject of any selector within - // a :is() pseudo-class, unless that compound selector - // contains an explicit universal selector or type selector. - // - // (Similar quotes for :where() / :not()) - // - const ignore_default_ns = state.skip_default_namespace or - (result == .simple_selector and result.simple_selector == .host); - if (!ignore_default_ns) { - builder.pushSimpleSelector(.{ .default_namespace = url }); - } - } - } - - empty = false; - - switch (result) { - .simple_selector => { - builder.pushSimpleSelector(result.simple_selector); - }, - .part_pseudo => { - const selector = result.part_pseudo; - state.after_part = true; - builder.pushCombinator(.part); - builder.pushSimpleSelector(.{ .part = selector }); - }, - .slotted_pseudo => |selector| { - state.after_slotted = true; - builder.pushCombinator(.slot_assignment); - builder.pushSimpleSelector(.{ .slotted = selector }); - }, - .pseudo_element => |p| { - if (!p.isUnknown()) { - state.after_pseudo_element = true; - builder.pushCombinator(.pseudo_element); - } else { - state.after_unknown_pseudo_element = true; - } - - if (!p.acceptsStatePseudoClasses()) { - state.after_non_stateful_pseudo_element = true; - } - - if (p.isWebkitScrollbar()) { - state.after_webkit_scrollbar = true; - } - - if (p.isViewTransition()) { - state.after_view_transition = true; - } - - builder.pushSimpleSelector(.{ .pseudo_element = p }); - }, - } - } - - return .{ .result = empty }; -} - -fn parse_relative_selector( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, - nesting_requirement_: NestingRequirement, -) Result(GenericSelector(Impl)) { - // https://www.w3.org/TR/selectors-4/#parse-relative-selector - var nesting_requirement = nesting_requirement_; - const s = input.state(); - - const combinator: ?Combinator = combinator: { - const tok = switch (input.next()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (tok.*) { - .delim => |c| { - switch (c) { - '>' => break :combinator Combinator.child, - '+' => break :combinator Combinator.next_sibling, - '~' => break :combinator Combinator.later_sibling, - else => {}, - } - }, - else => {}, - } - input.reset(&s); - break :combinator null; - }; - - const scope: GenericComponent(Impl) = if (nesting_requirement == .implicit) .nesting else .scope; - - if (combinator != null) { - nesting_requirement = .none; - } - - var selector = switch (parse_selector(Impl, parser, input, state, nesting_requirement)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (combinator) |wombo_combo| { - // https://www.w3.org/TR/selectors/#absolutizing - selector.components.append( - parser.allocator, - .{ .combinator = wombo_combo }, - ) catch unreachable; - selector.components.append( - parser.allocator, - scope, - ) catch unreachable; - } - - return .{ .result = selector }; -} - -pub fn ValidSelectorParser(comptime T: type) type { - ValidSelectorImpl(T.SelectorParser.Impl); - - // Whether to parse the `::slotted()` pseudo-element. - _ = T.SelectorParser.parseSlotted; - - _ = T.SelectorParser.parsePart; - - _ = T.SelectorParser.parseIsAndWhere; - - _ = T.SelectorParser.isAndWhereErrorRecovery; - - _ = T.SelectorParser.parseAnyPrefix; - - _ = T.SelectorParser.parseHost; - - _ = T.SelectorParser.parseNonTsPseudoClass; - - _ = T.SelectorParser.parseNonTsFunctionalPseudoClass; - - _ = T.SelectorParser.parsePseudoElement; - - _ = T.SelectorParser.parseFunctionalPseudoElement; - - _ = T.SelectorParser.defaultNamespace; - - _ = T.SelectorParser.namespaceForPrefix; - - _ = T.SelectorParser.isNestingAllowed; - - _ = T.SelectorParser.deepCombinatorEnabled; -} - -/// The [:dir()](https://drafts.csswg.org/selectors-4/#the-dir-pseudo) pseudo class. -pub const Direction = enum { - /// Left to right - ltr, - /// Right to left - rtl, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -/// A pseudo class. -pub const PseudoClass = union(enum) { - /// https://drafts.csswg.org/selectors-4/#linguistic-pseudos - /// The [:lang()](https://drafts.csswg.org/selectors-4/#the-lang-pseudo) pseudo class. - lang: struct { - /// A list of language codes. - languages: ArrayList([]const u8), - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The [:dir()](https://drafts.csswg.org/selectors-4/#the-dir-pseudo) pseudo class. - dir: struct { - /// A direction. - direction: Direction, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - - // https://drafts.csswg.org/selectors-4/#useraction-pseudos - /// The [:hover](https://drafts.csswg.org/selectors-4/#the-hover-pseudo) pseudo class. - hover, - /// The [:active](https://drafts.csswg.org/selectors-4/#the-active-pseudo) pseudo class. - active, - /// The [:focus](https://drafts.csswg.org/selectors-4/#the-focus-pseudo) pseudo class. - focus, - /// The [:focus-visible](https://drafts.csswg.org/selectors-4/#the-focus-visible-pseudo) pseudo class. - focus_visible, - /// The [:focus-within](https://drafts.csswg.org/selectors-4/#the-focus-within-pseudo) pseudo class. - focus_within, - - /// https://drafts.csswg.org/selectors-4/#time-pseudos - /// The [:current](https://drafts.csswg.org/selectors-4/#the-current-pseudo) pseudo class. - current, - /// The [:past](https://drafts.csswg.org/selectors-4/#the-past-pseudo) pseudo class. - past, - /// The [:future](https://drafts.csswg.org/selectors-4/#the-future-pseudo) pseudo class. - future, - - /// https://drafts.csswg.org/selectors-4/#resource-pseudos - /// The [:playing](https://drafts.csswg.org/selectors-4/#selectordef-playing) pseudo class. - playing, - /// The [:paused](https://drafts.csswg.org/selectors-4/#selectordef-paused) pseudo class. - paused, - /// The [:seeking](https://drafts.csswg.org/selectors-4/#selectordef-seeking) pseudo class. - seeking, - /// The [:buffering](https://drafts.csswg.org/selectors-4/#selectordef-buffering) pseudo class. - buffering, - /// The [:stalled](https://drafts.csswg.org/selectors-4/#selectordef-stalled) pseudo class. - stalled, - /// The [:muted](https://drafts.csswg.org/selectors-4/#selectordef-muted) pseudo class. - muted, - /// The [:volume-locked](https://drafts.csswg.org/selectors-4/#selectordef-volume-locked) pseudo class. - volume_locked, - - /// The [:fullscreen](https://fullscreen.spec.whatwg.org/#:fullscreen-pseudo-class) pseudo class. - fullscreen: css.VendorPrefix, - - /// https://drafts.csswg.org/selectors/#display-state-pseudos - /// The [:open](https://drafts.csswg.org/selectors/#selectordef-open) pseudo class. - open, - /// The [:closed](https://drafts.csswg.org/selectors/#selectordef-closed) pseudo class. - closed, - /// The [:modal](https://drafts.csswg.org/selectors/#modal-state) pseudo class. - modal, - /// The [:picture-in-picture](https://drafts.csswg.org/selectors/#pip-state) pseudo class. - picture_in_picture, - - /// https://html.spec.whatwg.org/multipage/semantics-other.html#selector-popover-open - /// The [:popover-open](https://html.spec.whatwg.org/multipage/semantics-other.html#selector-popover-open) pseudo class. - popover_open, - - /// The [:defined](https://drafts.csswg.org/selectors-4/#the-defined-pseudo) pseudo class. - defined, - - /// https://drafts.csswg.org/selectors-4/#location - /// The [:any-link](https://drafts.csswg.org/selectors-4/#the-any-link-pseudo) pseudo class. - any_link: css.VendorPrefix, - /// The [:link](https://drafts.csswg.org/selectors-4/#link-pseudo) pseudo class. - link, - /// The [:local-link](https://drafts.csswg.org/selectors-4/#the-local-link-pseudo) pseudo class. - local_link, - /// The [:target](https://drafts.csswg.org/selectors-4/#the-target-pseudo) pseudo class. - target, - /// The [:target-within](https://drafts.csswg.org/selectors-4/#the-target-within-pseudo) pseudo class. - target_within, - /// The [:visited](https://drafts.csswg.org/selectors-4/#visited-pseudo) pseudo class. - visited, - - /// https://drafts.csswg.org/selectors-4/#input-pseudos - /// The [:enabled](https://drafts.csswg.org/selectors-4/#enabled-pseudo) pseudo class. - enabled, - /// The [:disabled](https://drafts.csswg.org/selectors-4/#disabled-pseudo) pseudo class. - disabled, - /// The [:read-only](https://drafts.csswg.org/selectors-4/#read-only-pseudo) pseudo class. - read_only: css.VendorPrefix, - /// The [:read-write](https://drafts.csswg.org/selectors-4/#read-write-pseudo) pseudo class. - read_write: css.VendorPrefix, - /// The [:placeholder-shown](https://drafts.csswg.org/selectors-4/#placeholder) pseudo class. - placeholder_shown: css.VendorPrefix, - /// The [:default](https://drafts.csswg.org/selectors-4/#the-default-pseudo) pseudo class. - default, - /// The [:checked](https://drafts.csswg.org/selectors-4/#checked) pseudo class. - checked, - /// The [:indeterminate](https://drafts.csswg.org/selectors-4/#indeterminate) pseudo class. - indeterminate, - /// The [:blank](https://drafts.csswg.org/selectors-4/#blank) pseudo class. - blank, - /// The [:valid](https://drafts.csswg.org/selectors-4/#valid-pseudo) pseudo class. - valid, - /// The [:invalid](https://drafts.csswg.org/selectors-4/#invalid-pseudo) pseudo class. - invalid, - /// The [:in-range](https://drafts.csswg.org/selectors-4/#in-range-pseudo) pseudo class. - in_range, - /// The [:out-of-range](https://drafts.csswg.org/selectors-4/#out-of-range-pseudo) pseudo class. - out_of_range, - /// The [:required](https://drafts.csswg.org/selectors-4/#required-pseudo) pseudo class. - required, - /// The [:optional](https://drafts.csswg.org/selectors-4/#optional-pseudo) pseudo class. - optional, - /// The [:user-valid](https://drafts.csswg.org/selectors-4/#user-valid-pseudo) pseudo class. - user_valid, - /// The [:used-invalid](https://drafts.csswg.org/selectors-4/#user-invalid-pseudo) pseudo class. - user_invalid, - - /// The [:autofill](https://html.spec.whatwg.org/multipage/semantics-other.html#selector-autofill) pseudo class. - autofill: css.VendorPrefix, - - // CSS modules - /// The CSS modules :local() pseudo class. - local: struct { - /// A local selector. - selector: *Selector, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The CSS modules :global() pseudo class. - global: struct { - /// A global selector. - selector: *Selector, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - - /// A [webkit scrollbar](https://webkit.org/blog/363/styling-scrollbars/) pseudo class. - // https://webkit.org/blog/363/styling-scrollbars/ - webkit_scrollbar: WebKitScrollbarPseudoClass, - /// An unknown pseudo class. - custom: struct { - /// The pseudo class name. - name: []const u8, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// An unknown functional pseudo class. - custom_function: struct { - /// The pseudo class name. - name: []const u8, - /// The arguments of the pseudo class function. - arguments: css.TokenList, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - - pub fn isEquivalent(this: *const PseudoClass, other: *const PseudoClass) bool { - if (this.* == .fullscreen and other.* == .fullscreen) return true; - if (this.* == .any_link and other.* == .any_link) return true; - if (this.* == .read_only and other.* == .read_only) return true; - if (this.* == .read_write and other.* == .read_write) return true; - if (this.* == .placeholder_shown and other.* == .placeholder_shown) return true; - if (this.* == .autofill and other.* == .autofill) return true; - return this.eql(other); - } - - pub fn toCss(this: *const PseudoClass, dest: *Printer) PrintErr!void { - var s = std.Io.Writer.Allocating.init(dest.allocator); - // PERF(alloc): I don't like making these little allocations - const writer = &s.writer; - const scratchbuf = std.array_list.Managed(u8).init(dest.allocator); - var printer = Printer.new(dest.allocator, scratchbuf, writer, css.PrinterOptions.default(), dest.import_info, dest.local_names, dest.symbols); - try serialize.serializePseudoClass(this, &printer, null); - return dest.writeStr(s.written()); - } - - pub fn eql(lhs: *const PseudoClass, rhs: *const PseudoClass) bool { - return css.implementEql(PseudoClass, lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn getPrefix(this: *const PseudoClass) css.VendorPrefix { - return switch (this.*) { - inline .fullscreen, .any_link, .read_only, .read_write, .placeholder_shown, .autofill => |p| p, - else => css.VendorPrefix{}, - }; - } - - pub fn getNecessaryPrefixes(this: *PseudoClass, targets: css.targets.Targets) css.VendorPrefix { - const F = css.prefixes.Feature; - const p: *css.VendorPrefix, const feature: F = switch (this.*) { - .fullscreen => |*p| .{ p, F.pseudo_class_fullscreen }, - .any_link => |*p| .{ p, F.pseudo_class_any_link }, - .read_only => |*p| .{ p, F.pseudo_class_read_only }, - .read_write => |*p| .{ p, F.pseudo_class_read_write }, - .placeholder_shown => |*p| .{ p, F.pseudo_class_placeholder_shown }, - .autofill => |*p| .{ p, F.pseudo_class_autofill }, - else => return css.VendorPrefix{}, - }; - p.* = targets.prefixes(p.*, feature); - return p.*; - } - - pub fn isUserActionState(this: *const PseudoClass) bool { - return switch (this.*) { - .active, .hover, .focus, .focus_within, .focus_visible => true, - else => false, - }; - } - - pub fn isValidBeforeWebkitScrollbar(this: *const PseudoClass) bool { - return !switch (this.*) { - .webkit_scrollbar => true, - else => false, - }; - } - - pub fn isValidAfterWebkitScrollbar(this: *const PseudoClass) bool { - return switch (this.*) { - .webkit_scrollbar, .enabled, .disabled, .hover, .active => true, - else => false, - }; - } -}; - -/// A [webkit scrollbar](https://webkit.org/blog/363/styling-scrollbars/) pseudo class. -pub const WebKitScrollbarPseudoClass = enum { - /// :horizontal - horizontal, - /// :vertical - vertical, - /// :decrement - decrement, - /// :increment - increment, - /// :start - start, - /// :end - end, - /// :double-button - double_button, - /// :single-button - single_button, - /// :no-button - no_button, - /// :corner-present - corner_present, - /// :window-inactive - window_inactive, -}; - -/// A [webkit scrollbar](https://webkit.org/blog/363/styling-scrollbars/) pseudo element. -pub const WebKitScrollbarPseudoElement = enum { - /// ::-webkit-scrollbar - scrollbar, - /// ::-webkit-scrollbar-button - button, - /// ::-webkit-scrollbar-track - track, - /// ::-webkit-scrollbar-track-piece - track_piece, - /// ::-webkit-scrollbar-thumb - thumb, - /// ::-webkit-scrollbar-corner - corner, - /// ::-webkit-resizer - resizer, - - pub inline fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return lhs.* == rhs.*; - } -}; - -pub const SelectorParser = struct { - is_nesting_allowed: bool, - options: *const css.ParserOptions, - allocator: Allocator, - - pub const Impl = impl.Selectors; - - pub fn newLocalIdentifier(_: *SelectorParser, input: *css.Parser, tag: css.CssRef.Tag, raw: []const u8, loc: usize) Impl.SelectorImpl.LocalIdentifier { - if (input.flags.css_modules) { - return Impl.SelectorImpl.LocalIdentifier.fromRef(input.addSymbolForName(raw, tag, bun.logger.Loc{ - .start = @intCast(loc), - }), if (comptime bun.Environment.isDebug) .{ raw, input.allocator() } else {}); - } - return Impl.SelectorImpl.LocalIdentifier.fromIdent(.{ .v = raw }); - } - - pub fn namespaceForPrefix(this: *SelectorParser, prefix: css.css_values.ident.Ident) ?[]const u8 { - _ = this; // autofix - return prefix.v; - } - - pub fn parseFunctionalPseudoElement(this: *SelectorParser, name: []const u8, input: *css.Parser) Result(Impl.SelectorImpl.PseudoElement) { - const Enum = enum { - cue, - @"cue-region", - @"view-transition-group", - @"view-transition-image-pair", - @"view-transition-old", - @"view-transition-new", - }; - - const Map = bun.ComptimeEnumMap(Enum); - if (Map.get(name)) |v| { - return switch (v) { - .cue => .{ .result = .{ .cue_function = .{ .selector = switch (Selector.parse(this, input)) { - .result => |a| bun.create(input.allocator(), Selector, a), - .err => |e| return .{ .err = e }, - } } } }, - .@"cue-region" => .{ .result = .{ .cue_region_function = .{ .selector = switch (Selector.parse(this, input)) { - .result => |a| bun.create(input.allocator(), Selector, a), - .err => |e| return .{ .err = e }, - } } } }, - .@"view-transition-group" => .{ .result = .{ .view_transition_group = .{ .part_name = switch (ViewTransitionPartName.parse(input)) { - .result => |a| a, - .err => |e| return .{ .err = e }, - } } } }, - .@"view-transition-image-pair" => .{ .result = .{ .view_transition_image_pair = .{ .part_name = switch (ViewTransitionPartName.parse(input)) { - .result => |a| a, - .err => |e| return .{ .err = e }, - } } } }, - .@"view-transition-old" => .{ .result = .{ .view_transition_old = .{ .part_name = switch (ViewTransitionPartName.parse(input)) { - .result => |a| a, - .err => |e| return .{ .err = e }, - } } } }, - .@"view-transition-new" => .{ .result = .{ .view_transition_new = .{ .part_name = switch (ViewTransitionPartName.parse(input)) { - .result => |a| a, - .err => |e| return .{ .err = e }, - } } } }, - }; - } else { - if (!bun.strings.startsWith(name, "-")) { - this.options.warn(input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ - .unsupported_pseudo_class_or_element = name, - }))); - } - - var args = std.ArrayListUnmanaged(css.css_properties.custom.TokenOrValue){}; - if (css.TokenList.parseRaw(input, &args, this.options, 0).asErr()) |e| return .{ .err = e }; - - return .{ .result = .{ .custom_function = .{ - .name = name, - .arguments = css.TokenList{ .v = args }, - } } }; - } - } - - fn parseIsAndWhere(this: *const SelectorParser) bool { - _ = this; // autofix - return true; - } - - /// Whether the given function name is an alias for the `:is()` function. - fn parseAnyPrefix(_: *const SelectorParser, name: []const u8) ?css.VendorPrefix { - const Map = comptime bun.ComptimeStringMap(css.VendorPrefix, .{ - .{ "-webkit-any", css.VendorPrefix{ .webkit = true } }, - .{ "-moz-any", css.VendorPrefix{ .moz = true } }, - }); - - return Map.getAnyCase(name); - } - - pub fn parseNonTsPseudoClass( - this: *SelectorParser, - loc: css.SourceLocation, - name: []const u8, - ) Result(PseudoClass) { - // @compileError(css.todo_stuff.match_ignore_ascii_case); - const pseudo_class: PseudoClass = pseudo_class: { - const Map = comptime bun.ComptimeStringMap(PseudoClass, .{ - // https://drafts.csswg.org/selectors-4/#useraction-pseudos - .{ "hover", PseudoClass{ .hover = {} } }, - .{ "active", PseudoClass{ .active = {} } }, - .{ "focus", PseudoClass{ .focus = {} } }, - .{ "focus-visible", PseudoClass{ .focus_visible = {} } }, - .{ "focus-within", PseudoClass{ .focus_within = {} } }, - - // https://drafts.csswg.org/selectors-4/#time-pseudos - .{ "current", PseudoClass{ .current = {} } }, - .{ "past", PseudoClass{ .past = {} } }, - .{ "future", PseudoClass{ .future = {} } }, - - // https://drafts.csswg.org/selectors-4/#resource-pseudos - .{ "playing", PseudoClass{ .playing = {} } }, - .{ "paused", PseudoClass{ .paused = {} } }, - .{ "seeking", PseudoClass{ .seeking = {} } }, - .{ "buffering", PseudoClass{ .buffering = {} } }, - .{ "stalled", PseudoClass{ .stalled = {} } }, - .{ "muted", PseudoClass{ .muted = {} } }, - .{ "volume-locked", PseudoClass{ .volume_locked = {} } }, - - // https://fullscreen.spec.whatwg.org/#:fullscreen-pseudo-class - .{ "fullscreen", PseudoClass{ .fullscreen = css.VendorPrefix{ .none = true } } }, - .{ "-webkit-full-screen", PseudoClass{ .fullscreen = css.VendorPrefix{ .webkit = true } } }, - .{ "-moz-full-screen", PseudoClass{ .fullscreen = css.VendorPrefix{ .moz = true } } }, - .{ "-ms-fullscreen", PseudoClass{ .fullscreen = css.VendorPrefix{ .ms = true } } }, - - // https://drafts.csswg.org/selectors/#display-state-pseudos - .{ "open", PseudoClass{ .open = {} } }, - .{ "closed", PseudoClass{ .closed = {} } }, - .{ "modal", PseudoClass{ .modal = {} } }, - .{ "picture-in-picture", PseudoClass{ .picture_in_picture = {} } }, - - // https://html.spec.whatwg.org/multipage/semantics-other.html#selector-popover-open - .{ "popover-open", PseudoClass{ .popover_open = {} } }, - - // https://drafts.csswg.org/selectors-4/#the-defined-pseudo - .{ "defined", PseudoClass{ .defined = {} } }, - - // https://drafts.csswg.org/selectors-4/#location - .{ "any-link", PseudoClass{ .any_link = css.VendorPrefix{ .none = true } } }, - .{ "-webkit-any-link", PseudoClass{ .any_link = css.VendorPrefix{ .webkit = true } } }, - .{ "-moz-any-link", PseudoClass{ .any_link = css.VendorPrefix{ .moz = true } } }, - .{ "link", PseudoClass{ .link = {} } }, - .{ "local-link", PseudoClass{ .local_link = {} } }, - .{ "target", PseudoClass{ .target = {} } }, - .{ "target-within", PseudoClass{ .target_within = {} } }, - .{ "visited", PseudoClass{ .visited = {} } }, - - // https://drafts.csswg.org/selectors-4/#input-pseudos - .{ "enabled", PseudoClass{ .enabled = {} } }, - .{ "disabled", PseudoClass{ .disabled = {} } }, - .{ "read-only", PseudoClass{ .read_only = css.VendorPrefix{ .none = true } } }, - .{ "-moz-read-only", PseudoClass{ .read_only = css.VendorPrefix{ .moz = true } } }, - .{ "read-write", PseudoClass{ .read_write = css.VendorPrefix{ .none = true } } }, - .{ "-moz-read-write", PseudoClass{ .read_write = css.VendorPrefix{ .moz = true } } }, - .{ "placeholder-shown", PseudoClass{ .placeholder_shown = css.VendorPrefix{ .none = true } } }, - .{ "-moz-placeholder-shown", PseudoClass{ .placeholder_shown = css.VendorPrefix{ .moz = true } } }, - .{ "-ms-placeholder-shown", PseudoClass{ .placeholder_shown = css.VendorPrefix{ .ms = true } } }, - .{ "default", PseudoClass{ .default = {} } }, - .{ "checked", PseudoClass{ .checked = {} } }, - .{ "indeterminate", PseudoClass{ .indeterminate = {} } }, - .{ "blank", PseudoClass{ .blank = {} } }, - .{ "valid", PseudoClass{ .valid = {} } }, - .{ "invalid", PseudoClass{ .invalid = {} } }, - .{ "in-range", PseudoClass{ .in_range = {} } }, - .{ "out-of-range", PseudoClass{ .out_of_range = {} } }, - .{ "required", PseudoClass{ .required = {} } }, - .{ "optional", PseudoClass{ .optional = {} } }, - .{ "user-valid", PseudoClass{ .user_valid = {} } }, - .{ "user-invalid", PseudoClass{ .user_invalid = {} } }, - - // https://html.spec.whatwg.org/multipage/semantics-other.html#selector-autofill - .{ "autofill", PseudoClass{ .autofill = css.VendorPrefix{ .none = true } } }, - .{ "-webkit-autofill", PseudoClass{ .autofill = css.VendorPrefix{ .webkit = true } } }, - .{ "-o-autofill", PseudoClass{ .autofill = css.VendorPrefix{ .o = true } } }, - - // https://webkit.org/blog/363/styling-scrollbars/ - .{ "horizontal", PseudoClass{ .webkit_scrollbar = .horizontal } }, - .{ "vertical", PseudoClass{ .webkit_scrollbar = .vertical } }, - .{ "decrement", PseudoClass{ .webkit_scrollbar = .decrement } }, - .{ "increment", PseudoClass{ .webkit_scrollbar = .increment } }, - .{ "start", PseudoClass{ .webkit_scrollbar = .start } }, - .{ "end", PseudoClass{ .webkit_scrollbar = .end } }, - .{ "double-button", PseudoClass{ .webkit_scrollbar = .double_button } }, - .{ "single-button", PseudoClass{ .webkit_scrollbar = .single_button } }, - .{ "no-button", PseudoClass{ .webkit_scrollbar = .no_button } }, - .{ "corner-present", PseudoClass{ .webkit_scrollbar = .corner_present } }, - .{ "window-inactive", PseudoClass{ .webkit_scrollbar = .window_inactive } }, - }); - - if (Map.getAnyCase(name)) |pseudo| { - break :pseudo_class pseudo; - } else { - if (bun.strings.startsWithChar(name, '_')) { - this.options.warn(loc.newCustomError(SelectorParseErrorKind{ .unsupported_pseudo_class_or_element = name })); - } else if (this.options.css_modules != null and bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "local") or bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "global")) { - return .{ .err = loc.newCustomError(SelectorParseErrorKind{ .ambiguous_css_module_class = name }) }; - } - return .{ .result = PseudoClass{ .custom = .{ .name = name } } }; - } - }; - - return .{ .result = pseudo_class }; - } - - pub fn parseHost(_: *SelectorParser) bool { - return true; - } - - pub fn parseNonTsFunctionalPseudoClass( - this: *SelectorParser, - name: []const u8, - parser: *css.Parser, - ) Result(PseudoClass) { - - // todo_stuff.match_ignore_ascii_case - const pseudo_class = pseudo_class: { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "lang")) { - const languages = switch (parser.parseCommaSeparated([]const u8, css.Parser.expectIdentOrString)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = PseudoClass{ - .lang = .{ .languages = languages }, - } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "dir")) { - break :pseudo_class PseudoClass{ - .dir = .{ - .direction = switch (Direction.parse(parser)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - }, - }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "local") and this.options.css_modules != null) { - break :pseudo_class PseudoClass{ - .local = .{ - .selector = brk: { - const selector = switch (Selector.parse(this, parser)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - break :brk bun.create(this.allocator, Selector, selector); - }, - }, - }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "global") and this.options.css_modules != null) { - break :pseudo_class PseudoClass{ - .global = .{ - .selector = brk: { - const selector = switch (Selector.parse(this, parser)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - break :brk bun.create(this.allocator, Selector, selector); - }, - }, - }; - } else { - if (!bun.strings.startsWithChar(name, '-')) { - this.options.warn(parser.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unsupported_pseudo_class_or_element = name }))); - } - var args = ArrayList(css.css_properties.custom.TokenOrValue){}; - _ = switch (css.TokenListFns.parseRaw(parser, &args, this.options, 0)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - break :pseudo_class PseudoClass{ - .custom_function = .{ - .name = name, - .arguments = css.TokenList{ .v = args }, - }, - }; - } - }; - - return .{ .result = pseudo_class }; - } - - pub fn isNestingAllowed(this: *SelectorParser) bool { - return this.is_nesting_allowed; - } - - pub fn deepCombinatorEnabled(this: *SelectorParser) bool { - return this.options.flags.deep_selector_combinator; - } - - pub fn defaultNamespace(this: *SelectorParser) ?impl.Selectors.SelectorImpl.NamespaceUrl { - _ = this; // autofix - return null; - } - - pub fn parsePart(this: *SelectorParser) bool { - _ = this; // autofix - return true; - } - - pub fn parseSlotted(this: *SelectorParser) bool { - _ = this; // autofix - return true; - } - - /// The error recovery that selector lists inside :is() and :where() have. - fn isAndWhereErrorRecovery(this: *SelectorParser) ParseErrorRecovery { - _ = this; // autofix - return .ignore_invalid_selector; - } - - pub fn parsePseudoElement(this: *SelectorParser, loc: css.SourceLocation, name: []const u8) Result(PseudoElement) { - const Map = comptime bun.ComptimeStringMap(PseudoElement, .{ - .{ "before", PseudoElement.before }, - .{ "after", PseudoElement.after }, - .{ "first-line", PseudoElement.first_line }, - .{ "first-letter", PseudoElement.first_letter }, - .{ "cue", PseudoElement.cue }, - .{ "cue-region", PseudoElement.cue_region }, - .{ "selection", PseudoElement{ .selection = css.VendorPrefix{ .none = true } } }, - .{ "-moz-selection", PseudoElement{ .selection = css.VendorPrefix{ .moz = true } } }, - .{ "placeholder", PseudoElement{ .placeholder = css.VendorPrefix{ .none = true } } }, - .{ "-webkit-input-placeholder", PseudoElement{ .placeholder = css.VendorPrefix{ .webkit = true } } }, - .{ "-moz-placeholder", PseudoElement{ .placeholder = css.VendorPrefix{ .moz = true } } }, - .{ "-ms-input-placeholder", PseudoElement{ .placeholder = css.VendorPrefix{ .ms = true } } }, - .{ "marker", PseudoElement.marker }, - .{ "backdrop", PseudoElement{ .backdrop = css.VendorPrefix{ .none = true } } }, - .{ "-webkit-backdrop", PseudoElement{ .backdrop = css.VendorPrefix{ .webkit = true } } }, - .{ "file-selector-button", PseudoElement{ .file_selector_button = css.VendorPrefix{ .none = true } } }, - .{ "-webkit-file-upload-button", PseudoElement{ .file_selector_button = css.VendorPrefix{ .webkit = true } } }, - .{ "-ms-browse", PseudoElement{ .file_selector_button = css.VendorPrefix{ .ms = true } } }, - .{ "-webkit-scrollbar", PseudoElement{ .webkit_scrollbar = .scrollbar } }, - .{ "-webkit-scrollbar-button", PseudoElement{ .webkit_scrollbar = .button } }, - .{ "-webkit-scrollbar-track", PseudoElement{ .webkit_scrollbar = .track } }, - .{ "-webkit-scrollbar-track-piece", PseudoElement{ .webkit_scrollbar = .track_piece } }, - .{ "-webkit-scrollbar-thumb", PseudoElement{ .webkit_scrollbar = .thumb } }, - .{ "-webkit-scrollbar-corner", PseudoElement{ .webkit_scrollbar = .corner } }, - .{ "-webkit-resizer", PseudoElement{ .webkit_scrollbar = .resizer } }, - .{ "view-transition", PseudoElement.view_transition }, - }); - - const pseudo_element = Map.getCaseInsensitiveWithEql(name, bun.strings.eqlComptimeIgnoreLen) orelse brk: { - if (!bun.strings.startsWithChar(name, '-')) { - this.options.warn(loc.newCustomError(SelectorParseErrorKind{ .unsupported_pseudo_class_or_element = name })); - } - break :brk PseudoElement{ .custom = .{ .name = name } }; - }; - - return .{ .result = pseudo_element }; - } -}; - -pub fn GenericSelectorList(comptime Impl: type) type { - ValidSelectorImpl(Impl); - - const SelectorT = GenericSelector(Impl); - return struct { - // PERF: make this equivalent to SmallVec<[Selector; 1]> - v: css.SmallList(SelectorT, 1) = .{}, - - const This = @This(); - - const DebugFmt = struct { - this: *const This, - - pub fn format(this: @This(), writer: *std.Io.Writer) std.Io.Writer.Error!void { - if (comptime !bun.Environment.isDebug) return; - try writer.print("SelectorList[\n", .{}); - const last = this.this.v.len() -| 1; - for (this.this.v.slice(), 0..) |*sel, i| { - if (i != last) { - try writer.print(" {f}\n", .{sel.debug()}); - } else { - try writer.print(" {f},\n", .{sel.debug()}); - } - } - try writer.print("]\n", .{}); - } - }; - - pub fn debug(this: *const @This()) DebugFmt { - return DebugFmt{ .this = this }; - } - - pub fn anyHasPseudoElement(this: *const This) bool { - for (this.v.slice()) |*sel| { - if (sel.hasPseudoElement()) return true; - } - return false; - } - - pub fn specifitiesAllEqual(this: *const This) bool { - if (this.v.len() == 0) return true; - if (this.v.len() == 1) return true; - - const value = this.v.at(0).specificity(); - for (this.v.slice()[1..]) |*sel| { - if (sel.specificity() != value) return false; - } - return true; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - _ = this; // autofix - _ = dest; // autofix - @compileError("Do not call this! Use `serializer.serializeSelectorList()` or `tocss_servo.toCss_SelectorList()` instead."); - } - - pub fn parseWithOptions(input: *css.Parser, options: *const css.ParserOptions) Result(This) { - var parser = SelectorParser{ - .options = options, - .is_nesting_allowed = true, - }; - return parse(&parser, input, .discard_list, .none); - } - - pub fn parse( - parser: *SelectorParser, - input: *css.Parser, - error_recovery: ParseErrorRecovery, - nesting_requirement: NestingRequirement, - ) Result(This) { - var state = SelectorParsingState{}; - return parseWithState(parser, input, &state, error_recovery, nesting_requirement); - } - - pub fn parseRelative( - parser: *SelectorParser, - input: *css.Parser, - error_recovery: ParseErrorRecovery, - nesting_requirement: NestingRequirement, - ) Result(This) { - var state = SelectorParsingState{}; - return parseRelativeWithState(parser, input, &state, error_recovery, nesting_requirement); - } - - pub fn parseWithState( - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, - recovery: ParseErrorRecovery, - nesting_requirement: NestingRequirement, - ) Result(This) { - const original_state = state.*; - // TODO: Think about deinitialization in error cases - var values = SmallList(SelectorT, 1){}; - - while (true) { - const Closure = struct { - outer_state: *SelectorParsingState, - original_state: SelectorParsingState, - nesting_requirement: NestingRequirement, - parser: *SelectorParser, - - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(SelectorT) { - var selector_state = this.original_state; - const result = parse_selector(Impl, this.parser, input2, &selector_state, this.nesting_requirement); - if (selector_state.after_nesting) { - this.outer_state.after_nesting = true; - } - return result; - } - }; - var closure = Closure{ - .outer_state = state, - .original_state = original_state, - .nesting_requirement = nesting_requirement, - .parser = parser, - }; - const selector = input.parseUntilBefore(css.Delimiters{ .comma = true }, SelectorT, &closure, Closure.parsefn); - - const was_ok = selector.isOk(); - switch (selector) { - .result => |sel| { - values.append(input.allocator(), sel); - }, - .err => |e| { - switch (recovery) { - .discard_list => return .{ .err = e }, - .ignore_invalid_selector => {}, - } - }, - } - - while (true) { - if (input.next().asValue()) |tok| { - if (tok.* == .comma) break; - // Shouldn't have got a selector if getting here. - bun.debugAssert(!was_ok); - } - return .{ .result = .{ .v = values } }; - } - } - } - - // TODO: this looks exactly the same as `parseWithState()` except it uses `parse_relative_selector()` instead of `parse_selector()` - pub fn parseRelativeWithState( - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, - recovery: ParseErrorRecovery, - nesting_requirement: NestingRequirement, - ) Result(This) { - const original_state = state.*; - // TODO: Think about deinitialization in error cases - var values = SmallList(SelectorT, 1){}; - - while (true) { - const Closure = struct { - outer_state: *SelectorParsingState, - original_state: SelectorParsingState, - nesting_requirement: NestingRequirement, - parser: *SelectorParser, - - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(SelectorT) { - var selector_state = this.original_state; - const result = parse_relative_selector(Impl, this.parser, input2, &selector_state, this.nesting_requirement); - if (selector_state.after_nesting) { - this.outer_state.after_nesting = true; - } - return result; - } - }; - var closure = Closure{ - .outer_state = state, - .original_state = original_state, - .nesting_requirement = nesting_requirement, - .parser = parser, - }; - const selector = input.parseUntilBefore(css.Delimiters{ .comma = true }, SelectorT, &closure, Closure.parsefn); - - const was_ok = selector.isOk(); - switch (selector) { - .result => |sel| { - values.append(input.allocator(), sel); - }, - .err => |e| { - switch (recovery) { - .discard_list => return .{ .err = e }, - .ignore_invalid_selector => {}, - } - }, - } - - while (true) { - if (input.next().asValue()) |tok| { - if (tok.* == .comma) break; - // Shouldn't have got a selector if getting here. - bun.debugAssert(!was_ok); - } - return .{ .result = .{ .v = values } }; - } - } - } - - pub fn fromSelector(allocator: Allocator, selector: GenericSelector(Impl)) This { - var result = This{}; - result.v.append(allocator, selector); - return result; - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) This { - return .{ .v = this.v.deepClone(allocator) }; - } - - pub fn eql(lhs: *const This, rhs: *const This) bool { - return lhs.v.eql(&rhs.v); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - }; -} - -/// -- original comment from servo -- -/// A Selector stores a sequence of simple selectors and combinators. The -/// iterator classes allow callers to iterate at either the raw sequence level or -/// at the level of sequences of simple selectors separated by combinators. Most -/// callers want the higher-level iterator. -/// -/// We store compound selectors internally right-to-left (in matching order). -/// Additionally, we invert the order of top-level compound selectors so that -/// each one matches left-to-right. This is because matching namespace, local name, -/// id, and class are all relatively cheap, whereas matching pseudo-classes might -/// be expensive (depending on the pseudo-class). Since authors tend to put the -/// pseudo-classes on the right, it's faster to start matching on the left. -/// -/// This reordering doesn't change the semantics of selector matching, and we -/// handle it in to_css to make it invisible to serialization. -pub fn GenericSelector(comptime Impl: type) type { - ValidSelectorImpl(Impl); - - return struct { - specificity_and_flags: SpecificityAndFlags, - components: ArrayList(GenericComponent(Impl)), - - const This = @This(); - - const DebugFmt = struct { - this: *const This, - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - if (comptime !bun.Environment.isDebug) return; - try writer.print("Selector(", .{}); - var arraylist = std.Io.Writer.Allocating.init(bun.default_allocator); - const w = &arraylist.writer; - defer arraylist.deinit(); - const symbols = bun.ast.Symbol.Map{}; - const P = css.Printer; - var printer = P.new(bun.default_allocator, std.array_list.Managed(u8).init(bun.default_allocator), w, css.PrinterOptions.default(), null, null, &symbols); - defer printer.deinit(); - P.in_debug_fmt = true; - defer P.in_debug_fmt = false; - - css.selector.tocss_servo.toCss_Selector(this.this, &printer) catch |e| return try writer.print("\n", .{@errorName(e)}); - try writer.writeAll(arraylist.written()); - } - }; - - pub fn debug(this: *const This) DebugFmt { - return DebugFmt{ .this = this }; - } - - /// Parse a selector, without any pseudo-element. - pub fn parse(parser: *SelectorParser, input: *css.Parser) Result(This) { - var state = SelectorParsingState{}; - return parse_selector(Impl, parser, input, &state, .none); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - _ = this; // autofix - _ = dest; // autofix - @compileError("Do not call this! Use `serializer.serializeSelector()` or `tocss_servo.toCss_Selector()` instead."); - } - - pub fn append(this: *This, allocator: Allocator, component: GenericComponent(Impl)) void { - const index = index: { - for (this.components.items, 0..) |*comp, i| { - switch (comp.*) { - .combinator, .pseudo_element => break :index i, - else => {}, - } - } - break :index this.components.items.len; - }; - bun.handleOom(this.components.insert(allocator, index, component)); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) This { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const This, other: *const This) bool { - return css.implementEql(This, this, other); - } - - pub fn hasCombinator(this: *const This) bool { - for (this.components.items) |*c| { - if (c.* == .combinator and c.combinator.isTreeCombinator()) return true; - } - return false; - } - - pub fn hasPseudoElement(this: *const This) bool { - return this.specificity_and_flags.hasPseudoElement(); - } - - /// Returns count of simple selectors and combinators in the Selector. - pub fn len(this: *const This) usize { - return this.components.items.len; - } - - pub fn fromComponent(allocator: Allocator, component: GenericComponent(Impl)) This { - var builder = SelectorBuilder(Impl).init(allocator); - if (component.asCombinator()) |combinator| { - builder.pushCombinator(combinator); - } else { - builder.pushSimpleSelector(component); - } - const result = builder.build(false, false, false); - return This{ - .specificity_and_flags = result.specificity_and_flags, - .components = result.components, - }; - } - - pub fn specificity(this: *const This) u32 { - return this.specificity_and_flags.specificity; - } - - pub fn parseWithOptions(input: *css.Parser, options: *const css.ParserOptions) Result(This) { - var selector_parser = SelectorParser{ - .is_nesting_allowed = true, - .options = options, - }; - return parse(&selector_parser, input); - } - - pub fn iterRawMatchOrder(this: *const This) RawMatchOrderIterator { - return RawMatchOrderIterator{ - .slice = this.components.items, - }; - } - - const RawMatchOrderIterator = struct { - slice: []const GenericComponent(Impl), - i: usize = 0, - - pub fn next(this: *@This()) ?GenericComponent(Impl) { - if (this.i >= this.slice.len) return null; - const result = this.slice[this.i]; - this.i += 1; - return result; - } - }; - - /// Returns an iterator over the sequence of simple selectors and - /// combinators, in parse order (from left to right), starting from - /// `offset`. - pub fn iterRawParseOrderFrom(this: *const This, offset: usize) RawParseOrderFromIter { - return RawParseOrderFromIter{ - .slice = this.components.items[0 .. this.components.items.len - offset], - }; - } - - const RawParseOrderFromIter = struct { - slice: []const GenericComponent(Impl), - i: usize = 0, - - pub fn next(this: *@This()) ?GenericComponent(Impl) { - if (!(this.i < this.slice.len)) return null; - const result = this.slice[this.slice.len - 1 - this.i]; - this.i += 1; - return result; - } - }; - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - }; -} - -/// A CSS simple selector or combinator. We store both in the same enum for -/// optimal packing and cache performance, see [1]. -/// -/// [1] https://bugzilla.mozilla.org/show_bug.cgi?id=1357973 -pub fn GenericComponent(comptime Impl: type) type { - ValidSelectorImpl(Impl); - - return union(enum) { - combinator: Combinator, - - explicit_any_namespace, - explicit_no_namespace, - default_namespace: Impl.SelectorImpl.NamespaceUrl, - namespace: struct { - prefix: Impl.SelectorImpl.NamespacePrefix, - url: Impl.SelectorImpl.NamespaceUrl, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - - explicit_universal_type, - local_name: LocalName(Impl), - - id: Impl.SelectorImpl.LocalIdentifier, - class: Impl.SelectorImpl.LocalIdentifier, - - attribute_in_no_namespace_exists: struct { - local_name: Impl.SelectorImpl.LocalName, - local_name_lower: Impl.SelectorImpl.LocalName, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// Used only when local_name is already lowercase. - attribute_in_no_namespace: struct { - local_name: Impl.SelectorImpl.LocalName, - operator: attrs.AttrSelectorOperator, - value: Impl.SelectorImpl.AttrValue, - case_sensitivity: attrs.ParsedCaseSensitivity, - never_matches: bool, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// Use a Box in the less common cases with more data to keep size_of::() small. - attribute_other: *attrs.AttrSelectorWithOptionalNamespace(Impl), - - /// Pseudo-classes - negation: []GenericSelector(Impl), - root, - empty, - scope, - nth: NthSelectorData, - nth_of: NthOfSelectorData(Impl), - non_ts_pseudo_class: Impl.SelectorImpl.NonTSPseudoClass, - /// The ::slotted() pseudo-element: - /// - /// https://drafts.csswg.org/css-scoping/#slotted-pseudo - /// - /// The selector here is a compound selector, that is, no combinators. - /// - /// NOTE(emilio): This should support a list of selectors, but as of this - /// writing no other browser does, and that allows them to put ::slotted() - /// in the rule hash, so we do that too. - /// - /// See https://github.com/w3c/csswg-drafts/issues/2158 - slotted: GenericSelector(Impl), - /// The `::part` pseudo-element. - /// https://drafts.csswg.org/css-shadow-parts/#part - part: []Impl.SelectorImpl.Identifier, - /// The `:host` pseudo-class: - /// - /// https://drafts.csswg.org/css-scoping/#host-selector - /// - /// NOTE(emilio): This should support a list of selectors, but as of this - /// writing no other browser does, and that allows them to put :host() - /// in the rule hash, so we do that too. - /// - /// See https://github.com/w3c/csswg-drafts/issues/2158 - host: ?GenericSelector(Impl), - /// The `:where` pseudo-class. - /// - /// https://drafts.csswg.org/selectors/#zero-matches - /// - /// The inner argument is conceptually a SelectorList, but we move the - /// selectors to the heap to keep Component small. - where: []GenericSelector(Impl), - /// The `:is` pseudo-class. - /// - /// https://drafts.csswg.org/selectors/#matches-pseudo - /// - /// Same comment as above re. the argument. - is: []GenericSelector(Impl), - any: struct { - vendor_prefix: Impl.SelectorImpl.VendorPrefix, - selectors: []GenericSelector(Impl), - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The `:has` pseudo-class. - /// - /// https://www.w3.org/TR/selectors/#relational - has: []GenericSelector(Impl), - /// An implementation-dependent pseudo-element selector. - pseudo_element: Impl.SelectorImpl.PseudoElement, - /// A nesting selector: - /// - /// https://drafts.csswg.org/css-nesting-1/#nest-selector - /// - /// NOTE: This is a lightningcss addition. - nesting, - - const This = @This(); - - /// If css mdules is enabled these will be locally scoped - pub fn isLocallyScoped(this: *const @This()) bool { - return switch (this.*) { - .id, .class => true, - else => false, - }; - } - - pub fn asClass(this: *const @This()) ?Impl.SelectorImpl.LocalIdentifier { - return switch (this.*) { - inline .class => |v| v, - else => null, - }; - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const This, rhs: *const This) bool { - return css.implementEql(This, lhs, rhs); - } - - pub fn format(this: *const This, writer: *std.Io.Writer) !void { - switch (this.*) { - .local_name => return try writer.print("local_name={s}", .{this.local_name.name.v}), - .combinator => return try writer.print("combinator='{f}'", .{this.combinator}), - .pseudo_element => return try writer.print("pseudo_element={f}", .{this.pseudo_element}), - .class => return try writer.print("class={f}", .{this.class}), - else => {}, - } - return writer.print("{s}", .{@tagName(this.*)}); - } - - pub fn asCombinator(this: *const This) ?Combinator { - if (this.* == .combinator) return this.combinator; - return null; - } - - pub fn convertHelper_is(s: []GenericSelector(Impl)) This { - return .{ .is = s }; - } - - pub fn convertHelper_where(s: []GenericSelector(Impl)) This { - return .{ .where = s }; - } - - pub fn convertHelper_any(s: []GenericSelector(Impl), prefix: Impl.SelectorImpl.VendorPrefix) This { - return .{ - .any = .{ - .vendor_prefix = prefix, - .selectors = s, - }, - }; - } - - /// Returns true if this is a combinator. - pub fn isCombinator(this: *const This) bool { - return this.* == .combinator; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - _ = this; // autofix - _ = dest; // autofix - @compileError("Do not call this! Use `serializer.serializeComponent()` or `tocss_servo.toCss_Component()` instead."); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - }; -} - -/// The properties that comprise an :nth- pseudoclass as of Selectors 3 (e.g., -/// nth-child(An+B)). -/// https://www.w3.org/TR/selectors-3/#nth-child-pseudo -pub const NthSelectorData = struct { - ty: NthType, - is_function: bool, - a: i32, - b: i32, - - /// Returns selector data for :only-{child,of-type} - pub fn only(of_type: bool) NthSelectorData { - return NthSelectorData{ - .ty = if (of_type) NthType.only_of_type else NthType.only_child, - .is_function = false, - .a = 0, - .b = 1, - }; - } - - /// Returns selector data for :first-{child,of-type} - pub fn first(of_type: bool) NthSelectorData { - return NthSelectorData{ - .ty = if (of_type) NthType.of_type else NthType.child, - .is_function = false, - .a = 0, - .b = 1, - }; - } - - /// Returns selector data for :last-{child,of-type} - pub fn last(of_type: bool) NthSelectorData { - return NthSelectorData{ - .ty = if (of_type) NthType.last_of_type else NthType.last_child, - .is_function = false, - .a = 0, - .b = 1, - }; - } - - pub fn writeStart(this: *const @This(), dest: *Printer, is_function: bool) PrintErr!void { - try dest.writeStr(switch (this.ty) { - .child => if (is_function) ":nth-child(" else ":first-child", - .last_child => if (is_function) ":nth-last-child(" else ":last-child", - .of_type => if (is_function) ":nth-of-type(" else ":first-of-type", - .last_of_type => if (is_function) ":nth-last-of-type(" else ":last-of-type", - .only_child => ":only-child", - .only_of_type => ":only-of-type", - .col => ":nth-col(", - .last_col => ":nth-last-col(", - }); - } - - pub fn isFunction(this: *const @This()) bool { - return this.a != 0 or this.b != 1; - } - - fn numberSign(num: i32) []const u8 { - if (num >= 0) return "+"; - return ""; - } - - pub fn writeAffine(this: *const @This(), dest: *Printer) PrintErr!void { - // PERF: this could be made faster - if (this.a == 0 and this.b == 0) { - try dest.writeChar('0'); - } else if (this.a == 1 and this.b == 0) { - try dest.writeChar('n'); - } else if (this.a == -1 and this.b == 0) { - try dest.writeStr("-n"); - } else if (this.b == 0) { - try dest.writeFmt("{d}n", .{this.a}); - } else if (this.a == 2 and this.b == 1) { - try dest.writeStr("odd"); - } else if (this.a == 0) { - try dest.writeFmt("{d}", .{this.b}); - } else if (this.a == 1) { - try dest.writeFmt("n{s}{d}", .{ numberSign(this.b), this.b }); - } else if (this.a == -1) { - try dest.writeFmt("-n{s}{d}", .{ numberSign(this.b), this.b }); - } else { - try dest.writeFmt("{}n{s}{d}", .{ this.a, numberSign(this.b), this.b }); - } - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// The properties that comprise an :nth- pseudoclass as of Selectors 4 (e.g., -/// nth-child(An+B [of S]?)). -/// https://www.w3.org/TR/selectors-4/#nth-child-pseudo -pub fn NthOfSelectorData(comptime Impl: type) type { - return struct { - data: NthSelectorData, - selectors: []GenericSelector(Impl), - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn nthData(this: *const @This()) NthSelectorData { - return this.data; - } - }; -} - -pub const SelectorParsingState = packed struct(u16) { - /// Whether we should avoid adding default namespaces to selectors that - /// aren't type or universal selectors. - skip_default_namespace: bool = false, - - /// Whether we've parsed a ::slotted() pseudo-element already. - /// - /// If so, then we can only parse a subset of pseudo-elements, and - /// whatever comes after them if so. - after_slotted: bool = false, - - /// Whether we've parsed a ::part() pseudo-element already. - /// - /// If so, then we can only parse a subset of pseudo-elements, and - /// whatever comes after them if so. - after_part: bool = false, - - /// Whether we've parsed a pseudo-element (as in, an - /// `Impl::PseudoElement` thus not accounting for `::slotted` or - /// `::part`) already. - /// - /// If so, then other pseudo-elements and most other selectors are - /// disallowed. - after_pseudo_element: bool = false, - - /// Whether we've parsed a non-stateful pseudo-element (again, as-in - /// `Impl::PseudoElement`) already. If so, then other pseudo-classes are - /// disallowed. If this flag is set, `AFTER_PSEUDO_ELEMENT` must be set - /// as well. - after_non_stateful_pseudo_element: bool = false, - - /// Whether we explicitly disallow combinators. - disallow_combinators: bool = false, - - /// Whether we explicitly disallow pseudo-element-like things. - disallow_pseudos: bool = false, - - /// Whether we have seen a nesting selector. - after_nesting: bool = false, - - after_webkit_scrollbar: bool = false, - after_view_transition: bool = false, - after_unknown_pseudo_element: bool = false, - __unused: u5 = 0, - - /// Whether we are after any of the pseudo-like things. - pub fn afterAnyPseudo(state: SelectorParsingState) bool { - return state.after_part or state.after_slotted or state.after_pseudo_element; - } - - pub fn allowsPseudos(this: SelectorParsingState) bool { - return !this.after_pseudo_element and !this.disallow_pseudos; - } - - pub fn allowsPart(this: SelectorParsingState) bool { - return !this.disallow_pseudos and !this.afterAnyPseudo(); - } - - pub fn allowsSlotted(this: SelectorParsingState) bool { - return this.allowsPart(); - } - - pub fn allowsTreeStructuralPseudoClasses(this: SelectorParsingState) bool { - return !this.afterAnyPseudo(); - } - - pub fn allowsNonFunctionalPseudoClasses(this: SelectorParsingState) bool { - return !this.after_slotted and !this.after_non_stateful_pseudo_element; - } - - pub fn allowsCombinators(this: SelectorParsingState) bool { - return !this.disallow_combinators; - } - - pub fn allowsCustomFunctionalPseudoClasses(this: SelectorParsingState) bool { - return !this.afterAnyPseudo(); - } -}; - -pub const SpecificityAndFlags = struct { - /// There are two free bits here, since we use ten bits for each specificity - /// kind (id, class, element). - specificity: u32, - /// There's padding after this field due to the size of the flags. - flags: SelectorFlags, - - pub fn eql(this: *const SpecificityAndFlags, other: *const SpecificityAndFlags) bool { - return css.implementEql(@This(), this, other); - } - - pub fn hasPseudoElement(this: *const SpecificityAndFlags) bool { - return this.flags.has_pseudo; - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub const SelectorFlags = packed struct(u8) { - has_pseudo: bool = false, - has_slotted: bool = false, - has_part: bool = false, - __unused: u5 = 0, -}; - -/// How to treat invalid selectors in a selector list. -pub const ParseErrorRecovery = enum { - /// Discard the entire selector list, this is the default behavior for - /// almost all of CSS. - discard_list, - /// Ignore invalid selectors, potentially creating an empty selector list. - /// - /// This is the error recovery mode of :is() and :where() - ignore_invalid_selector, -}; - -pub const NestingRequirement = enum { - none, - prefixed, - contained, - implicit, -}; - -pub const Combinator = enum { - child, // > - descendant, // space - next_sibling, // + - later_sibling, // ~ - /// A dummy combinator we use to the left of pseudo-elements. - /// - /// It serializes as the empty string, and acts effectively as a child - /// combinator in most cases. If we ever actually start using a child - /// combinator for this, we will need to fix up the way hashes are computed - /// for revalidation selectors. - pseudo_element, - /// Another combinator used for ::slotted(), which represent the jump from - /// a node to its assigned slot. - slot_assignment, - - /// Another combinator used for `::part()`, which represents the jump from - /// the part to the containing shadow host. - part, - - /// Non-standard Vue >>> combinator. - /// https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors - deep_descendant, - /// Non-standard /deep/ combinator. - /// Appeared in early versions of the css-scoping-1 specification: - /// https://www.w3.org/TR/2014/WD-css-scoping-1-20140403/#deep-combinator - /// And still supported as an alias for >>> by Vue. - deep, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return lhs.* == rhs.*; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - _ = this; // autofix - _ = dest; // autofix - @compileError("Do not call this! Use `serializer.serializeCombinator()` or `tocss_servo.toCss_Combinator()` instead."); - } - - pub fn isTreeCombinator(this: *const @This()) bool { - return switch (this.*) { - .child, .descendant, .next_sibling, .later_sibling => true, - else => false, - }; - } - - pub fn format(this: *const Combinator, writer: *std.Io.Writer) !void { - return switch (this.*) { - .child => writer.print(">", .{}), - .descendant => writer.print("`descendant` (space)", .{}), - .next_sibling => writer.print("+", .{}), - .later_sibling => writer.print("~", .{}), - else => writer.print("{s}", .{@tagName(this.*)}), - }; - } -}; - -pub const SelectorParseErrorKind = union(enum) { - invalid_state, - class_needs_ident: css.Token, - pseudo_element_expected_ident: css.Token, - unsupported_pseudo_class_or_element: []const u8, - no_qualified_name_in_attribute_selector: css.Token, - unexpected_token_in_attribute_selector: css.Token, - unexpected_selector_after_pseudo_element: css.Token, - invalid_qual_name_in_attr: css.Token, - expected_bar_in_attr: css.Token, - empty_selector, - dangling_combinator, - invalid_pseudo_class_before_webkit_scrollbar, - invalid_pseudo_class_after_webkit_scrollbar, - invalid_pseudo_class_after_pseudo_element, - missing_nesting_selector, - missing_nesting_prefix, - expected_namespace: []const u8, - bad_value_in_attr: css.Token, - explicit_namespace_unexpected_token: css.Token, - unexpected_ident: []const u8, - ambiguous_css_module_class: []const u8, - - pub fn intoDefaultParserError(this: SelectorParseErrorKind) css.ParserError { - return css.ParserError{ - .selector_error = this.intoSelectorError(), - }; - } - - pub fn intoSelectorError(this: SelectorParseErrorKind) css.SelectorError { - return switch (this) { - .invalid_state => .invalid_state, - .class_needs_ident => |token| .{ .class_needs_ident = token }, - .pseudo_element_expected_ident => |token| .{ .pseudo_element_expected_ident = token }, - .unsupported_pseudo_class_or_element => |name| .{ .unsupported_pseudo_class_or_element = name }, - .no_qualified_name_in_attribute_selector => |token| .{ .no_qualified_name_in_attribute_selector = token }, - .unexpected_token_in_attribute_selector => |token| .{ .unexpected_token_in_attribute_selector = token }, - .invalid_qual_name_in_attr => |token| .{ .invalid_qual_name_in_attr = token }, - .expected_bar_in_attr => |token| .{ .expected_bar_in_attr = token }, - .empty_selector => .empty_selector, - .dangling_combinator => .dangling_combinator, - .invalid_pseudo_class_before_webkit_scrollbar => .invalid_pseudo_class_before_webkit_scrollbar, - .invalid_pseudo_class_after_webkit_scrollbar => .invalid_pseudo_class_after_webkit_scrollbar, - .invalid_pseudo_class_after_pseudo_element => .invalid_pseudo_class_after_pseudo_element, - .missing_nesting_selector => .missing_nesting_selector, - .missing_nesting_prefix => .missing_nesting_prefix, - .expected_namespace => |name| .{ .expected_namespace = name }, - .bad_value_in_attr => |token| .{ .bad_value_in_attr = token }, - .explicit_namespace_unexpected_token => |token| .{ .explicit_namespace_unexpected_token = token }, - .unexpected_ident => |ident| .{ .unexpected_ident = ident }, - .unexpected_selector_after_pseudo_element => |tok| .{ .unexpected_selector_after_pseudo_element = tok }, - .ambiguous_css_module_class => |name| .{ .ambiguous_css_module_class = name }, - }; - } -}; - -pub fn SimpleSelectorParseResult(comptime Impl: type) type { - ValidSelectorImpl(Impl); - - return union(enum) { - simple_selector: GenericComponent(Impl), - pseudo_element: Impl.SelectorImpl.PseudoElement, - slotted_pseudo: GenericSelector(Impl), - // todo_stuff.think_mem_mgmt - part_pseudo: []Impl.SelectorImpl.Identifier, - }; -} - -/// A pseudo element. -pub const PseudoElement = union(enum) { - /// The [::after](https://drafts.csswg.org/css-pseudo-4/#selectordef-after) pseudo element. - after, - /// The [::before](https://drafts.csswg.org/css-pseudo-4/#selectordef-before) pseudo element. - before, - /// The [::first-line](https://drafts.csswg.org/css-pseudo-4/#first-line-pseudo) pseudo element. - first_line, - /// The [::first-letter](https://drafts.csswg.org/css-pseudo-4/#first-letter-pseudo) pseudo element. - first_letter, - /// The [::selection](https://drafts.csswg.org/css-pseudo-4/#selectordef-selection) pseudo element. - selection: css.VendorPrefix, - /// The [::placeholder](https://drafts.csswg.org/css-pseudo-4/#placeholder-pseudo) pseudo element. - placeholder: css.VendorPrefix, - /// The [::marker](https://drafts.csswg.org/css-pseudo-4/#marker-pseudo) pseudo element. - marker, - /// The [::backdrop](https://fullscreen.spec.whatwg.org/#::backdrop-pseudo-element) pseudo element. - backdrop: css.VendorPrefix, - /// The [::file-selector-button](https://drafts.csswg.org/css-pseudo-4/#file-selector-button-pseudo) pseudo element. - file_selector_button: css.VendorPrefix, - /// A [webkit scrollbar](https://webkit.org/blog/363/styling-scrollbars/) pseudo element. - webkit_scrollbar: WebKitScrollbarPseudoElement, - /// The [::cue](https://w3c.github.io/webvtt/#the-cue-pseudo-element) pseudo element. - cue, - /// The [::cue-region](https://w3c.github.io/webvtt/#the-cue-region-pseudo-element) pseudo element. - cue_region, - /// The [::cue()](https://w3c.github.io/webvtt/#cue-selector) functional pseudo element. - cue_function: struct { - /// The selector argument. - selector: *Selector, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The [::cue-region()](https://w3c.github.io/webvtt/#cue-region-selector) functional pseudo element. - cue_region_function: struct { - /// The selector argument. - selector: *Selector, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The [::view-transition](https://w3c.github.io/csswg-drafts/css-view-transitions-1/#view-transition) pseudo element. - view_transition, - /// The [::view-transition-group()](https://w3c.github.io/csswg-drafts/css-view-transitions-1/#view-transition-group-pt-name-selector) functional pseudo element. - view_transition_group: struct { - /// A part name selector. - part_name: ViewTransitionPartName, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The [::view-transition-image-pair()](https://w3c.github.io/csswg-drafts/css-view-transitions-1/#view-transition-image-pair-pt-name-selector) functional pseudo element. - view_transition_image_pair: struct { - /// A part name selector. - part_name: ViewTransitionPartName, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The [::view-transition-old()](https://w3c.github.io/csswg-drafts/css-view-transitions-1/#view-transition-old-pt-name-selector) functional pseudo element. - view_transition_old: struct { - /// A part name selector. - part_name: ViewTransitionPartName, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// The [::view-transition-new()](https://w3c.github.io/csswg-drafts/css-view-transitions-1/#view-transition-new-pt-name-selector) functional pseudo element. - view_transition_new: struct { - /// A part name selector. - part_name: ViewTransitionPartName, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// An unknown pseudo element. - custom: struct { - /// The name of the pseudo element. - name: []const u8, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - /// An unknown functional pseudo element. - custom_function: struct { - /// The name of the pseudo element. - name: []const u8, - /// The arguments of the pseudo element function. - arguments: css.TokenList, - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }, - - pub fn isEquivalent(this: *const PseudoElement, other: *const PseudoElement) bool { - if (this.* == .selection and other.* == .selection) return true; - if (this.* == .placeholder and other.* == .placeholder) return true; - if (this.* == .backdrop and other.* == .backdrop) return true; - if (this.* == .file_selector_button and other.* == .file_selector_button) return true; - return this.eql(other); - } - - pub fn eql(this: *const PseudoElement, other: *const PseudoElement) bool { - return css.implementEql(PseudoElement, this, other); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn getNecessaryPrefixes(this: *PseudoElement, targets: css.targets.Targets) css.VendorPrefix { - const F = css.prefixes.Feature; - const p: *css.VendorPrefix, const feature: F = switch (this.*) { - .selection => |*p| .{ p, F.pseudo_element_selection }, - .placeholder => |*p| .{ p, F.pseudo_element_placeholder }, - .backdrop => |*p| .{ p, F.pseudo_element_backdrop }, - .file_selector_button => |*p| .{ p, F.pseudo_element_file_selector_button }, - else => return css.VendorPrefix{}, - }; - - p.* = targets.prefixes(p.*, feature); - - return p.*; - } - - pub fn getPrefix(this: *const PseudoElement) css.VendorPrefix { - return switch (this.*) { - .selection, .placeholder, .backdrop, .file_selector_button => |p| p, - else => css.VendorPrefix{}, - }; - } - - pub fn format(this: *const PseudoElement, writer: *std.Io.Writer) !void { - try writer.print("{s}", .{@tagName(this.*)}); - } - - pub fn validAfterSlotted(this: *const PseudoElement) bool { - return switch (this.*) { - .before, .after, .marker, .placeholder, .file_selector_button => true, - else => false, - }; - } - - pub fn isUnknown(this: *const PseudoElement) bool { - return switch (this.*) { - .custom, .custom_function => true, - else => false, - }; - } - - pub fn acceptsStatePseudoClasses(this: *const PseudoElement) bool { - _ = this; // autofix - // Be lienient. - return true; - } - - pub fn isWebkitScrollbar(this: *const PseudoElement) bool { - return this.* == .webkit_scrollbar; - } - - pub fn isViewTransition(this: *const PseudoElement) bool { - return switch (this.*) { - .view_transition_group, .view_transition_image_pair, .view_transition_new, .view_transition_old => true, - else => false, - }; - } - - pub fn toCss(this: *const PseudoElement, dest: *Printer) PrintErr!void { - var s = std.Io.Writer.Allocating.init(dest.allocator); - // PERF(alloc): I don't like making small allocations here for the string. - const writer = &s.writer; - const scratchbuf = std.array_list.Managed(u8).init(dest.allocator); - var printer = Printer.new(dest.allocator, scratchbuf, writer, css.PrinterOptions.default(), dest.import_info, dest.local_names, dest.symbols); - try serialize.serializePseudoElement(this, &printer, null); - return dest.writeStr(s.written()); - } -}; - -/// An enum for the different types of :nth- pseudoclasses -pub const NthType = enum { - child, - last_child, - only_child, - of_type, - last_of_type, - only_of_type, - col, - last_col, - - pub fn isOnly(self: NthType) bool { - return self == NthType.only_child or self == NthType.only_of_type; - } - - pub fn isOfType(self: NthType) bool { - return self == NthType.of_type or self == NthType.last_of_type or self == NthType.only_of_type; - } - - pub fn isFromEnd(self: NthType) bool { - return self == NthType.last_child or self == NthType.last_of_type or self == NthType.last_col; - } - - pub fn allowsOfSelector(self: NthType) bool { - return self == NthType.child or self == NthType.last_child; - } -}; - -/// * `Err(())`: Invalid selector, abort -/// * `Ok(false)`: Not a type selector, could be something else. `input` was not consumed. -/// * `Ok(true)`: Length 0 (`*|*`), 1 (`*|E` or `ns|*`) or 2 (`|E` or `ns|E`) -pub fn parse_type_selector( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: SelectorParsingState, - sink: *SelectorBuilder(Impl), -) Result(bool) { - const result = switch (parse_qualified_name( - Impl, - parser, - input, - false, - )) { - .result => |v| v, - .err => |e| { - if (e.kind == .basic and e.kind.basic == .end_of_input) { - return .{ .result = false }; - } - - return .{ .err = e }; - }, - }; - - if (result == .none) return .{ .result = false }; - - const namespace: QNamePrefix(Impl) = result.some[0]; - const local_name: ?[]const u8 = result.some[1]; - if (state.afterAnyPseudo()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - - switch (namespace) { - .implicit_any_namespace => {}, - .implicit_default_namespace => |url| { - sink.pushSimpleSelector(.{ .default_namespace = url }); - }, - .explicit_namespace => { - const prefix = namespace.explicit_namespace[0]; - const url = namespace.explicit_namespace[1]; - const component: GenericComponent(Impl) = component: { - if (parser.defaultNamespace()) |default_url| { - if (bun.strings.eql(url, default_url)) { - break :component .{ .default_namespace = url }; - } - } - break :component .{ - .namespace = .{ - .prefix = prefix, - .url = url, - }, - }; - }; - sink.pushSimpleSelector(component); - }, - .explicit_no_namespace => { - sink.pushSimpleSelector(.explicit_no_namespace); - }, - .explicit_any_namespace => { - // Element type selectors that have no namespace - // component (no namespace separator) represent elements - // without regard to the element's namespace (equivalent - // to "*|") unless a default namespace has been declared - // for namespaced selectors (e.g. in CSS, in the style - // sheet). If a default namespace has been declared, - // such selectors will represent only elements in the - // default namespace. - // -- Selectors § 6.1.1 - // So we'll have this act the same as the - // QNamePrefix::ImplicitAnyNamespace case. - // For lightning css this logic was removed, should be handled when matching. - sink.pushSimpleSelector(.explicit_any_namespace); - }, - .implicit_no_namespace => { - bun.unreachablePanic("Should not be returned with in_attr_selector = false", .{}); - }, - } - - if (local_name) |name| { - sink.pushSimpleSelector(.{ - .local_name = LocalName(Impl){ - .lower_name = brk: { - var lowercase = parser.allocator.alloc(u8, name.len) catch unreachable; // PERF: check if it's already lowercase - break :brk .{ .v = bun.strings.copyLowercase(name, lowercase[0..]) }; - }, - .name = .{ .v = name }, - }, - }); - } else { - sink.pushSimpleSelector(.explicit_universal_type); - } - - return .{ .result = true }; -} - -/// Parse a simple selector other than a type selector. -/// -/// * `Err(())`: Invalid selector, abort -/// * `Ok(None)`: Not a simple selector, could be something else. `input` was not consumed. -/// * `Ok(Some(_))`: Parsed a simple selector or pseudo-element -pub fn parse_one_simple_selector( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, -) Result(?SimpleSelectorParseResult(Impl)) { - const S = SimpleSelectorParseResult(Impl); - - const start = input.state(); - const token_location = input.currentSourceLocation(); - const token_loc = input.position(); - const token = switch (input.nextIncludingWhitespace()) { - .result => |v| v.*, - .err => { - input.reset(&start); - return .{ .result = null }; - }, - }; - - switch (token) { - .idhash => |id| { - if (state.afterAnyPseudo()) { - return .{ .err = token_location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_selector_after_pseudo_element = .{ .idhash = id } })) }; - } - const component: GenericComponent(Impl) = .{ .id = parser.newLocalIdentifier(input, .ID, id, token_loc) }; - return .{ .result = S{ - .simple_selector = component, - } }; - }, - .open_square => { - if (state.afterAnyPseudo()) { - return .{ .err = token_location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_selector_after_pseudo_element = .open_square })) }; - } - const Closure = struct { - parser: *SelectorParser, - }; - var closure = Closure{ - .parser = parser, - }; - const attr = switch (input.parseNestedBlock(GenericComponent(Impl), &closure, struct { - pub fn parsefn(this: *Closure, input2: *css.Parser) Result(GenericComponent(Impl)) { - return parse_attribute_selector(Impl, this.parser, input2); - } - } - .parsefn)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = .{ .simple_selector = attr } }; - }, - .colon => { - const location = input.currentSourceLocation(); - const is_single_colon: bool, const next_token: css.Token = switch ((switch (input.nextIncludingWhitespace()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }).*) { - .colon => .{ false, (switch (input.nextIncludingWhitespace()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }).* }, - else => |t| .{ true, t }, - }; - const name: []const u8, const is_functional = switch (next_token) { - .ident => |name| .{ name, false }, - .function => |name| .{ name, true }, - else => |t| { - const e = SelectorParseErrorKind{ .pseudo_element_expected_ident = t }; - return .{ .err = input.newCustomError(e.intoDefaultParserError()) }; - }, - }; - const is_pseudo_element = !is_single_colon or is_css2_pseudo_element(name); - if (is_pseudo_element) { - if (!state.allowsPseudos()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - const pseudo_element: Impl.SelectorImpl.PseudoElement = if (is_functional) pseudo_element: { - if (parser.parsePart() and bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "part")) { - if (!state.allowsPart()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - - const Closure = struct { - parser: *SelectorParser, - - pub fn parsefn(self: *const @This(), input2: *css.Parser) Result([]Impl.SelectorImpl.Identifier) { - // todo_stuff.think_about_mem_mgmt - var result = ArrayList(Impl.SelectorImpl.Identifier).initCapacity( - self.parser.allocator, - // TODO: source does this, should see if initializing to 1 is actually better - // when appending empty std.ArrayList(T), it will usually initially reserve 8 elements, - // maybe that's unnecessary, or maybe smallvec is gud here - 1, - ) catch unreachable; - - result.append( - self.parser.allocator, - switch (input2.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| .{ .v = v }, - }, - ) catch unreachable; - - while (!input2.isExhausted()) { - result.append( - self.parser.allocator, - switch (input2.expectIdent()) { - .err => |e| return .{ .err = e }, - .result => |v| .{ .v = v }, - }, - ) catch unreachable; - } - - return .{ .result = result.items }; - } - }; - - const names = switch (input.parseNestedBlock([]Impl.SelectorImpl.Identifier, &Closure{ .parser = parser }, Closure.parsefn)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - return .{ .result = .{ .part_pseudo = names } }; - } - - if (parser.parseSlotted() and bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "slotted")) { - if (!state.allowsSlotted()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - const Closure = struct { - parser: *SelectorParser, - state: *SelectorParsingState, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(GenericSelector(Impl)) { - return parse_inner_compound_selector(Impl, this.parser, input2, this.state); - } - }; - var closure = Closure{ - .parser = parser, - .state = state, - }; - const selector = switch (input.parseNestedBlock(GenericSelector(Impl), &closure, Closure.parsefn)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = .{ .slotted_pseudo = selector } }; - } - - const Closure = struct { - parser: *SelectorParser, - state: *SelectorParsingState, - name: []const u8, - }; - break :pseudo_element switch (input.parseNestedBlock(Impl.SelectorImpl.PseudoElement, &Closure{ .parser = parser, .state = state, .name = name }, struct { - pub fn parseFn(closure: *const Closure, i: *css.Parser) Result(Impl.SelectorImpl.PseudoElement) { - return closure.parser.parseFunctionalPseudoElement(closure.name, i); - } - }.parseFn)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - } else pseudo_element: { - break :pseudo_element switch (parser.parsePseudoElement(location, name)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - }; - - if (state.after_slotted and pseudo_element.validAfterSlotted()) { - return .{ .result = .{ .pseudo_element = pseudo_element } }; - } - - return .{ .result = .{ .pseudo_element = pseudo_element } }; - } else { - const pseudo_class: GenericComponent(Impl) = if (is_functional) pseudo_class: { - const Closure = struct { - parser: *SelectorParser, - name: []const u8, - state: *SelectorParsingState, - pub fn parsefn(this: *@This(), input2: *css.Parser) Result(GenericComponent(Impl)) { - return parse_functional_pseudo_class(Impl, this.parser, input2, this.name, this.state); - } - }; - var closure = Closure{ - .parser = parser, - .name = name, - .state = state, - }; - - break :pseudo_class switch (input.parseNestedBlock(GenericComponent(Impl), &closure, Closure.parsefn)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - } else switch (parse_simple_pseudo_class(Impl, parser, location, name, state.*)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - return .{ .result = .{ .simple_selector = pseudo_class } }; - } - }, - .delim => |d| { - switch (d) { - '.' => { - if (state.afterAnyPseudo()) { - return .{ .err = token_location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_selector_after_pseudo_element = .{ .delim = '.' } })) }; - } - const location = input.currentSourceLocation(); - const class = switch ((switch (input.nextIncludingWhitespace()) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }).*) { - .ident => |class| class, - else => |t| { - const e = SelectorParseErrorKind{ .class_needs_ident = t }; - return .{ .err = location.newCustomError(e.intoDefaultParserError()) }; - }, - }; - return .{ .result = .{ .simple_selector = .{ .class = parser.newLocalIdentifier(input, .CLASS, class, token_loc) } } }; - }, - '&' => { - if (parser.isNestingAllowed()) { - state.after_nesting = true; - return .{ .result = S{ - .simple_selector = .nesting, - } }; - } - }, - else => {}, - } - }, - else => {}, - } - - input.reset(&start); - return .{ .result = null }; -} - -pub fn parse_attribute_selector(comptime Impl: type, parser: *SelectorParser, input: *css.Parser) Result(GenericComponent(Impl)) { - const N = attrs.NamespaceConstraint(attrs.NamespaceUrl(Impl)); - - const namespace: ?N, const local_name: []const u8 = brk: { - input.skipWhitespace(); - - const _qname = switch (parse_qualified_name(Impl, parser, input, true)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - switch (_qname) { - .none => |t| return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .no_qualified_name_in_attribute_selector = t })) }, - .some => |qname| { - if (qname[1] == null) { - bun.unreachablePanic("", .{}); - } - const ns: QNamePrefix(Impl) = qname[0]; - const ln = qname[1].?; - break :brk .{ - switch (ns) { - .implicit_no_namespace, .explicit_no_namespace => null, - .explicit_namespace => |x| .{ .specific = .{ .prefix = x[0], .url = x[1] } }, - .explicit_any_namespace => .any, - .implicit_any_namespace, .implicit_default_namespace => { - bun.unreachablePanic("Not returned with in_attr_selector = true", .{}); - }, - }, - ln, - }; - }, - } - }; - - const location = input.currentSourceLocation(); - const operator: attrs.AttrSelectorOperator = operator: { - const tok = switch (input.next()) { - .result => |v| v, - .err => { - // [foo] - const local_name_lower = local_name_lower: { - const lower = parser.allocator.alloc(u8, local_name.len) catch unreachable; - _ = bun.strings.copyLowercase(local_name, lower); - break :local_name_lower lower; - }; - if (namespace) |ns| { - const x = attrs.AttrSelectorWithOptionalNamespace(Impl){ - .namespace = ns, - .local_name = .{ .v = local_name }, - .local_name_lower = .{ .v = local_name_lower }, - .never_matches = false, - .operation = .exists, - }; - return .{ - .result = .{ .attribute_other = bun.create(parser.allocator, attrs.AttrSelectorWithOptionalNamespace(Impl), x) }, - }; - } else { - return .{ .result = .{ - .attribute_in_no_namespace_exists = .{ - .local_name = .{ .v = local_name }, - .local_name_lower = .{ .v = local_name_lower }, - }, - } }; - } - }, - }; - - switch (tok.*) { - // [foo=bar] - .delim => |d| { - if (d == '=') break :operator .equal; - }, - // [foo~=bar] - .include_match => break :operator .includes, - // [foo|=bar] - .dash_match => break :operator .dash_match, - // [foo^=bar] - .prefix_match => break :operator .prefix, - // [foo*=bar] - .substring_match => break :operator .substring, - // [foo$=bar] - .suffix_match => break :operator .suffix, - else => {}, - } - return .{ .err = location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unexpected_token_in_attribute_selector = tok.* })) }; - }; - - const value_str: []const u8 = switch (input.expectIdentOrString()) { - .result => |v| v, - .err => |e| { - if (e.kind == .basic and e.kind.basic == .unexpected_token) { - return .{ .err = e.location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .bad_value_in_attr = e.kind.basic.unexpected_token })) }; - } - return .{ - .err = .{ - .kind = e.kind, - .location = e.location, - }, - }; - }, - }; - const never_matches = switch (operator) { - .equal, .dash_match => false, - .includes => value_str.len == 0 or bun.strings.indexOfAny(value_str, SELECTOR_WHITESPACE) != null, - .prefix, .substring, .suffix => value_str.len == 0, - }; - - const attribute_flags = switch (parse_attribute_flags(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const value: Impl.SelectorImpl.AttrValue = value_str; - const local_name_lower: Impl.SelectorImpl.LocalName, const local_name_is_ascii_lowercase: bool = brk: { - if (a: { - for (local_name, 0..) |b, i| { - if (b >= 'A' and b <= 'Z') break :a i; - } - break :a null; - }) |first_uppercase| { - const str = local_name[first_uppercase..]; - const lower = parser.allocator.alloc(u8, str.len) catch unreachable; - break :brk .{ .{ .v = bun.strings.copyLowercase(str, lower) }, false }; - } else { - break :brk .{ .{ .v = local_name }, true }; - } - }; - const case_sensitivity: attrs.ParsedCaseSensitivity = attribute_flags.toCaseSensitivity(local_name_lower.v, namespace != null); - if (namespace != null and !local_name_is_ascii_lowercase) { - return .{ .result = .{ - .attribute_other = brk: { - const x = attrs.AttrSelectorWithOptionalNamespace(Impl){ - .namespace = namespace, - .local_name = .{ .v = local_name }, - .local_name_lower = local_name_lower, - .never_matches = never_matches, - .operation = .{ - .with_value = .{ - .operator = operator, - .case_sensitivity = case_sensitivity, - .expected_value = value, - }, - }, - }; - break :brk bun.create(parser.allocator, @TypeOf(x), x); - }, - } }; - } else { - return .{ .result = .{ - .attribute_in_no_namespace = .{ - .local_name = .{ .v = local_name }, - .operator = operator, - .value = value, - .case_sensitivity = case_sensitivity, - .never_matches = never_matches, - }, - } }; - } -} - -/// Returns whether the name corresponds to a CSS2 pseudo-element that -/// can be specified with the single colon syntax (in addition to the -/// double-colon syntax, which can be used for all pseudo-elements). -pub fn is_css2_pseudo_element(name: []const u8) bool { - // ** Do not add to this list! ** - // TODO: todo_stuff.match_ignore_ascii_case - return bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "before") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "after") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "first-line") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "first-letter"); -} - -/// Parses one compound selector suitable for nested stuff like :-moz-any, etc. -pub fn parse_inner_compound_selector( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, -) Result(GenericSelector(Impl)) { - var child_state = brk: { - var child_state = state.*; - child_state.disallow_pseudos = true; - child_state.disallow_combinators = true; - break :brk child_state; - }; - const result = switch (parse_selector(Impl, parser, input, &child_state, NestingRequirement.none)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (child_state.after_nesting) { - state.after_nesting = true; - } - return .{ .result = result }; -} - -pub fn parse_functional_pseudo_class( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - name: []const u8, - state: *SelectorParsingState, -) Result(GenericComponent(Impl)) { - const FunctionalPseudoClass = enum { - @"nth-child", - @"nth-of-type", - @"nth-last-child", - @"nth-last-of-type", - @"nth-col", - @"nth-last-col", - is, - where, - has, - host, - not, - }; - const Map = bun.ComptimeEnumMap(FunctionalPseudoClass); - - if (Map.getASCIIICaseInsensitive(name)) |functional_pseudo_class| { - switch (functional_pseudo_class) { - .@"nth-child" => return parse_nth_pseudo_class(Impl, parser, input, state.*, .child), - .@"nth-of-type" => return parse_nth_pseudo_class(Impl, parser, input, state.*, .of_type), - .@"nth-last-child" => return parse_nth_pseudo_class(Impl, parser, input, state.*, .last_child), - .@"nth-last-of-type" => return parse_nth_pseudo_class(Impl, parser, input, state.*, .last_of_type), - .@"nth-col" => return parse_nth_pseudo_class(Impl, parser, input, state.*, .col), - .@"nth-last-col" => return parse_nth_pseudo_class(Impl, parser, input, state.*, .last_col), - .is => if (parser.parseIsAndWhere()) return parse_is_or_where(Impl, parser, input, state, GenericComponent(Impl).convertHelper_is, .{}), - .where => if (parser.parseIsAndWhere()) return parse_is_or_where(Impl, parser, input, state, GenericComponent(Impl).convertHelper_where, .{}), - .has => return parse_has(Impl, parser, input, state), - .host => if (!state.allowsTreeStructuralPseudoClasses()) - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) } - else - return .{ .result = .{ - .host = switch (parse_inner_compound_selector(Impl, parser, input, state)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }, - } }, - .not => return parse_negation(Impl, parser, input, state), - } - } - - if (parser.parseAnyPrefix(name)) |prefix| { - return parse_is_or_where(Impl, parser, input, state, GenericComponent(Impl).convertHelper_any, .{prefix}); - } - - if (!state.allowsCustomFunctionalPseudoClasses()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - - const result = switch (parser.parseNonTsFunctionalPseudoClass(name, input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - return .{ .result = .{ .non_ts_pseudo_class = result } }; -} - -const TreeStructuralPseudoClass = enum { @"first-child", @"last-child", @"only-child", root, empty, scope, host, @"first-of-type", @"last-of-type", @"only-of-type" }; -const TreeStructuralPseudoClassMap = bun.ComptimeEnumMap(TreeStructuralPseudoClass); - -pub fn parse_simple_pseudo_class( - comptime Impl: type, - parser: *SelectorParser, - location: css.SourceLocation, - name: []const u8, - state: SelectorParsingState, -) Result(GenericComponent(Impl)) { - if (!state.allowsNonFunctionalPseudoClasses()) { - return .{ .err = location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - - if (state.allowsTreeStructuralPseudoClasses()) { - if (TreeStructuralPseudoClassMap.getAnyCase(name)) |pseudo_class| { - switch (pseudo_class) { - .@"first-child" => return .{ .result = .{ .nth = NthSelectorData.first(false) } }, - .@"last-child" => return .{ .result = .{ .nth = NthSelectorData.last(false) } }, - .@"only-child" => return .{ .result = .{ .nth = NthSelectorData.only(false) } }, - .root => return .{ .result = .root }, - .empty => return .{ .result = .empty }, - .scope => return .{ .result = .scope }, - .host => if (parser.parseHost()) return .{ .result = .{ .host = null } }, - .@"first-of-type" => return .{ .result = .{ .nth = NthSelectorData.first(true) } }, - .@"last-of-type" => return .{ .result = .{ .nth = NthSelectorData.last(true) } }, - .@"only-of-type" => return .{ .result = .{ .nth = NthSelectorData.only(true) } }, - } - } - } - - // The view-transition pseudo elements accept the :only-child pseudo class. - // https://w3c.github.io/csswg-drafts/css-view-transitions-1/#pseudo-root - if (state.after_view_transition) { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(name, "only-child")) { - return .{ .result = .{ .nth = NthSelectorData.only(false) } }; - } - } - - const pseudo_class = switch (parser.parseNonTsPseudoClass(location, name)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (state.after_webkit_scrollbar) { - if (!pseudo_class.isValidAfterWebkitScrollbar()) { - return .{ .err = location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_pseudo_class_after_webkit_scrollbar)) }; - } - } else if (state.after_pseudo_element) { - if (!pseudo_class.isUserActionState()) { - return .{ .err = location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_pseudo_class_after_pseudo_element)) }; - } - } else if (!pseudo_class.isValidBeforeWebkitScrollbar()) { - return .{ .err = location.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_pseudo_class_before_webkit_scrollbar)) }; - } - - return .{ .result = .{ .non_ts_pseudo_class = pseudo_class } }; -} - -pub fn parse_nth_pseudo_class( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: SelectorParsingState, - ty: NthType, -) Result(GenericComponent(Impl)) { - if (!state.allowsTreeStructuralPseudoClasses()) { - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.invalid_state)) }; - } - - const a, const b = switch (css.nth.parse_nth(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - const nth_data = NthSelectorData{ - .ty = ty, - .is_function = true, - .a = a, - .b = b, - }; - - if (!ty.allowsOfSelector()) { - return .{ .result = .{ .nth = nth_data } }; - } - - // Try to parse "of ". - if (input.tryParse(css.Parser.expectIdentMatching, .{"of"}).isErr()) { - return .{ .result = .{ .nth = nth_data } }; - } - - // Whitespace between "of" and the selector list is optional - // https://github.com/w3c/csswg-drafts/issues/8285 - var child_state = child_state: { - var s = state; - s.skip_default_namespace = true; - s.disallow_pseudos = true; - break :child_state s; - }; - - const selectors = switch (SelectorList.parseWithState( - parser, - input, - &child_state, - .ignore_invalid_selector, - .none, - )) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - return .{ .result = .{ - .nth_of = NthOfSelectorData(Impl){ - .data = nth_data, - .selectors = selectors.v.toOwnedSlice(input.allocator()), - }, - } }; -} - -/// `func` must be of the type: fn([]GenericSelector(Impl), ...@TypeOf(args_)) GenericComponent(Impl) -pub fn parse_is_or_where( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, - comptime func: anytype, - args_: anytype, -) Result(GenericComponent(Impl)) { - bun.debugAssert(parser.parseIsAndWhere()); - // https://drafts.csswg.org/selectors/#matches-pseudo: - // - // Pseudo-elements cannot be represented by the matches-any - // pseudo-class; they are not valid within :is(). - // - var child_state = brk: { - var child_state = state.*; - child_state.skip_default_namespace = true; - child_state.disallow_pseudos = true; - break :brk child_state; - }; - - const inner = switch (SelectorList.parseWithState(parser, input, &child_state, parser.isAndWhereErrorRecovery(), NestingRequirement.none)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - if (child_state.after_nesting) { - state.after_nesting = true; - } - - const selector_slice = inner.v.toOwnedSlice(input.allocator()); - - const result = result: { - const args = brk: { - var args: std.meta.ArgsTuple(@TypeOf(func)) = undefined; - args[0] = selector_slice; - - inline for (args_, 1..) |a, i| { - args[i] = a; - } - - break :brk args; - }; - - break :result @call(.auto, func, args); - }; - - return .{ .result = result }; -} - -pub fn parse_has( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, -) Result(GenericComponent(Impl)) { - var child_state = state.*; - const inner = switch (SelectorList.parseRelativeWithState( - parser, - input, - &child_state, - parser.isAndWhereErrorRecovery(), - .none, - )) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - if (child_state.after_nesting) { - state.after_nesting = true; - } - return .{ .result = .{ .has = inner.v.toOwnedSlice(input.allocator()) } }; -} - -/// Level 3: Parse **one** simple_selector. (Though we might insert a second -/// implied "|*" type selector.) -pub fn parse_negation( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - state: *SelectorParsingState, -) Result(GenericComponent(Impl)) { - var child_state = state.*; - child_state.skip_default_namespace = true; - child_state.disallow_pseudos = true; - - const list = switch (SelectorList.parseWithState(parser, input, &child_state, .discard_list, .none)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - if (child_state.after_nesting) { - state.after_nesting = true; - } - - return .{ .result = .{ .negation = list.v.toOwnedSlice(input.allocator()) } }; -} - -pub fn OptionalQName(comptime Impl: type) type { - return union(enum) { - some: struct { QNamePrefix(Impl), ?[]const u8 }, - none: css.Token, - }; -} - -pub fn QNamePrefix(comptime Impl: type) type { - return union(enum) { - implicit_no_namespace, // `foo` in attr selectors - implicit_any_namespace, // `foo` in type selectors, without a default ns - implicit_default_namespace: Impl.SelectorImpl.NamespaceUrl, // `foo` in type selectors, with a default ns - explicit_no_namespace, // `|foo` - explicit_any_namespace, // `*|foo` - explicit_namespace: struct { Impl.SelectorImpl.NamespacePrefix, Impl.SelectorImpl.NamespaceUrl }, // `prefix|foo` - }; -} - -/// * `Err(())`: Invalid selector, abort -/// * `Ok(None(token))`: Not a simple selector, could be something else. `input` was not consumed, -/// but the token is still returned. -/// * `Ok(Some(namespace, local_name))`: `None` for the local name means a `*` universal selector -pub fn parse_qualified_name( - comptime Impl: type, - parser: *SelectorParser, - input: *css.Parser, - in_attr_selector: bool, -) Result(OptionalQName(Impl)) { - const start = input.state(); - - const tok = switch (input.nextIncludingWhitespace()) { - .result => |v| v, - .err => |e| { - input.reset(&start); - return .{ .err = e }; - }, - }; - switch (tok.*) { - .ident => |value| { - const after_ident = input.state(); - const n = if (input.nextIncludingWhitespace().asValue()) |t| t.* == .delim and t.delim == '|' else false; - if (n) { - const prefix: Impl.SelectorImpl.NamespacePrefix = .{ .v = value }; - const result: ?Impl.SelectorImpl.NamespaceUrl = parser.namespaceForPrefix(prefix); - const url: Impl.SelectorImpl.NamespaceUrl = brk: { - if (result) |url| break :brk url; - return .{ .err = input.newCustomError(SelectorParseErrorKind.intoDefaultParserError(.{ .unsupported_pseudo_class_or_element = value })) }; - }; - return parse_qualified_name_eplicit_namespace_helper( - Impl, - input, - .{ .explicit_namespace = .{ prefix, url } }, - in_attr_selector, - ); - } else { - input.reset(&after_ident); - if (in_attr_selector) return .{ .result = .{ .some = .{ .implicit_no_namespace, value } } }; - return .{ .result = parse_qualified_name_default_namespace_helper(Impl, parser, value) }; - } - }, - .delim => |c| { - switch (c) { - '*' => { - const after_star = input.state(); - const result = input.nextIncludingWhitespace(); - if (result.asValue()) |t| if (t.* == .delim and t.delim == '|') - return parse_qualified_name_eplicit_namespace_helper( - Impl, - input, - .explicit_any_namespace, - in_attr_selector, - ); - input.reset(&after_star); - if (in_attr_selector) { - switch (result) { - .result => |t| { - return .{ .err = after_star.sourceLocation().newCustomError(SelectorParseErrorKind{ - .expected_bar_in_attr = t.*, - }) }; - }, - .err => |e| { - return .{ .err = e }; - }, - } - } else { - return .{ .result = parse_qualified_name_default_namespace_helper(Impl, parser, null) }; - } - }, - '|' => return parse_qualified_name_eplicit_namespace_helper(Impl, input, .explicit_no_namespace, in_attr_selector), - else => {}, - } - }, - else => {}, - } - input.reset(&start); - return .{ .result = .{ .none = tok.* } }; -} - -fn parse_qualified_name_default_namespace_helper( - comptime Impl: type, - parser: *SelectorParser, - local_name: ?[]const u8, -) OptionalQName(Impl) { - const namespace: QNamePrefix(Impl) = if (parser.defaultNamespace()) |url| .{ .implicit_default_namespace = url } else .implicit_any_namespace; - return .{ - .some = .{ - namespace, - local_name, - }, - }; -} - -fn parse_qualified_name_eplicit_namespace_helper( - comptime Impl: type, - input: *css.Parser, - namespace: QNamePrefix(Impl), - in_attr_selector: bool, -) Result(OptionalQName(Impl)) { - const location = input.currentSourceLocation(); - const t = switch (input.nextIncludingWhitespace()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - switch (t.*) { - .ident => |local_name| return .{ .result = .{ .some = .{ namespace, local_name } } }, - .delim => |c| { - if (c == '*') { - return .{ .result = .{ .some = .{ namespace, null } } }; - } - }, - else => {}, - } - if (in_attr_selector) { - const e = SelectorParseErrorKind{ .invalid_qual_name_in_attr = t.* }; - return .{ .err = location.newCustomError(e) }; - } - return .{ .err = location.newCustomError(SelectorParseErrorKind{ .explicit_namespace_unexpected_token = t.* }) }; -} - -pub fn LocalName(comptime Impl: type) type { - return struct { - name: Impl.SelectorImpl.LocalName, - lower_name: Impl.SelectorImpl.LocalName, - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.IdentFns.toCss(&this.name, dest); - } - - pub fn __generateEql() void {} - pub fn __generateDeepClone() void {} - pub fn __generateHash() void {} - }; -} - -/// An attribute selector can have 's' or 'i' as flags, or no flags at all. -pub const AttributeFlags = enum { - // Matching should be case-sensitive ('s' flag). - case_sensitive, - // Matching should be case-insensitive ('i' flag). - ascii_case_insensitive, - // No flags. Matching behavior depends on the name of the attribute. - case_sensitivity_depends_on_name, - - pub fn toCaseSensitivity(this: AttributeFlags, local_name: []const u8, have_namespace: bool) attrs.ParsedCaseSensitivity { - return switch (this) { - .case_sensitive => .explicit_case_sensitive, - .ascii_case_insensitive => .ascii_case_insensitive, - .case_sensitivity_depends_on_name => { - // - const AsciiCaseInsensitiveHtmlAttributes = enum { - dir, - http_equiv, - rel, - enctype, - @"align", - accept, - nohref, - lang, - bgcolor, - direction, - valign, - checked, - frame, - link, - accept_charset, - hreflang, - text, - valuetype, - language, - nowrap, - vlink, - disabled, - noshade, - codetype, - @"defer", - noresize, - target, - scrolling, - rules, - scope, - rev, - media, - method, - charset, - alink, - selected, - multiple, - color, - shape, - type, - clear, - compact, - face, - declare, - axis, - readonly, - }; - const Map = comptime bun.ComptimeEnumMap(AsciiCaseInsensitiveHtmlAttributes); - if (!have_namespace and Map.has(local_name)) return .ascii_case_insensitive_if_in_html_element_in_html_document; - return .case_sensitive; - }, - }; - } -}; - -/// A [view transition part name](https://w3c.github.io/csswg-drafts/css-view-transitions-1/#typedef-pt-name-selector). -pub const ViewTransitionPartName = union(enum) { - /// * - all, - /// - name: css.css_values.ident.CustomIdent, - /// . - class: css.css_values.ident.CustomIdent, - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .all => try dest.writeStr("*"), - .name => |name| try css.CustomIdentFns.toCss(&name, dest), - .class => |name| { - try dest.writeChar('.'); - try css.CustomIdentFns.toCss(&name, dest); - }, - }; - } - - pub fn parse(input: *css.Parser) Result(ViewTransitionPartName) { - if (input.tryParse(css.Parser.expectDelim, .{'*'}).isOk()) { - return .{ .result = .all }; - } - - // Try to parse a class selector (.) - if (input.tryParse(css.Parser.expectDelim, .{'.'}).isOk()) { - return .{ .result = .{ .class = switch (css.css_values.ident.CustomIdent.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }; - } - - return .{ .result = .{ .name = switch (css.css_values.ident.CustomIdent.parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - } } }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub fn parse_attribute_flags(input: *css.Parser) Result(AttributeFlags) { - const location = input.currentSourceLocation(); - const token = switch (input.next()) { - .result => |v| v, - .err => { - // Selectors spec says language-defined; HTML says it depends on the - // exact attribute name. - return .{ .result = AttributeFlags.case_sensitivity_depends_on_name }; - }, - }; - - const ident = if (token.* == .ident) token.ident else return .{ .err = location.newBasicUnexpectedTokenError(token.*) }; - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "i")) { - return .{ .result = AttributeFlags.ascii_case_insensitive }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "s")) { - return .{ .result = AttributeFlags.case_sensitive }; - } else { - return .{ .err = location.newBasicUnexpectedTokenError(token.*) }; - } -} - -const selector_builder = @import("./builder.zig"); -const SelectorBuilder = selector_builder.SelectorBuilder; - -const bun = @import("bun"); -const logger = bun.logger; - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/selectors/selector.zig b/src/css/selectors/selector.zig deleted file mode 100644 index eb9a0e910710..000000000000 --- a/src/css/selectors/selector.zig +++ /dev/null @@ -1,1613 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const CSSString = css.CSSString; -const CSSStringFns = css.CSSStringFns; - -pub const Printer = css.Printer; -pub const PrintErr = css.PrintErr; - -pub const Selector = parser.Selector; -pub const SelectorList = parser.SelectorList; -pub const Component = parser.Component; -pub const PseudoClass = parser.PseudoClass; -pub const PseudoElement = parser.PseudoElement; - -const debug = bun.Output.scoped(.CSS_SELECTORS, .visible); - -/// Our implementation of the `SelectorImpl` interface -/// -pub const impl = struct { - pub const Selectors = struct { - pub const SelectorImpl = struct { - pub const AttrValue = css.css_values.string.CSSString; - pub const Identifier = css.css_values.ident.Ident; - /// An identifier which could be a local name for use in CSS modules - pub const LocalIdentifier = css.css_values.ident.IdentOrRef; - pub const LocalName = css.css_values.ident.Ident; - pub const NamespacePrefix = css.css_values.ident.Ident; - pub const NamespaceUrl = []const u8; - pub const BorrowedNamespaceUrl = []const u8; - pub const BorrowedLocalName = css.css_values.ident.Ident; - - pub const NonTSPseudoClass = parser.PseudoClass; - pub const PseudoElement = parser.PseudoElement; - pub const VendorPrefix = css.VendorPrefix; - pub const ExtraMatchingData = void; - }; - - pub const LocalIdentifier = struct { - pub fn fromIdent(ident: css.css_values.ident.Ident) SelectorImpl.LocalIdentifier { - return .{ .v = ident }; - } - }; - }; -}; - -pub const parser = @import("./parser.zig"); - -/// Returns whether two selector lists are equivalent, i.e. the same minus any vendor prefix differences. -pub fn isEquivalent(selectors: []const Selector, other: []const Selector) bool { - if (selectors.len != other.len) return false; - - for (selectors, 0..) |*a, i| { - const b = &other[i]; - if (a.len() != b.len()) return false; - - for (a.components.items, b.components.items) |*a_comp, *b_comp| { - const is_equivalent = blk: { - if (a_comp.* == .non_ts_pseudo_class and b_comp.* == .non_ts_pseudo_class) { - break :blk a_comp.non_ts_pseudo_class.isEquivalent(&b_comp.non_ts_pseudo_class); - } else if (a_comp.* == .pseudo_element and b_comp.* == .pseudo_element) { - break :blk a_comp.pseudo_element.isEquivalent(&b_comp.pseudo_element); - } else if ((a_comp.* == .any and b_comp.* == .is) or - (a_comp.* == .is and b_comp.* == .any) or - (a_comp.* == .any and b_comp.* == .any) or - (a_comp.* == .is and b_comp.* == .is)) - { - const a_selectors = switch (a_comp.*) { - .any => |v| v.selectors, - .is => |v| v, - else => unreachable, - }; - const b_selectors = switch (b_comp.*) { - .any => |v| v.selectors, - .is => |v| v, - else => unreachable, - }; - break :blk isEquivalent(a_selectors, b_selectors); - } else { - break :blk Component.eql(a_comp, b_comp); - } - }; - - if (!is_equivalent) { - return false; - } - } - } - - return true; -} - -/// Downlevels the given selectors to be compatible with the given browser targets. -/// Returns the necessary vendor prefixes. -pub fn downlevelSelectors(allocator: Allocator, selectors: []Selector, targets: css.targets.Targets) css.VendorPrefix { - var necessary_prefixes = css.VendorPrefix{}; - for (selectors) |*selector| { - for (selector.components.items) |*component| { - bun.bits.insert(css.VendorPrefix, &necessary_prefixes, downlevelComponent(allocator, component, targets)); - } - } - return necessary_prefixes; -} - -pub fn downlevelComponent(allocator: Allocator, component: *Component, targets: css.targets.Targets) css.VendorPrefix { - return switch (component.*) { - .non_ts_pseudo_class => |*pc| { - return switch (pc.*) { - .dir => |*d| { - if (targets.shouldCompileSame(.dir_selector)) { - component.* = downlevelDir(allocator, d.direction, targets); - return downlevelComponent(allocator, component, targets); - } - return css.VendorPrefix{}; - }, - .lang => |l| { - // :lang() with multiple languages is not supported everywhere. - // compile this to :is(:lang(a), :lang(b)) etc. - if (l.languages.items.len > 1 and targets.shouldCompileSame(.lang_selector_list)) { - component.* = .{ .is = langListToSelectors(allocator, l.languages.items) }; - return downlevelComponent(allocator, component, targets); - } - return css.VendorPrefix{}; - }, - else => pc.getNecessaryPrefixes(targets), - }; - }, - .pseudo_element => |*pe| pe.getNecessaryPrefixes(targets), - .is => |selectors| { - var necessary_prefixes = downlevelSelectors(allocator, selectors, targets); - - // Convert :is to :-webkit-any/:-moz-any if needed. - // All selectors must be simple, no combinators are supported. - if (targets.shouldCompileSame(.is_selector) and - !shouldUnwrapIs(selectors) and brk: { - for (selectors) |*selector| { - if (selector.hasCombinator()) break :brk false; - } - break :brk true; - }) { - bun.bits.insert(css.VendorPrefix, &necessary_prefixes, targets.prefixes(css.VendorPrefix{ .none = true }, .any_pseudo)); - } else { - necessary_prefixes.none = true; - } - - return necessary_prefixes; - }, - .negation => |selectors| { - var necessary_prefixes = downlevelSelectors(allocator, selectors, targets); - - // Downlevel :not(.a, .b) -> :not(:is(.a, .b)) if not list is unsupported. - // We need to use :is() / :-webkit-any() rather than :not(.a):not(.b) to ensure the specificity is equivalent. - // https://drafts.csswg.org/selectors/#specificity-rules - if (selectors.len > 1 and css.targets.Targets.shouldCompileSame(&targets, .not_selector_list)) { - const is: Selector = Selector.fromComponent(allocator, Component{ .is = selectors: { - const new_selectors = bun.handleOom(allocator.alloc(Selector, selectors.len)); - for (new_selectors, selectors) |*new, *sel| { - new.* = sel.deepClone(allocator); - } - break :selectors new_selectors; - } }); - var list = bun.handleOom(ArrayList(Selector).initCapacity(allocator, 1)); - list.appendAssumeCapacity(is); - component.* = .{ .negation = list.items }; - - if (targets.shouldCompileSame(.is_selector)) { - bun.bits.insert(css.VendorPrefix, &necessary_prefixes, targets.prefixes(css.VendorPrefix{ .none = true }, .any_pseudo)); - } else { - bun.bits.insert(css.VendorPrefix, &necessary_prefixes, css.VendorPrefix{ .none = true }); - } - } - - return necessary_prefixes; - }, - .where, .has => |s| downlevelSelectors(allocator, s, targets), - .any => |*a| downlevelSelectors(allocator, a.selectors, targets), - else => css.VendorPrefix{}, - }; -} - -const RTL_LANGS: []const []const u8 = &.{ - "ae", "ar", "arc", "bcc", "bqi", "ckb", "dv", "fa", "glk", "he", "ku", "mzn", "nqo", "pnb", "ps", "sd", "ug", - "ur", "yi", -}; - -fn downlevelDir(allocator: Allocator, dir: parser.Direction, targets: css.targets.Targets) Component { - // Convert :dir to :lang. If supported, use a list of languages in a single :lang, - // otherwise, use :is/:not, which may be further downleveled to e.g. :-webkit-any. - if (!targets.shouldCompileSame(.lang_selector_list)) { - const c = Component{ - .non_ts_pseudo_class = PseudoClass{ - .lang = .{ .languages = lang: { - var list = bun.handleOom(ArrayList([]const u8).initCapacity(allocator, RTL_LANGS.len)); - list.appendSliceAssumeCapacity(RTL_LANGS); - break :lang list; - } }, - }, - }; - if (dir == .ltr) return Component{ - .negation = negation: { - var list = bun.handleOom(allocator.alloc(Selector, 1)); - list[0] = Selector.fromComponent(allocator, c); - break :negation list; - }, - }; - return c; - } else { - if (dir == .ltr) return Component{ .negation = langListToSelectors(allocator, RTL_LANGS) }; - return Component{ .is = langListToSelectors(allocator, RTL_LANGS) }; - } -} - -fn langListToSelectors(allocator: Allocator, langs: []const []const u8) []Selector { - var selectors = bun.handleOom(allocator.alloc(Selector, langs.len)); - for (langs, selectors[0..]) |lang, *sel| { - sel.* = Selector.fromComponent(allocator, Component{ - .non_ts_pseudo_class = PseudoClass{ - .lang = .{ .languages = langs: { - var list = bun.handleOom(ArrayList([]const u8).initCapacity(allocator, 1)); - list.appendAssumeCapacity(lang); - break :langs list; - } }, - }, - }); - } - return selectors; -} - -/// Returns the vendor prefix (if any) used in the given selector list. -/// If multiple vendor prefixes are seen, this is invalid, and an empty result is returned. -pub fn getPrefix(selectors: *const SelectorList) css.VendorPrefix { - var prefix = css.VendorPrefix{}; - for (selectors.v.slice()) |*selector| { - for (selector.components.items) |*component_| { - const component: *const Component = component_; - const p = switch (component.*) { - // Return none rather than empty for these so that we call downlevel_selectors. - .non_ts_pseudo_class => |*pc| switch (pc.*) { - .lang => css.VendorPrefix{ .none = true }, - .dir => css.VendorPrefix{ .none = true }, - else => pc.getPrefix(), - }, - .is => css.VendorPrefix{ .none = true }, - .where => css.VendorPrefix{ .none = true }, - .has => css.VendorPrefix{ .none = true }, - .negation => css.VendorPrefix{ .none = true }, - .any => |*any| any.vendor_prefix, - .pseudo_element => |*pe| pe.getPrefix(), - else => css.VendorPrefix{}, - }; - - if (!p.isEmpty()) { - // Allow none to be mixed with a prefix. - var prefix_without_none = prefix; - prefix_without_none.none = false; - if (prefix_without_none.isEmpty() or prefix_without_none == p) { - bun.bits.insert(css.VendorPrefix, &prefix, p); - } else { - return css.VendorPrefix{}; - } - } - } - } - - return prefix; -} - -pub fn isCompatible(selectors: []const parser.Selector, targets: css.targets.Targets) bool { - const F = css.compat.Feature; - for (selectors) |*selector| { - for (selector.components.items) |*component| { - const feature = switch (component.*) { - .id, .class, .local_name => continue, - - .explicit_any_namespace, - .explicit_no_namespace, - .default_namespace, - .namespace, - => F.namespaces, - - .explicit_universal_type => F.selectors2, - - .attribute_in_no_namespace_exists => F.selectors2, - - .attribute_in_no_namespace => |x| brk: { - if (x.case_sensitivity != parser.attrs.ParsedCaseSensitivity.case_sensitive) break :brk F.case_insensitive; - break :brk switch (x.operator) { - .equal, .includes, .dash_match => F.selectors2, - .prefix, .substring, .suffix => F.selectors3, - }; - }, - - .attribute_other => |attr| switch (attr.operation) { - .exists => F.selectors2, - .with_value => |*x| brk: { - if (x.case_sensitivity != parser.attrs.ParsedCaseSensitivity.case_sensitive) break :brk F.case_insensitive; - - break :brk switch (x.operator) { - .equal, .includes, .dash_match => F.selectors2, - .prefix, .substring, .suffix => F.selectors3, - }; - }, - }, - - .empty, .root => F.selectors3, - .negation => |sels| { - // :not() selector list is not forgiving. - if (!targets.isCompatible(F.selectors3) or !isCompatible(sels, targets)) return false; - continue; - }, - - .nth => |*data| brk: { - if (data.ty == .child and data.a == 0 and data.b == 1) break :brk F.selectors2; - if (data.ty == .col or data.ty == .last_col) return false; - break :brk F.selectors3; - }, - .nth_of => |*n| { - if (!targets.isCompatible(F.nth_child_of) or !isCompatible(n.selectors, targets)) return false; - continue; - }, - - // These support forgiving selector lists, so no need to check nested selectors. - .is => |sels| brk: { - // ... except if we are going to unwrap them. - if (shouldUnwrapIs(sels) and isCompatible(sels, targets)) continue; - break :brk F.is_selector; - }, - .where, .nesting => F.is_selector, - .any => return false, - .has => |sels| { - if (!targets.isCompatible(F.has_selector) or !isCompatible(sels, targets)) return false; - continue; - }, - - .scope, .host, .slotted => F.shadowdomv1, - - .part => F.part_pseudo, - - .non_ts_pseudo_class => |*pseudo| brk: { - switch (pseudo.*) { - .link, .visited, .active, .hover, .focus, .lang => break :brk F.selectors2, - - .checked, .disabled, .enabled, .target => break :brk F.selectors3, - - .any_link => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.any_link; - }, - .indeterminate => break :brk F.indeterminate_pseudo, - - .fullscreen => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.fullscreen; - }, - - .focus_visible => break :brk F.focus_visible, - .focus_within => break :brk F.focus_within, - .default => break :brk F.default_pseudo, - .dir => break :brk F.dir_selector, - .optional => break :brk F.optional_pseudo, - .placeholder_shown => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.placeholder_shown; - }, - - inline .read_only, .read_write => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.read_only_write; - }, - - .valid, .invalid, .required => break :brk F.form_validation, - .in_range, .out_of_range => break :brk F.in_out_of_range, - - .autofill => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.autofill; - }, - - // Experimental, no browser support. - .current, - .past, - .future, - .playing, - .paused, - .seeking, - .stalled, - .buffering, - .muted, - .volume_locked, - .target_within, - .local_link, - .blank, - .user_invalid, - .user_valid, - .defined, - => return false, - - .custom => {}, - - else => {}, - } - return false; - }, - - .pseudo_element => |*pseudo| brk: { - switch (pseudo.*) { - .after, .before => break :brk F.gencontent, - .first_line => break :brk F.first_line, - .first_letter => break :brk F.first_letter, - .selection => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.selection; - }, - .placeholder => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.placeholder; - }, - .marker => break :brk F.marker_pseudo, - .backdrop => |prefix| { - if (prefix == css.VendorPrefix{ .none = true }) break :brk F.dialog; - }, - .cue => break :brk F.cue, - .cue_function => break :brk F.cue_function, - .custom => return false, - else => {}, - } - return false; - }, - - .combinator => |*combinator| brk: { - break :brk switch (combinator.*) { - .child, .next_sibling => F.selectors2, - .later_sibling => F.selectors3, - else => continue, - }; - }, - }; - - if (!targets.isCompatible(feature)) return false; - } - } - - return true; -} - -/// Determines whether a selector list contains only unused selectors. -/// A selector is considered unused if it contains a class or id component that exists in the set of unused symbols. -pub fn isUnused( - selectors: []const parser.Selector, - unused_symbols: *const std.StringArrayHashMapUnmanaged(void), - symbols: *const css.SymbolList, - parent_is_unused: bool, -) bool { - if (unused_symbols.count() == 0) return false; - - for (selectors) |*selector| { - if (!isSelectorUnused(selector, unused_symbols, symbols, parent_is_unused)) return false; - } - - return true; -} - -fn isSelectorUnused( - selector: *const parser.Selector, - unused_symbols: *const std.StringArrayHashMapUnmanaged(void), - symbols: *const css.SymbolList, - parent_is_unused: bool, -) bool { - for (selector.components.items) |*component| { - switch (component.*) { - .class, .id => |ident| { - const actual_ident = ident.asOriginalString(symbols); - if (unused_symbols.contains(actual_ident)) return true; - }, - .is, .where => |is| { - if (isUnused(is, unused_symbols, symbols, parent_is_unused)) return true; - }, - .any => |any| { - if (isUnused(any.selectors, unused_symbols, symbols, parent_is_unused)) return true; - }, - .nesting => { - if (parent_is_unused) return true; - }, - else => {}, - } - } - return false; -} - -/// The serialization module ported from lightningcss. -/// -/// Note that we have two serialization modules, one from lightningcss and one from servo. -/// -/// This is because it actually uses both implementations. This is confusing. -pub const serialize = struct { - pub fn serializeSelectorList( - list: []const parser.Selector, - dest: *Printer, - context: ?*const css.StyleContext, - is_relative: bool, - ) PrintErr!void { - var first = true; - for (list) |*selector| { - if (!first) { - try dest.delim(',', false); - } - first = false; - try serializeSelector(selector, dest, context, is_relative); - } - } - - pub fn serializeSelector( - selector: *const parser.Selector, - dest: *css.Printer, - context: ?*const css.StyleContext, - __is_relative: bool, - ) PrintErr!void { - var is_relative = __is_relative; - - if (comptime bun.Environment.isDebug) { - debug("Selector components:\n", .{}); - for (selector.components.items) |*comp| { - debug(" {f}\n", .{comp}); - } - - debug("Compound selector iter\n", .{}); - var compound_selectors = CompoundSelectorIter{ .sel = selector }; - while (compound_selectors.next()) |comp| { - for (comp) |c| { - debug(" {f}, ", .{c}); - } - } - debug("\n", .{}); - } - - // Compound selectors invert the order of their contents, so we need to - // undo that during serialization. - // - // This two-iterator strategy involves walking over the selector twice. - // We could do something more clever, but selector serialization probably - // isn't hot enough to justify it, and the stringification likely - // dominates anyway. - // - // NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(), - // which we need for |split|. So we split by combinators on a match-order - // sequence and then reverse. - var combinators = CombinatorIter{ .sel = selector }; - var compound_selectors = CompoundSelectorIter{ .sel = selector }; - const should_compile_nesting = dest.targets.shouldCompileSame(.nesting); - - var first = true; - var combinators_exhausted = false; - while (compound_selectors.next()) |_compound_| { - bun.debugAssert(!combinators_exhausted); - var compound = _compound_; - - // Skip implicit :scope in relative selectors (e.g. :has(:scope > foo) -> :has(> foo)) - if (is_relative and compound.len >= 1 and compound[0] == .scope) { - if (combinators.next()) |*combinator| { - try serializeCombinator(combinator, dest); - } - compound = compound[1..]; - is_relative = false; - } - - // https://drafts.csswg.org/cssom/#serializing-selectors - if (compound.len == 0) continue; - - const has_leading_nesting = first and compound[0] == .nesting; - const first_index: usize = if (has_leading_nesting) 1 else 0; - first = false; - - // 1. If there is only one simple selector in the compound selectors - // which is a universal selector, append the result of - // serializing the universal selector to s. - // - // Check if `!compound{}` first--this can happen if we have - // something like `... > ::before`, because we store `>` and `::` - // both as combinators internally. - // - // If we are in this case, after we have serialized the universal - // selector, we skip Step 2 and continue with the algorithm. - const can_elide_namespace, const first_non_namespace = if (first_index >= compound.len) - .{ true, first_index } - else switch (compound[0]) { - .explicit_any_namespace, .explicit_no_namespace, .namespace => .{ false, first_index + 1 }, - .default_namespace => .{ true, first_index + 1 }, - else => .{ true, first_index }, - }; - var perform_step_2 = true; - const next_combinator = combinators.next(); - if (first_non_namespace == compound.len - 1) { - // We have to be careful here, because if there is a - // pseudo element "combinator" there isn't really just - // the one simple selector. Technically this compound - // selector contains the pseudo element selector as well - // -- Combinator::PseudoElement, just like - // Combinator::SlotAssignment, don't exist in the - // spec. - if (next_combinator == .pseudo_element and compound[first_non_namespace].asCombinator() == .slot_assignment) { - // do nothing - } else if (compound[first_non_namespace] == .explicit_universal_type) { - // Iterate over everything so we serialize the namespace - // too. - const swap_nesting = has_leading_nesting and should_compile_nesting; - const slice = if (swap_nesting) brk: { - // Swap nesting and type selector (e.g. &div -> div&). - break :brk compound[@min(1, compound.len)..]; - } else compound; - - for (slice) |*simple| { - try serializeComponent(simple, dest, context); - } - - if (swap_nesting) { - try serializeNesting(dest, context, false); - } - - // Skip step 2, which is an "otherwise". - perform_step_2 = false; - } else { - // do nothing - } - } - - // 2. Otherwise, for each simple selector in the compound selectors - // that is not a universal selector of which the namespace prefix - // maps to a namespace that is not the default namespace - // serialize the simple selector and append the result to s. - // - // See https://github.com/w3c/csswg-drafts/issues/1606, which is - // proposing to change this to match up with the behavior asserted - // in cssom/serialize-namespaced-type-selectors.html, which the - // following code tries to match. - if (perform_step_2) { - const iter = compound; - var i: usize = 0; - if (has_leading_nesting and - should_compile_nesting and - isTypeSelector(if (first_non_namespace < compound.len) &compound[first_non_namespace] else null)) - { - // Swap nesting and type selector (e.g. &div -> div&). - // This ensures that the compiled selector is valid. e.g. (div.foo is valid, .foodiv is not). - const nesting = &iter[i]; - i += 1; - const local = &iter[i]; - i += 1; - try serializeComponent(local, dest, context); - - // Also check the next item in case of namespaces. - if (first_non_namespace > first_index) { - const local2 = &iter[i]; - i += 1; - try serializeComponent(local2, dest, context); - } - - try serializeComponent(nesting, dest, context); - } else if (has_leading_nesting and should_compile_nesting) { - // Nesting selector may serialize differently if it is leading, due to type selectors. - i += 1; - try serializeNesting(dest, context, true); - } - - if (i < compound.len) { - for (iter[i..]) |*simple| { - if (simple.* == .explicit_universal_type) { - // Can't have a namespace followed by a pseudo-element - // selector followed by a universal selector in the same - // compound selector, so we don't have to worry about the - // real namespace being in a different `compound`. - if (can_elide_namespace) { - continue; - } - } - try serializeComponent(simple, dest, context); - } - } - } - - // 3. If this is not the last part of the chain of the selector - // append a single SPACE (U+0020), followed by the combinator - // ">", "+", "~", ">>", "||", as appropriate, followed by another - // single SPACE (U+0020) if the combinator was not whitespace, to - // s. - if (next_combinator) |*c| { - try serializeCombinator(c, dest); - } else { - combinators_exhausted = true; - } - - // 4. If this is the last part of the chain of the selector and - // there is a pseudo-element, append "::" followed by the name of - // the pseudo-element, to s. - // - // (we handle this above) - } - } - - pub fn serializeComponent( - component: *const parser.Component, - dest: *css.Printer, - context: ?*const css.StyleContext, - ) PrintErr!void { - switch (component.*) { - .combinator => |c| return serializeCombinator(&c, dest), - .attribute_in_no_namespace => |*v| { - try dest.writeChar('['); - try css.css_values.ident.IdentFns.toCss(&v.local_name, dest); - try v.operator.toCss(dest); - - if (dest.minify) { - // PERF: should we put a scratch buffer in the printer - // Serialize as both an identifier and a string and choose the shorter one. - var id = std.Io.Writer.Allocating.init(dest.allocator); - const writer = &id.writer; - css.serializer.serializeIdentifier(v.value, writer) catch return dest.addFmtError(); - - const s = try css.to_css.string(dest.allocator, CSSString, &v.value, css.PrinterOptions.default(), dest.import_info, dest.local_names, dest.symbols); - - const id_items = id.written(); - if (id_items.len > 0 and id_items.len < s.len) { - try dest.writeStr(id_items); - } else { - try dest.writeStr(s); - } - } else { - try css.CSSStringFns.toCss(&v.value, dest); - } - - switch (v.case_sensitivity) { - .case_sensitive, .ascii_case_insensitive_if_in_html_element_in_html_document => {}, - .ascii_case_insensitive => try dest.writeStr(" i"), - .explicit_case_sensitive => try dest.writeStr(" s"), - } - return dest.writeChar(']'); - }, - .is, .where, .negation, .any => { - switch (component.*) { - .where => try dest.writeStr(":where("), - .is => |selectors| { - // If there's only one simple selector, serialize it directly. - if (shouldUnwrapIs(selectors)) { - return serializeSelector(&selectors[0], dest, context, false); - } - - const vp = dest.vendor_prefix; - if (vp.webkit or vp.moz) { - try dest.writeChar(':'); - try vp.toCss(dest); - try dest.writeStr("any("); - } else { - try dest.writeStr(":is("); - } - }, - .negation => { - try dest.writeStr(":not("); - }, - .any => |v| { - const vp = dest.vendor_prefix._or(v.vendor_prefix); - if (vp.webkit or vp.moz) { - try dest.writeChar(':'); - try vp.toCss(dest); - try dest.writeStr("any("); - } else { - try dest.writeStr(":is("); - } - }, - else => unreachable, - } - try serializeSelectorList(switch (component.*) { - .where, .is, .negation => |list| list, - .any => |v| v.selectors, - else => unreachable, - }, dest, context, false); - return dest.writeStr(")"); - }, - .has => |list| { - try dest.writeStr(":has("); - try serializeSelectorList(list, dest, context, true); - return dest.writeStr(")"); - }, - .non_ts_pseudo_class => |*pseudo| { - return serializePseudoClass(pseudo, dest, context); - }, - .pseudo_element => |*pseudo| { - return serializePseudoElement(pseudo, dest, context); - }, - .nesting => { - return serializeNesting(dest, context, false); - }, - .class => |class| { - try dest.writeChar('.'); - return dest.writeIdentOrRef(class, dest.css_module != null); - }, - .id => |id| { - try dest.writeChar('#'); - return dest.writeIdentOrRef(id, dest.css_module != null); - }, - .host => |selector| { - try dest.writeStr(":host"); - if (selector) |*sel| { - try dest.writeChar('('); - try serializeSelector(sel, dest, dest.context(), false); - try dest.writeChar(')'); - } - return; - }, - .slotted => |*selector| { - try dest.writeStr("::slotted("); - try serializeSelector(selector, dest, dest.context(), false); - try dest.writeChar(')'); - }, - // .nth => |nth_data| { - // try nth_data.writeStart(dest, nth_data.isFunction()); - // if (nth_data.isFunction()) { - // try nth_data.writeAffine(dest); - // try dest.writeChar(')'); - // } - // }, - - else => { - try tocss_servo.toCss_Component(component, dest); - }, - } - } - - pub fn serializeCombinator( - combinator: *const parser.Combinator, - dest: *Printer, - ) PrintErr!void { - switch (combinator.*) { - .child => try dest.delim('>', true), - .descendant => try dest.writeStr(" "), - .next_sibling => try dest.delim('+', true), - .later_sibling => try dest.delim('~', true), - .deep => try dest.writeStr(" /deep/ "), - .deep_descendant => { - try dest.whitespace(); - try dest.writeStr(">>>"); - try dest.whitespace(); - }, - .pseudo_element, .part, .slot_assignment => return, - } - } - - pub fn serializePseudoClass( - pseudo_class: *const parser.PseudoClass, - dest: *Printer, - context: ?*const css.StyleContext, - ) PrintErr!void { - switch (pseudo_class.*) { - .lang => { - try dest.writeStr(":lang("); - var first = true; - for (pseudo_class.lang.languages.items) |lang| { - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - css.serializer.serializeIdentifier(lang, dest) catch return dest.addFmtError(); - } - return dest.writeStr(")"); - }, - .dir => { - const dir = pseudo_class.dir.direction; - try dest.writeStr(":dir("); - try dir.toCss(dest); - return try dest.writeStr(")"); - }, - else => {}, - } - - const Helpers = struct { - pub inline fn writePrefixed( - d: *Printer, - prefix: css.VendorPrefix, - comptime val: []const u8, - ) PrintErr!void { - try d.writeChar(':'); - // If the printer has a vendor prefix override, use that. - const vp = if (!d.vendor_prefix.isEmpty()) - bun.bits.@"or"(css.VendorPrefix, d.vendor_prefix, prefix).orNone() - else - prefix; - - try vp.toCss(d); - try d.writeStr(val); - } - pub inline fn pseudo( - d: *Printer, - comptime key: []const u8, - comptime s: []const u8, - ) PrintErr!void { - const key_snake_case = comptime key_snake_case: { - var buf: [key.len]u8 = undefined; - for (key, 0..) |c, i| { - buf[i] = if (c >= 'A' and c <= 'Z') c + 32 else if (c == '-') '_' else c; - } - const buf2 = buf; - break :key_snake_case buf2; - }; - const _class = if (d.pseudo_classes) |*pseudo_classes| @field(pseudo_classes, &key_snake_case) else null; - - if (_class) |class| { - try d.writeChar('.'); - try d.writeIdent(class, true); - } else { - try d.writeStr(s); - } - } - }; - - switch (pseudo_class.*) { - // https://drafts.csswg.org/selectors-4/#useraction-pseudos - .hover => try Helpers.pseudo(dest, "hover", ":hover"), - .active => try Helpers.pseudo(dest, "active", ":active"), - .focus => try Helpers.pseudo(dest, "focus", ":focus"), - .focus_visible => try Helpers.pseudo(dest, "focus-visible", ":focus-visible"), - .focus_within => try Helpers.pseudo(dest, "focus-within", ":focus-within"), - - // https://drafts.csswg.org/selectors-4/#time-pseudos - .current => try dest.writeStr(":current"), - .past => try dest.writeStr(":past"), - .future => try dest.writeStr(":future"), - - // https://drafts.csswg.org/selectors-4/#resource-pseudos - .playing => try dest.writeStr(":playing"), - .paused => try dest.writeStr(":paused"), - .seeking => try dest.writeStr(":seeking"), - .buffering => try dest.writeStr(":buffering"), - .stalled => try dest.writeStr(":stalled"), - .muted => try dest.writeStr(":muted"), - .volume_locked => try dest.writeStr(":volume-locked"), - - // https://fullscreen.spec.whatwg.org/#:fullscreen-pseudo-class - .fullscreen => |prefix| { - try dest.writeChar(':'); - const vp = if (!dest.vendor_prefix.isEmpty()) - bits.@"and"(css.VendorPrefix, dest.vendor_prefix, prefix).orNone() - else - prefix; - try vp.toCss(dest); - if (vp.webkit or vp.moz) { - try dest.writeStr("full-screen"); - } else { - try dest.writeStr("fullscreen"); - } - }, - - // https://drafts.csswg.org/selectors/#display-state-pseudos - .open => try dest.writeStr(":open"), - .closed => try dest.writeStr(":closed"), - .modal => try dest.writeStr(":modal"), - .picture_in_picture => try dest.writeStr(":picture-in-picture"), - - // https://html.spec.whatwg.org/multipage/semantics-other.html#selector-popover-open - .popover_open => try dest.writeStr(":popover-open"), - - // https://drafts.csswg.org/selectors-4/#the-defined-pseudo - .defined => try dest.writeStr(":defined"), - - // https://drafts.csswg.org/selectors-4/#location - .any_link => |prefix| try Helpers.writePrefixed(dest, prefix, "any-link"), - .link => try dest.writeStr(":link"), - .local_link => try dest.writeStr(":local-link"), - .target => try dest.writeStr(":target"), - .target_within => try dest.writeStr(":target-within"), - .visited => try dest.writeStr(":visited"), - - // https://drafts.csswg.org/selectors-4/#input-pseudos - .enabled => try dest.writeStr(":enabled"), - .disabled => try dest.writeStr(":disabled"), - .read_only => |prefix| try Helpers.writePrefixed(dest, prefix, "read-only"), - .read_write => |prefix| try Helpers.writePrefixed(dest, prefix, "read-write"), - .placeholder_shown => |prefix| try Helpers.writePrefixed(dest, prefix, "placeholder-shown"), - .default => try dest.writeStr(":default"), - .checked => try dest.writeStr(":checked"), - .indeterminate => try dest.writeStr(":indeterminate"), - .blank => try dest.writeStr(":blank"), - .valid => try dest.writeStr(":valid"), - .invalid => try dest.writeStr(":invalid"), - .in_range => try dest.writeStr(":in-range"), - .out_of_range => try dest.writeStr(":out-of-range"), - .required => try dest.writeStr(":required"), - .optional => try dest.writeStr(":optional"), - .user_valid => try dest.writeStr(":user-valid"), - .user_invalid => try dest.writeStr(":user-invalid"), - - // https://html.spec.whatwg.org/multipage/semantics-other.html#selector-autofill - .autofill => |prefix| try Helpers.writePrefixed(dest, prefix, "autofill"), - - .local => |selector| try serializeSelector(selector.selector, dest, context, false), - .global => |selector| { - const css_module = if (dest.css_module) |module| css_module: { - dest.css_module = null; - break :css_module module; - } else null; - try serializeSelector(selector.selector, dest, context, false); - dest.css_module = css_module; - }, - - // https://webkit.org/blog/363/styling-scrollbars/ - .webkit_scrollbar => |s| { - try dest.writeStr(switch (s) { - .horizontal => ":horizontal", - .vertical => ":vertical", - .decrement => ":decrement", - .increment => ":increment", - .start => ":start", - .end => ":end", - .double_button => ":double-button", - .single_button => ":single-button", - .no_button => ":no-button", - .corner_present => ":corner-present", - .window_inactive => ":window-inactive", - }); - }, - - .lang => unreachable, - .dir => unreachable, - .custom => |name| { - try dest.writeChar(':'); - return dest.writeStr(name.name); - }, - .custom_function => |v| { - try dest.writeChar(':'); - try dest.writeStr(v.name); - try dest.writeChar('('); - try v.arguments.toCssRaw(dest); - try dest.writeChar(')'); - }, - } - } - - pub fn serializePseudoElement( - pseudo_element: *const parser.PseudoElement, - dest: *Printer, - context: ?*const css.StyleContext, - ) PrintErr!void { - const Helpers = struct { - pub fn writePrefix(d: *Printer, prefix: css.VendorPrefix) PrintErr!css.VendorPrefix { - try d.writeStr("::"); - // If the printer has a vendor prefix override, use that. - const vp = if (!d.vendor_prefix.isEmpty()) - bits.@"and"(css.VendorPrefix, d.vendor_prefix, prefix).orNone() - else - prefix; - try vp.toCss(d); - debug("VENDOR PREFIX {d} OVERRIDE {d}", .{ vp.asBits(), d.vendor_prefix.asBits() }); - return vp; - } - - pub fn writePrefixed(d: *Printer, prefix: css.VendorPrefix, comptime val: []const u8) PrintErr!void { - _ = try writePrefix(d, prefix); - try d.writeStr(val); - } - }; - // switch (pseudo_element.*) { - // // CSS2 pseudo elements support a single colon syntax in addition - // // to the more correct double colon for other pseudo elements. - // // We use that here because it's supported everywhere and is shorter. - // .after => try dest.writeStr(":after"), - // .before => try dest.writeStr(":before"), - // .marker => try dest.writeStr(":first-letter"), - // .selection => |prefix| Helpers.writePrefixed(dest, prefix, "selection"), - // .cue => dest.writeStr("::cue"), - // .cue_region => dest.writeStr("::cue-region"), - // .cue_function => |v| { - // dest.writeStr("::cue("); - // try serializeSelector(v.selector, dest, context, false); - // try dest.writeChar(')'); - // }, - // } - switch (pseudo_element.*) { - // CSS2 pseudo elements support a single colon syntax in addition - // to the more correct double colon for other pseudo elements. - // We use that here because it's supported everywhere and is shorter. - .after => try dest.writeStr(":after"), - .before => try dest.writeStr(":before"), - .first_line => try dest.writeStr(":first-line"), - .first_letter => try dest.writeStr(":first-letter"), - .marker => try dest.writeStr("::marker"), - .selection => |prefix| try Helpers.writePrefixed(dest, prefix, "selection"), - .cue => try dest.writeStr("::cue"), - .cue_region => try dest.writeStr("::cue-region"), - .cue_function => |v| { - try dest.writeStr("::cue("); - try serializeSelector(v.selector, dest, context, false); - try dest.writeChar(')'); - }, - .cue_region_function => |v| { - try dest.writeStr("::cue-region("); - try serializeSelector(v.selector, dest, context, false); - try dest.writeChar(')'); - }, - .placeholder => |prefix| { - const vp = try Helpers.writePrefix(dest, prefix); - if (vp.webkit or vp.ms) { - try dest.writeStr("input-placeholder"); - } else { - try dest.writeStr("placeholder"); - } - }, - .backdrop => |prefix| try Helpers.writePrefixed(dest, prefix, "backdrop"), - .file_selector_button => |prefix| { - const vp = try Helpers.writePrefix(dest, prefix); - if (vp.webkit) { - try dest.writeStr("file-upload-button"); - } else if (vp.ms) { - try dest.writeStr("browse"); - } else { - try dest.writeStr("file-selector-button"); - } - }, - .webkit_scrollbar => |s| { - try dest.writeStr(switch (s) { - .scrollbar => "::-webkit-scrollbar", - .button => "::-webkit-scrollbar-button", - .track => "::-webkit-scrollbar-track", - .track_piece => "::-webkit-scrollbar-track-piece", - .thumb => "::-webkit-scrollbar-thumb", - .corner => "::-webkit-scrollbar-corner", - .resizer => "::-webkit-resizer", - }); - }, - .view_transition => try dest.writeStr("::view-transition"), - .view_transition_group => |v| { - try dest.writeStr("::view-transition-group("); - try v.part_name.toCss(dest); - try dest.writeChar(')'); - }, - .view_transition_image_pair => |v| { - try dest.writeStr("::view-transition-image-pair("); - try v.part_name.toCss(dest); - try dest.writeChar(')'); - }, - .view_transition_old => |v| { - try dest.writeStr("::view-transition-old("); - try v.part_name.toCss(dest); - try dest.writeChar(')'); - }, - .view_transition_new => |v| { - try dest.writeStr("::view-transition-new("); - try v.part_name.toCss(dest); - try dest.writeChar(')'); - }, - .custom => |val| { - try dest.writeStr("::"); - return dest.writeStr(val.name); - }, - .custom_function => |v| { - const name = v.name; - try dest.writeStr("::"); - try dest.writeStr(name); - try dest.writeChar('('); - try v.arguments.toCssRaw(dest); - try dest.writeChar(')'); - }, - } - } - - pub fn serializeNesting( - dest: *Printer, - context: ?*const css.StyleContext, - first: bool, - ) PrintErr!void { - if (context) |ctx| { - // If there's only one simple selector, just serialize it directly. - // Otherwise, use an :is() pseudo class. - // Type selectors are only allowed at the start of a compound selector, - // so use :is() if that is not the case. - if (ctx.selectors.v.len() == 1 and - (first or (!hasTypeSelector(ctx.selectors.v.at(0)) and - isSimple(ctx.selectors.v.at(0))))) - { - try serializeSelector(ctx.selectors.v.at(0), dest, ctx.parent, false); - } else { - try dest.writeStr(":is("); - try serializeSelectorList(ctx.selectors.v.slice(), dest, ctx.parent, false); - try dest.writeChar(')'); - } - } else { - // If there is no context, we are at the root if nesting is supported. This is equivalent to :scope. - // Otherwise, if nesting is supported, serialize the nesting selector directly. - if (dest.targets.shouldCompileSame(.nesting)) { - try dest.writeStr(":scope"); - } else { - try dest.writeChar('&'); - } - } - } -}; - -pub const tocss_servo = struct { - pub fn toCss_SelectorList( - selectors: []const parser.Selector, - dest: *css.Printer, - ) PrintErr!void { - if (selectors.len == 0) { - return; - } - - try tocss_servo.toCss_Selector(&selectors[0], dest); - - if (selectors.len > 1) { - for (selectors[1..]) |*selector| { - try dest.writeStr(", "); - try tocss_servo.toCss_Selector(selector, dest); - } - } - } - - pub fn toCss_Selector( - selector: *const parser.Selector, - dest: *css.Printer, - ) PrintErr!void { - // Compound selectors invert the order of their contents, so we need to - // undo that during serialization. - // - // This two-iterator strategy involves walking over the selector twice. - // We could do something more clever, but selector serialization probably - // isn't hot enough to justify it, and the stringification likely - // dominates anyway. - // - // NB: A parse-order iterator is a Rev<>, which doesn't expose as_slice(), - // which we need for |split|. So we split by combinators on a match-order - // sequence and then reverse. - var combinators = CombinatorIter{ .sel = selector }; - var compound_selectors = CompoundSelectorIter{ .sel = selector }; - - var combinators_exhausted = false; - while (compound_selectors.next()) |compound| { - bun.debugAssert(!combinators_exhausted); - - // https://drafts.csswg.org/cssom/#serializing-selectors - if (compound.len == 0) continue; - - // 1. If there is only one simple selector in the compound selectors - // which is a universal selector, append the result of - // serializing the universal selector to s. - // - // Check if `!compound{}` first--this can happen if we have - // something like `... > ::before`, because we store `>` and `::` - // both as combinators internally. - // - // If we are in this case, after we have serialized the universal - // selector, we skip Step 2 and continue with the algorithm. - const can_elide_namespace, const first_non_namespace: usize = if (0 >= compound.len) - .{ true, 0 } - else switch (compound[0]) { - .explicit_any_namespace, .explicit_no_namespace, .namespace => .{ false, 1 }, - .default_namespace => .{ true, 1 }, - else => .{ true, 0 }, - }; - var perform_step_2 = true; - const next_combinator = combinators.next(); - if (first_non_namespace == compound.len - 1) { - // We have to be careful here, because if there is a - // pseudo element "combinator" there isn't really just - // the one simple selector. Technically this compound - // selector contains the pseudo element selector as well - // -- Combinator::PseudoElement, just like - // Combinator::SlotAssignment, don't exist in the - // spec. - if (next_combinator == .pseudo_element and compound[first_non_namespace].asCombinator() == .slot_assignment) { - // do nothing - } else if (compound[first_non_namespace] == .explicit_universal_type) { - // Iterate over everything so we serialize the namespace - // too. - for (compound) |*simple| { - try tocss_servo.toCss_Component(simple, dest); - } - // Skip step 2, which is an "otherwise". - perform_step_2 = false; - } else { - // do nothing - } - } - - // 2. Otherwise, for each simple selector in the compound selectors - // that is not a universal selector of which the namespace prefix - // maps to a namespace that is not the default namespace - // serialize the simple selector and append the result to s. - // - // See https://github.com/w3c/csswg-drafts/issues/1606, which is - // proposing to change this to match up with the behavior asserted - // in cssom/serialize-namespaced-type-selectors.html, which the - // following code tries to match. - if (perform_step_2) { - for (compound) |*simple| { - if (simple.* == .explicit_universal_type) { - // Can't have a namespace followed by a pseudo-element - // selector followed by a universal selector in the same - // compound selector, so we don't have to worry about the - // real namespace being in a different `compound`. - if (can_elide_namespace) { - continue; - } - } - try tocss_servo.toCss_Component(simple, dest); - } - } - - // 3. If this is not the last part of the chain of the selector - // append a single SPACE (U+0020), followed by the combinator - // ">", "+", "~", ">>", "||", as appropriate, followed by another - // single SPACE (U+0020) if the combinator was not whitespace, to - // s. - if (next_combinator) |c| { - try toCss_Combinator(&c, dest); - } else { - combinators_exhausted = true; - } - - // 4. If this is the last part of the chain of the selector and - // there is a pseudo-element, append "::" followed by the name of - // the pseudo-element, to s. - // - // (we handle this above) - } - } - - pub fn toCss_Component( - component: *const parser.Component, - dest: *Printer, - ) PrintErr!void { - switch (component.*) { - .combinator => |*c| try toCss_Combinator(c, dest), - .slotted => |*selector| { - try dest.writeStr("::slotted("); - try tocss_servo.toCss_Selector(selector, dest); - try dest.writeChar(')'); - }, - .part => |part_names| { - try dest.writeStr("::part("); - for (part_names, 0..) |name, i| { - if (i != 0) { - try dest.writeChar(' '); - } - try css.IdentFns.toCss(&name, dest); - } - try dest.writeChar(')'); - }, - .pseudo_element => |*p| { - try p.toCss(dest); - }, - .id => |s| { - try dest.writeChar('#'); - const str = dest.lookupIdentOrRef(s); - try dest.writeStr(str); - }, - .class => |s| { - try dest.writeChar('.'); - const str = dest.lookupIdentOrRef(s); - try dest.writeStr(str); - }, - .local_name => |local_name| { - try local_name.toCss(dest); - }, - .explicit_universal_type => { - try dest.writeChar('*'); - }, - .default_namespace => return, - - .explicit_no_namespace => { - try dest.writeChar('|'); - }, - .explicit_any_namespace => { - try dest.writeStr("*|"); - }, - .namespace => |ns| { - try css.IdentFns.toCss(&ns.prefix, dest); - try dest.writeChar('|'); - }, - .attribute_in_no_namespace_exists => |v| { - try dest.writeChar('['); - try css.IdentFns.toCss(&v.local_name, dest); - try dest.writeChar(']'); - }, - .attribute_in_no_namespace => |v| { - try dest.writeChar('['); - try css.IdentFns.toCss(&v.local_name, dest); - try v.operator.toCss(dest); - try css.CSSStringFns.toCss(&v.value, dest); - switch (v.case_sensitivity) { - .case_sensitive, .ascii_case_insensitive_if_in_html_element_in_html_document => {}, - .ascii_case_insensitive => try dest.writeStr(" i"), - .explicit_case_sensitive => try dest.writeStr(" s"), - } - try dest.writeChar(']'); - }, - .attribute_other => |attr_selector| { - try attr_selector.toCss(dest); - }, - // Pseudo-classes - .root => { - try dest.writeStr(":root"); - }, - .empty => { - try dest.writeStr(":empty"); - }, - .scope => { - try dest.writeStr(":scope"); - }, - .host => |selector| { - try dest.writeStr(":host"); - if (selector) |*sel| { - try dest.writeChar('('); - try tocss_servo.toCss_Selector(sel, dest); - try dest.writeChar(')'); - } - }, - .nth => |nth_data| { - try nth_data.writeStart(dest, nth_data.isFunction()); - if (nth_data.isFunction()) { - try nth_data.writeAffine(dest); - try dest.writeChar(')'); - } - }, - .nth_of => |nth_of_data| { - const nth_data = nth_of_data.nthData(); - try nth_data.writeStart(dest, true); - // A selector must be a function to hold An+B notation - bun.debugAssert(nth_data.is_function); - try nth_data.writeAffine(dest); - // Only :nth-child or :nth-last-child can be of a selector list - bun.debugAssert(nth_data.ty == .child or nth_data.ty == .last_child); - // The selector list should not be empty - bun.debugAssert(nth_of_data.selectors.len != 0); - try dest.writeStr(" of "); - try tocss_servo.toCss_SelectorList(nth_of_data.selectors, dest); - try dest.writeChar(')'); - }, - .is, .where, .negation, .has, .any => { - switch (component.*) { - .where => try dest.writeStr(":where("), - .is => try dest.writeStr(":is("), - .negation => try dest.writeStr(":not("), - .has => try dest.writeStr(":has("), - .any => |v| { - try dest.writeChar(':'); - try v.vendor_prefix.toCss(dest); - try dest.writeStr("any("); - }, - else => unreachable, - } - try tocss_servo.toCss_SelectorList( - switch (component.*) { - .where, .is, .negation, .has => |list| list, - .any => |v| v.selectors, - else => unreachable, - }, - dest, - ); - try dest.writeStr(")"); - }, - .non_ts_pseudo_class => |*pseudo| { - try pseudo.toCss(dest); - }, - .nesting => try dest.writeChar('&'), - } - } - - pub fn toCss_Combinator( - combinator: *const parser.Combinator, - dest: *Printer, - ) PrintErr!void { - switch (combinator.*) { - .child => try dest.writeStr(" > "), - .descendant => try dest.writeStr(" "), - .next_sibling => try dest.writeStr(" + "), - .later_sibling => try dest.writeStr(" ~ "), - .deep => try dest.writeStr(" /deep/ "), - .deep_descendant => { - try dest.writeStr(" >>> "); - }, - .pseudo_element, .part, .slot_assignment => return, - } - } - - pub fn toCss_PseudoElement( - pseudo_element: *const parser.PseudoElement, - dest: *Printer, - ) PrintErr!void { - switch (pseudo_element.*) { - .before => try dest.writeStr("::before"), - .after => try dest.writeStr("::after"), - } - } -}; - -pub fn shouldUnwrapIs(selectors: []const parser.Selector) bool { - if (selectors.len == 1) { - const first = selectors[0]; - if (!hasTypeSelector(&first) and isSimple(&first)) return true; - } - - return false; -} - -fn hasTypeSelector(selector: *const parser.Selector) bool { - var iter = selector.iterRawMatchOrder(); - const first = iter.next(); - - if (isNamespace(if (first) |*f| f else null)) return isTypeSelector(if (iter.next()) |*n| n else null); - - return isTypeSelector(if (first) |*f| f else null); -} - -fn isNamespace(component: ?*const parser.Component) bool { - if (component) |c| return switch (c.*) { - .explicit_any_namespace, .explicit_no_namespace, .namespace, .default_namespace => true, - else => false, - }; - return false; -} - -fn isTypeSelector(component: ?*const parser.Component) bool { - if (component) |c| return switch (c.*) { - .local_name, .explicit_universal_type => true, - else => false, - }; - return false; -} - -fn isSimple(selector: *const parser.Selector) bool { - var iter = selector.iterRawParseOrderFrom(0); - const any_is_combinator = any_is_combinator: { - while (iter.next()) |component| { - if (component.isCombinator()) break :any_is_combinator true; - } - break :any_is_combinator false; - }; - return !any_is_combinator; -} - -const CombinatorIter = struct { - sel: *const parser.Selector, - i: usize = 0, - - /// Original source has this iterator defined like so: - /// ```rs - /// selector - /// .iter_raw_match_order() // just returns an iterator - /// .rev() // reverses the iterator - /// .filter_map(|x| x.as_combinator()) // returns only entries which are combinators - /// ``` - pub fn next(this: *@This()) ?parser.Combinator { - while (this.i < this.sel.components.items.len) { - defer this.i += 1; - const combinator = this.sel.components.items[this.sel.components.items.len - 1 - this.i].asCombinator() orelse continue; - return combinator; - } - return null; - } -}; -const CompoundSelectorIter = struct { - sel: *const parser.Selector, - i: usize = 0, - - /// This iterator is basically like doing `selector.components.splitByCombinator()`. - /// - /// For example: - /// ```css - /// div > p.class - /// ``` - /// - /// The iterator would return: - /// ``` - /// First slice: - /// .{ - /// .{ .local_name = "div" } - /// } - /// - /// Second slice: - /// .{ - /// .{ .local_name = "p" }, - /// .{ .class = "class" } - /// } - /// ``` - /// - /// BUT, the selectors are stored in reverse order, so this code needs to split the components backwards. - /// - /// Original source has this iterator defined like so: - /// ```rs - /// selector - /// .iter_raw_match_order() - /// .as_slice() - /// .split(|x| x.is_combinator()) // splits the slice into subslices by elements that match over the predicate - /// .rev() // reverse - /// ``` - pub inline fn next(this: *@This()) ?[]const parser.Component { - // Since we iterating backwards, we convert all indices into "backwards form" by doing `this.sel.components.items.len - 1 - i` - while (this.i < this.sel.components.items.len) { - const next_index: ?usize = next_index: { - for (this.i..this.sel.components.items.len) |j| { - if (this.sel.components.items[this.sel.components.items.len - 1 - j].isCombinator()) break :next_index j; - } - break :next_index null; - }; - if (next_index) |combinator_index| { - const start = if (combinator_index == 0) 0 else combinator_index - 1; - const end = this.i; - const slice = this.sel.components.items[this.sel.components.items.len - 1 - start .. this.sel.components.items.len - end]; - this.i = combinator_index + 1; - return slice; - } - const slice = this.sel.components.items[0 .. this.sel.components.items.len - 1 - this.i + 1]; - this.i = this.sel.components.items.len; - return slice; - } - return null; - } -}; - -const bun = @import("bun"); -const bits = bun.bits; - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/small_list.zig b/src/css/small_list.zig deleted file mode 100644 index c712fb682934..000000000000 --- a/src/css/small_list.zig +++ /dev/null @@ -1,672 +0,0 @@ -/// This is a type whose items can either be heap-allocated (essentially the -/// same as a BabyList(T)) or inlined in the struct itself. -/// -/// This is type is a performance optimization for avoiding allocations, especially when you know the list -/// will commonly have N or fewer items. -/// -/// The `capacity` field is used to disambiguate between the two states: - When -/// `capacity <= N`, the items are stored inline, and `capacity` is the length -/// of the items. - When `capacity > N`, the items are stored on the heap, and -/// this type essentially becomes a BabyList(T), but with the fields reordered. -/// -/// This code is based on servo/rust-smallvec and the Zig std.ArrayList source. -pub fn SmallList(comptime T: type, comptime N: comptime_int) type { - return struct { - capacity: u32 = 0, - data: Data = .{ .inlined = undefined }, - - const Data = union { - inlined: [N]T, - heap: HeapData, - }; - - const HeapData = struct { - len: u32, - ptr: [*]T, - - pub fn initCapacity(allocator: Allocator, capacity: u32) HeapData { - return .{ - .len = 0, - .ptr = bun.handleOom(allocator.alloc(T, capacity)).ptr, - }; - } - }; - - const This = @This(); - - pub fn initInlined(values: []const T) This { - bun.assert(values.len <= N); - var this = This{ - .capacity = values.len, - .data = .{ .inlined = undefined }, - }; - - @memcpy(this.data.inlined[0..values.len], values); - - return this; - } - pub fn parse(input: *Parser) Result(@This()) { - const parseFn = comptime voidWrap(T, generic.parseFor(T)); - var values: @This() = .{}; - while (true) { - input.skipWhitespace(); - switch (input.parseUntilBefore(Delimiters{ .comma = true }, T, {}, parseFn)) { - .result => |v| { - values.append(input.allocator(), v); - }, - .err => |e| return .{ .err = e }, - } - switch (input.next()) { - .err => return .{ .result = values }, - .result => |t| { - if (t.* == .comma) continue; - std.debug.panic("Expected a comma", .{}); - }, - } - } - unreachable; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - const length = this.len(); - for (this.slice(), 0..) |*val, idx| { - try val.toCss(dest); - if (idx < length - 1) { - try dest.delim(',', false); - } - } - } - - /// NOTE: This will deinit the list - pub fn fromList(allocator: Allocator, list: std.ArrayListUnmanaged(T)) @This() { - if (list.cap > N) { - return .{ - .capacity = list.cap, - .data = .{ .heap = .{ .len = list.len, .ptr = list.ptr } }, - }; - } - defer list.deinit(allocator); - var this: @This() = .{ - .capacity = list.len, - .data = .{ .inlined = undefined }, - }; - @memcpy(this.data.inlined[0..list.len], list.items[0..list.len]); - return this; - } - - pub fn fromListNoDeinit(list: std.ArrayListUnmanaged(T)) @This() { - if (list.cap > N) { - return .{ - .capacity = list.cap, - .data = .{ .heap = .{ .len = list.len, .ptr = list.ptr } }, - }; - } - var this: @This() = .{ - .capacity = list.len, - .data = .{ .inlined = undefined }, - }; - @memcpy(this.data.inlined[0..list.len], list.items[0..list.len]); - return this; - } - - /// NOTE: This will deinit the list - pub fn fromBabyList(allocator: Allocator, list: bun.BabyList(T)) @This() { - if (list.cap > N) { - return .{ - .capacity = list.cap, - .data = .{ .heap = .{ .len = list.len, .ptr = list.ptr } }, - }; - } - var list_ = list; - defer list_.deinit(allocator); - var this: @This() = .{ - .capacity = list_.len, - .data = .{ .inlined = undefined }, - }; - @memcpy(this.data.inlined[0..list_.len], list_.items[0..list_.len]); - return this; - } - - pub fn fromBabyListNoDeinit(list: bun.BabyList(T)) @This() { - if (list.cap > N) { - return .{ - .capacity = list.cap, - .data = .{ .heap = .{ .len = list.len, .ptr = list.ptr } }, - }; - } - var this: @This() = .{ - .capacity = list.len, - .data = .{ .inlined = undefined }, - }; - @memcpy(this.data.inlined[0..list.len], list.ptr[0..list.len]); - return this; - } - - pub fn withOne(val: T) @This() { - var ret = This{}; - ret.capacity = 1; - ret.data.inlined[0] = val; - return ret; - } - - pub inline fn getLastUnchecked(this: *const @This()) T { - if (this.spilled()) return this.data.heap.ptr[this.data.heap.len - 1]; - return this.data.inlined[this.capacity - 1]; - } - - pub inline fn at(this: *const @This(), idx: u32) *const T { - return &this.as_const_ptr()[idx]; - } - - pub inline fn mut(this: *@This(), idx: u32) *T { - return &this.as_ptr()[idx]; - } - - pub inline fn last(this: *const @This()) ?*const T { - const sl = this.slice(); - if (sl.len == 0) return null; - return &sl[sl.len - 1]; - } - - pub inline fn lastMut(this: *@This()) ?*T { - const sl = this.slice_mut(); - if (sl.len == 0) return null; - return &sl[sl.len - 1]; - } - - pub inline fn toOwnedSlice(this: *const @This(), allocator: Allocator) []T { - if (this.spilled()) return this.data.heap.ptr[0..this.data.heap.len]; - return bun.handleOom(allocator.dupe(T, this.data.inlined[0..this.capacity])); - } - - /// NOTE: If this is inlined then this will refer to stack memory, if - /// need it to be stable then you should use `.toOwnedSlice()` - pub inline fn slice(this: *const @This()) []const T { - if (this.capacity > N) return this.data.heap.ptr[0..this.data.heap.len]; - return this.data.inlined[0..this.capacity]; - } - - /// NOTE: If this is inlined then this will refer to stack memory, if - /// need it to be stable then you should use `.toOwnedSlice()` - pub inline fn slice_mut(this: *@This()) []T { - if (this.capacity > N) return this.data.heap.ptr[0..this.data.heap.len]; - return this.data.inlined[0..this.capacity]; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - for (this.slice()) |*v| { - if (!v.isCompatible(browsers)) return false; - } - return true; - } - - /// For this function to be called the T here must implement the ImageFallback interface - pub fn getFallbacks(this: *@This(), allocator: Allocator, targets: css.targets.Targets) getFallbacksReturnType(T, N) { - // Implements ImageFallback interface - if (@hasDecl(T, "getImage") and N == 1) { - const ColorFallbackKind = css.css_values.color.ColorFallbackKind; - // Determine what vendor prefixes and color fallbacks are needed. - var prefixes = css.VendorPrefix{}; - var fallbacks = ColorFallbackKind{}; - var res: bun.BabyList(@This()) = .{}; - for (this.slice()) |*item| { - bun.bits.insert(css.VendorPrefix, &prefixes, item.getImage().getNecessaryPrefixes(targets)); - bun.bits.insert(css.ColorFallbackKind, &fallbacks, item.getNecessaryFallbacks(targets)); - } - - // Get RGB fallbacks if needed. - const rgb: ?SmallList(T, 1) = if (fallbacks.rgb) brk: { - var shallow_clone = this.shallowClone(allocator); - for (shallow_clone.slice_mut(), this.slice_mut()) |*out, *in| { - out.* = in.getFallback(allocator, ColorFallbackKind{ .rgb = true }); - } - break :brk shallow_clone; - } else null; - - // Prefixed properties only support RGB. - const prefix_images: *const SmallList(T, 1) = if (rgb) |*r| r else this; - - // Legacy -webkit-gradient() - if (prefixes.webkit and targets.browsers != null and css.prefixes.Feature.isWebkitGradient(targets.browsers.?)) { - const images = images: { - var images = SmallList(T, 1){}; - for (prefix_images.slice()) |*item| { - if (item.getImage().getLegacyWebkit(allocator)) |img| { - images.append(allocator, item.withImage(allocator, img)); - } - } - break :images images; - }; - if (!images.isEmpty()) { - bun.handleOom(res.append(allocator, images)); - } - } - - const prefix = struct { - pub inline fn helper(comptime prefix: []const u8, pfs: *css.VendorPrefix, pfi: *const SmallList(T, 1), r: *bun.BabyList(This), alloc: Allocator) void { - if (bun.bits.contains(css.VendorPrefix, pfs.*, .fromName(prefix))) { - var images = SmallList(T, 1).initCapacity(alloc, pfi.len()); - images.setLen(pfi.len()); - for (images.slice_mut(), pfi.slice()) |*out, *in| { - const image = in.getImage().getPrefixed(alloc, css.VendorPrefix.fromName(prefix)); - out.* = in.withImage(alloc, image); - } - bun.handleOom(r.append(alloc, images)); - } - } - }.helper; - - prefix("webkit", &prefixes, prefix_images, &res, allocator); - prefix("moz", &prefixes, prefix_images, &res, allocator); - prefix("o", &prefixes, prefix_images, &res, allocator); - - if (prefixes.none) { - if (rgb) |r| { - bun.handleOom(res.append(allocator, r)); - } - - if (fallbacks.p3) { - var p3_images = this.shallowClone(allocator); - for (p3_images.slice_mut(), this.slice_mut()) |*out, *in| { - out.* = in.getFallback(allocator, ColorFallbackKind{ .p3 = true }); - } - bun.handleOom(res.append(allocator, p3_images)); - } - - // Convert to lab if needed (e.g. if oklab is not supported but lab is). - if (fallbacks.lab) { - for (this.slice_mut()) |*item| { - var old = item.*; - item.* = item.getFallback(allocator, ColorFallbackKind{ .lab = true }); - old.deinit(allocator); - } - } - } else if (res.pop()) |the_last| { - var old = this.*; - // Prefixed property with no unprefixed version. - // Replace self with the last prefixed version so that it doesn't - // get duplicated when the caller pushes the original value. - this.* = the_last; - old.deinit(allocator); - } - return res; - } - if (T == TextShadow and N == 1) { - var fallbacks = css.ColorFallbackKind{}; - for (this.slice()) |*shadow| { - bun.bits.insert(css.ColorFallbackKind, &fallbacks, shadow.color.getNecessaryFallbacks(targets)); - } - - var res = SmallList(SmallList(TextShadow, 1), 2){}; - if (fallbacks.rgb) { - var rgb = SmallList(TextShadow, 1).initCapacity(allocator, this.len()); - for (this.slice()) |*shadow| { - var new_shadow = shadow.*; - // dummy non-alloced color to avoid deep cloning the real one since we will replace it - new_shadow.color = .current_color; - new_shadow = new_shadow.deepClone(allocator); - new_shadow.color = shadow.color.toRGB(allocator).?; - rgb.appendAssumeCapacity(new_shadow); - } - res.append(allocator, rgb); - } - - if (fallbacks.p3) { - var p3 = SmallList(TextShadow, 1).initCapacity(allocator, this.len()); - for (this.slice()) |*shadow| { - var new_shadow = shadow.*; - // dummy non-alloced color to avoid deep cloning the real one since we will replace it - new_shadow.color = .current_color; - new_shadow = new_shadow.deepClone(allocator); - new_shadow.color = shadow.color.toP3(allocator).?; - p3.appendAssumeCapacity(new_shadow); - } - res.append(allocator, p3); - } - - if (fallbacks.lab) { - for (this.slice_mut()) |*shadow| { - const out = shadow.color.toLAB(allocator).?; - shadow.color.deinit(allocator); - shadow.color = out; - } - } - - return res; - } - @compileError("Dunno what to do here."); - } - - fn getFallbacksReturnType(comptime Type: type, comptime InlineSize: comptime_int) type { - // Implements ImageFallback interface - if (@hasDecl(Type, "getImage") and InlineSize == 1) { - return bun.BabyList(SmallList(Type, 1)); - } - if (Type == TextShadow and InlineSize == 1) { - return SmallList(SmallList(TextShadow, 1), 2); - } - @compileError("Unhandled for: " ++ @typeName(Type)); - } - - // TODO: remove this stupid function - pub fn map(this: *@This(), comptime func: anytype) void { - for (this.slice_mut()) |*item| { - func(item); - } - } - - /// `predicate` must be: `fn(*const T) bool` - pub fn any(this: *const @This(), comptime predicate: anytype) bool { - for (this.slice()) |*item| { - if (predicate(item)) return true; - } - return false; - } - - pub fn orderedRemove(this: *@This(), idx: u32) T { - var ptr, const len_ptr, const capp = this.tripleMut(); - _ = capp; // autofix - bun.assert(idx < len_ptr.*); - - const length = len_ptr.*; - - len_ptr.* = len_ptr.* - 1; - ptr += idx; - const item = ptr[0]; - std.mem.copyForwards(T, ptr[0 .. length - idx - 1], ptr[1..][0 .. length - idx - 1]); - - return item; - } - - pub fn swapRemove(this: *@This(), idx: u32) T { - var ptr, const len_ptr, const capp = this.tripleMut(); - _ = capp; // autofix - bun.assert(idx < len_ptr.*); - - const ret = ptr[idx]; - ptr[idx] = ptr[len_ptr.* -| 1]; - len_ptr.* = len_ptr.* - 1; - - return ret; - } - - pub fn clearRetainingCapacity(this: *@This()) void { - if (this.spilled()) { - this.data.heap.len = 0; - } else { - this.capacity = 0; - } - } - - pub fn shallowClone(this: *const @This(), allocator: Allocator) @This() { - if (!this.spilled()) return this.*; - var h = HeapData.initCapacity(allocator, this.capacity); - h.len = this.data.heap.len; - @memcpy(h.ptr[0..h.len], this.data.heap.ptr[0..h.len]); - return .{ - .capacity = this.capacity, - .data = .{ .heap = h }, - }; - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - var ret: @This() = initCapacity(allocator, this.len()); - ret.setLen(this.len()); - for (this.slice(), ret.slice_mut()) |*in, *out| { - out.* = generic.deepClone(T, in, allocator); - } - return ret; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - if (lhs.len() != rhs.len()) return false; - for (lhs.slice(), rhs.slice()) |*a, *b| { - if (!generic.eql(T, a, b)) return false; - } - return true; - } - - /// Shallow clone - pub fn clone(this: *const @This(), allocator: Allocator) @This() { - var ret = this.*; - if (!this.spilled()) return ret; - // Preserve the invariant that the heap allocation holds `capacity` elements, - // otherwise a later append that trusts `capacity` would write out of bounds. - const buf = bun.handleOom(allocator.alloc(T, this.capacity)); - @memcpy(buf[0..ret.data.heap.len], ret.data.heap.ptr[0..ret.data.heap.len]); - ret.data.heap.ptr = buf.ptr; - return ret; - } - - pub fn deinit(this: *@This(), allocator: Allocator) void { - if (this.spilled()) { - allocator.free(this.data.heap.ptr[0..this.capacity]); - } - } - - pub fn hash(this: *const @This(), hasher: anytype) void { - for (this.slice()) |*item| { - css.generic.hash(T, item, hasher); - } - } - - pub inline fn len(this: *const @This()) u32 { - if (this.spilled()) return this.data.heap.len; - return this.capacity; - } - - pub inline fn isEmpty(this: *const @This()) bool { - return this.len() == 0; - } - - pub fn initCapacity(allocator: Allocator, capacity: u32) @This() { - if (capacity > N) { - var list: This = .{}; - list.capacity = capacity; - list.data = .{ .heap = HeapData.initCapacity(allocator, capacity) }; - return list; - } - - return .{ - .capacity = 0, - }; - } - - pub fn ensureTotalCapacity(this: *@This(), allocator: Allocator, new_capacity: u32) void { - if (this.capacity >= new_capacity) return; - this.tryGrow(allocator, new_capacity); - } - - pub fn insert( - this: *@This(), - allocator: Allocator, - index: u32, - item: T, - ) void { - var ptr, var len_ptr, const capp = this.tripleMut(); - if (len_ptr.* == capp) { - this.reserveOneUnchecked(allocator); - const heap_ptr, const heap_len_ptr = this.heap(); - ptr = heap_ptr; - len_ptr = heap_len_ptr; - } - const length = len_ptr.*; - ptr += index; - if (index < length) { - const count = length - index; - std.mem.copyBackwards(T, ptr[1..][0..count], ptr[0..count]); - } else if (index == length) { - // No elements need shifting. - } else { - @panic("index exceeds length"); - } - len_ptr.* = length + 1; - ptr[0] = item; - } - - pub fn appendAssumeCapacity(this: *@This(), item: T) void { - var ptr, const len_ptr, const capp = this.tripleMut(); - bun.debugAssert(len_ptr.* < capp); - ptr[len_ptr.*] = item; - len_ptr.* += 1; - } - - pub fn pop(this: *@This()) ?T { - const ptr, const len_ptr, _ = this.tripleMut(); - if (len_ptr.* == 0) return null; - const last_index = len_ptr.* - 1; - len_ptr.* = last_index; - return ptr[last_index]; - } - - pub fn append(this: *@This(), allocator: Allocator, item: T) void { - var ptr, var len_ptr, const capp = this.tripleMut(); - if (len_ptr.* == capp) { - this.reserveOneUnchecked(allocator); - const heap_ptr, const heap_len = this.heap(); - ptr = heap_ptr; - len_ptr = heap_len; - } - ptr[len_ptr.*] = item; - len_ptr.* += 1; - } - - pub fn appendSlice(this: *@This(), allocator: Allocator, items: []const T) void { - this.insertSlice(allocator, this.len(), items); - } - - pub fn appendSliceAssumeCapacity(this: *@This(), items: []const T) void { - bun.assert(this.len() + items.len <= this.capacity); - this.insertSliceAssumeCapacity(this.len(), items); - } - - pub inline fn insertSlice(this: *@This(), allocator: Allocator, index: u32, items: []const T) void { - this.reserve(allocator, @intCast(items.len)); - this.insertSliceAssumeCapacity(index, items); - } - - pub inline fn insertSliceAssumeCapacity(this: *@This(), index: u32, items: []const T) void { - const length = this.len(); - bun.assert(index <= length); - const ptr: [*]T = this.as_ptr()[index..]; - const count = length - index; - std.mem.copyBackwards(T, ptr[items.len..][0..count], ptr[0..count]); - @memcpy(ptr[0..items.len], items); - this.setLen(length + @as(u32, @intCast(items.len))); - } - - pub fn setLen(this: *@This(), new_len: u32) void { - const len_ptr = this.lenMut(); - len_ptr.* = new_len; - } - - inline fn heap(this: *@This()) struct { [*]T, *u32 } { - return .{ this.data.heap.ptr, &this.data.heap.len }; - } - - fn as_const_ptr(this: *const @This()) [*]const T { - if (this.spilled()) return this.data.heap.ptr; - return &this.data.inlined; - } - - fn as_ptr(this: *@This()) [*]T { - if (this.spilled()) return this.data.heap.ptr; - return &this.data.inlined; - } - - fn reserve(this: *@This(), allocator: Allocator, additional: u32) void { - const ptr, const __len, const capp = this.tripleMut(); - _ = ptr; // autofix - const len_ = __len.*; - - if (capp - len_ >= additional) return; - const new_cap = growCapacity(capp, len_ + additional); - this.tryGrow(allocator, new_cap); - } - - fn reserveOneUnchecked(this: *@This(), allocator: Allocator) void { - @branchHint(.cold); - bun.assert(this.len() == this.capacity); - const new_cap = growCapacity(this.capacity, this.len() + 1); - this.tryGrow(allocator, new_cap); - } - - fn tryGrow(this: *@This(), allocator: Allocator, new_cap: u32) void { - const unspilled = !this.spilled(); - const ptr, const __len, const cap = this.tripleMut(); - const length = __len.*; - bun.assert(new_cap >= length); - if (new_cap <= N) { - if (unspilled) return; - this.data = .{ .inlined = undefined }; - @memcpy(this.data.inlined[0..length], ptr[0..length]); - this.capacity = length; - allocator.free(ptr[0..cap]); - } else if (new_cap != cap) { - const new_alloc: [*]T = if (unspilled) new_alloc: { - const new_alloc = bun.handleOom(allocator.alloc(T, new_cap)); - @memcpy(new_alloc[0..length], ptr[0..length]); - break :new_alloc new_alloc.ptr; - } else new_alloc: { - break :new_alloc bun.handleOom(allocator.realloc(ptr[0..cap], new_cap)).ptr; - }; - this.data = .{ .heap = .{ .ptr = new_alloc, .len = length } }; - this.capacity = new_cap; - } - } - - /// Returns a tuple with (data ptr, len, capacity) - /// Useful to get all SmallVec properties with a single check of the current storage variant. - inline fn tripleMut(this: *@This()) struct { [*]T, *u32, u32 } { - if (this.spilled()) return .{ this.data.heap.ptr, &this.data.heap.len, this.capacity }; - return .{ &this.data.inlined, &this.capacity, N }; - } - - inline fn lenMut(this: *@This()) *u32 { - if (this.spilled()) return &this.data.heap.len; - return &this.capacity; - } - - fn growToHeap(this: *@This(), allocator: Allocator, additional: usize) void { - bun.assert(!this.spilled()); - const new_size = growCapacity(this.capacity, this.capacity + additional); - var slc = bun.handleOom(allocator.alloc(T, new_size)); - @memcpy(slc[0..this.capacity], this.data.inlined[0..this.capacity]); - this.data = .{ .heap = HeapData{ .len = this.capacity, .ptr = slc.ptr } }; - this.capacity = new_size; - } - - inline fn spilled(this: *const @This()) bool { - return this.capacity > N; - } - - /// Copy pasted from Zig std in array list: - /// - /// Called when memory growth is necessary. Returns a capacity larger than - /// minimum that grows super-linearly. - fn growCapacity(current: u32, minimum: u32) u32 { - var new = current; - while (true) { - new +|= new / 2 + 8; - if (new >= minimum) - return new; - } - } - - pub const looksLikeContainerTypeSmallList = T; - }; -} - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; - -const css = @import("./css_parser.zig"); -const Delimiters = css.Delimiters; -const Parser = css.Parser; -const PrintErr = css.PrintErr; -const Printer = css.Printer; -const Result = css.Result; -const generic = css.generic; -const voidWrap = css.voidWrap; -const TextShadow = css.css_properties.text.TextShadow; diff --git a/src/css/sourcemap.zig b/src/css/sourcemap.zig deleted file mode 100644 index 6a8ad1057df0..000000000000 --- a/src/css/sourcemap.zig +++ /dev/null @@ -1,29 +0,0 @@ -pub const css = @import("./css_parser.zig"); -pub const css_values = @import("./values/values.zig"); -pub const Error = css.Error; - -pub const SourceMap = struct { - project_root: []const u8, - inner: SourceMapInner, -}; - -pub const SourceMapInner = struct { - sources: ArrayList([]const u8), - sources_content: ArrayList([]const u8), - names: ArrayList([]const u8), - mapping_lines: ArrayList(MappingLine), -}; - -pub const MappingLine = struct { mappings: ArrayList(LineMapping), last_column: u32, is_sorted: bool }; - -pub const LineMapping = struct { generated_column: u32, original: ?OriginalLocation }; - -pub const OriginalLocation = struct { - original_line: u32, - original_column: u32, - source: u32, - name: ?u32, -}; - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; diff --git a/src/css/targets.rs b/src/css/targets.rs index 2ab9f1a36b0e..809e94187e41 100644 --- a/src/css/targets.rs +++ b/src/css/targets.rs @@ -415,26 +415,26 @@ bitflags::bitflags! { /// Features to explicitly enable or disable. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct Features: u32 { - const NESTING = 1 << 0; - const NOT_SELECTOR_LIST = 1 << 1; - const DIR_SELECTOR = 1 << 2; - const LANG_SELECTOR_LIST = 1 << 3; - const IS_SELECTOR = 1 << 4; + const NESTING = 1 << 0; + const NOT_SELECTOR_LIST = 1 << 1; + const DIR_SELECTOR = 1 << 2; + const LANG_SELECTOR_LIST = 1 << 3; + const IS_SELECTOR = 1 << 4; const TEXT_DECORATION_THICKNESS_PERCENT = 1 << 5; - const MEDIA_INTERVAL_SYNTAX = 1 << 6; - const MEDIA_RANGE_SYNTAX = 1 << 7; - const CUSTOM_MEDIA_QUERIES = 1 << 8; - const CLAMP_FUNCTION = 1 << 9; - const COLOR_FUNCTION = 1 << 10; - const OKLAB_COLORS = 1 << 11; - const LAB_COLORS = 1 << 12; - const P3_COLORS = 1 << 13; - const HEX_ALPHA_COLORS = 1 << 14; - const SPACE_SEPARATED_COLOR_NOTATION = 1 << 15; - const FONT_FAMILY_SYSTEM_UI = 1 << 16; - const DOUBLE_POSITION_GRADIENTS = 1 << 17; - const VENDOR_PREFIXES = 1 << 18; - const LOGICAL_PROPERTIES = 1 << 19; + const MEDIA_INTERVAL_SYNTAX = 1 << 6; + const MEDIA_RANGE_SYNTAX = 1 << 7; + const CUSTOM_MEDIA_QUERIES = 1 << 8; + const CLAMP_FUNCTION = 1 << 9; + const COLOR_FUNCTION = 1 << 10; + const OKLAB_COLORS = 1 << 11; + const LAB_COLORS = 1 << 12; + const P3_COLORS = 1 << 13; + const HEX_ALPHA_COLORS = 1 << 14; + const SPACE_SEPARATED_COLOR_NOTATION = 1 << 15; + const FONT_FAMILY_SYSTEM_UI = 1 << 16; + const DOUBLE_POSITION_GRADIENTS = 1 << 17; + const VENDOR_PREFIXES = 1 << 18; + const LOGICAL_PROPERTIES = 1 << 19; const SELECTORS = Self::NESTING.bits() | Self::NOT_SELECTOR_LIST.bits() diff --git a/src/css/targets.zig b/src/css/targets.zig deleted file mode 100644 index 5bd46ef3dcda..000000000000 --- a/src/css/targets.zig +++ /dev/null @@ -1,349 +0,0 @@ -pub const css = @import("./css_parser.zig"); - -const VendorPrefix = css.VendorPrefix; - -/// Target browsers and features to compile. -pub const Targets = struct { - /// Browser targets to compile the CSS for. - browsers: ?Browsers = null, - /// Features that should always be compiled, even when supported by targets. - include: Features = .{}, - /// Features that should never be compiled, even when unsupported by targets. - exclude: Features = .{}, - - /// Set a sane default for bundler - pub fn browserDefault() Targets { - return .{ - .browsers = Browsers.browserDefault, - }; - } - - /// Set a sane default for bundler - pub fn runtimeDefault() Targets { - return .{ - .browsers = null, - }; - } - - fn parseDebugTarget(val_: []const u8) ?u32 { - const val = bun.strings.trim(val_, " \n\r\t"); - if (val.len == 0) return null; - if (bun.strings.eqlCaseInsensitiveASCII(val, "null", true)) return null; - - var lhs: u32 = 0; - var rhs: u32 = 0; - - var i: usize = 0; - for (val, 0..) |c, j| { - if (!std.ascii.isDigit(c)) { - i = j; - lhs = std.fmt.parseInt(u32, val[0..j], 10) catch @panic("invalid bytes"); - break; - } - } - if (i >= val.len) { - lhs = std.fmt.parseInt(u32, val, 10) catch @panic("invalid bytes"); - return lhs; - } - if (val[i] != ' ') { - @panic("bad string"); - } - i += 1; - if (val[i] != '<' or i + 1 >= val.len or val[i + 1] != '<') { - @panic("bad string"); - } - i += 2; - if (val[i] != ' ') { - @panic("bad string"); - } - i += 1; - rhs = std.fmt.parseInt(u32, val[i..], 10) catch @panic("invalid bytes"); - return lhs << @intCast(rhs); - } - - pub fn forBundlerTarget(target: bun.transpiler.options.Target) Targets { - if (comptime bun.Environment.isDebug) { - var browsers: Browsers = .{}; - const browser_fields = std.meta.fields(Browsers); - var has_any = false; - inline for (browser_fields) |field| { - const env_var = "BUN_DEBUG_CSS_TARGET_" ++ field.name; - if (bun.getenvZAnyCase(env_var)) |val| { - @field(browsers, field.name) = parseDebugTarget(val); - has_any = true; - } - } - if (has_any) { - return .{ .browsers = browsers }; - } - } - return switch (target) { - .node, .bun => runtimeDefault(), - .browser, .bun_macro, .bake_server_components_ssr => browserDefault(), - }; - } - - pub fn prefixes(this: *const Targets, prefix: css.VendorPrefix, feature: css.prefixes.Feature) css.VendorPrefix { - if (prefix.none and !this.exclude.vendor_prefixes) { - if (this.include.vendor_prefixes) { - return .all; - } else { - return if (this.browsers) |b| feature.prefixesFor(b) else prefix; - } - } else { - return prefix; - } - } - - pub fn shouldCompileLogical(this: *const Targets, feature: css.compat.Feature) bool { - return this.shouldCompile(feature, css.Features{ .logical_properties = true }); - } - - pub fn shouldCompile(this: *const Targets, feature: css.compat.Feature, flag: Features) bool { - return bits.contains(Features, this.include, flag) or - (!bits.contains(Features, this.exclude, flag) and !this.isCompatible(feature)); - } - - pub fn shouldCompileSame(this: *const Targets, comptime compat_feature: css.compat.Feature) bool { - const target_feature: css.targets.Features = target_feature: { - var feature: css.targets.Features = .{}; - @field(feature, @tagName(compat_feature)) = true; - break :target_feature feature; - }; - - return shouldCompile(this, compat_feature, target_feature); - } - - pub fn shouldCompileSelectors(this: *const Targets) bool { - return bun.bits.intersects(Features, this.include, Features.selectors) or - (!bun.bits.intersects(Features, this.exclude, Features.selectors) and this.browsers != null); - } - - pub fn isCompatible(this: *const Targets, feature: css.compat.Feature) bool { - if (this.browsers) |*targets| { - return feature.isCompatible(targets.*); - } - return true; - } -}; - -/// Browser versions to compile CSS for. -/// -/// Versions are represented as a single 24-bit integer, with one byte -/// per `major.minor.patch` component. -/// -/// # Example -/// -/// This example represents a target of Safari 13.2.0. -/// -/// ``` -/// const Browsers = struct { -/// safari: ?u32 = (13 << 16) | (2 << 8), -/// ..Browsers{} -/// }; -/// ``` -pub const Browsers = struct { - android: ?u32 = null, - chrome: ?u32 = null, - edge: ?u32 = null, - firefox: ?u32 = null, - ie: ?u32 = null, - ios_saf: ?u32 = null, - opera: ?u32 = null, - safari: ?u32 = null, - samsung: ?u32 = null, - - pub const browserDefault = convertFromString(&.{ - "es2020", // support import.meta.url - "edge88", - "firefox78", - "chrome87", - "safari14", - }) catch unreachable; - - /// Ported from here: - /// https://github.com/vitejs/vite/blob/ac329685bba229e1ff43e3d96324f817d48abe48/packages/vite/src/node/plugins/css.ts#L3335 - pub fn convertFromString(esbuild_target: []const []const u8) anyerror!Browsers { - var browsers: Browsers = .{}; - - for (esbuild_target) |str| { - var entries_buf: [5][]const u8 = undefined; - const entries_without_es: [][]const u8 = entries_without_es: { - if (str.len <= 2 or !(str[0] == 'e' and str[1] == 's')) { - entries_buf[0] = str; - break :entries_without_es entries_buf[0..1]; - } - - const number_part = str[2..]; - const year = try std.fmt.parseInt(u16, number_part, 10); - switch (year) { - // https://caniuse.com/?search=es2015 - 2015 => { - entries_buf[0..5].* = .{ "chrome49", "edge13", "safari10", "firefox44", "opera36" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2016 - 2016 => { - entries_buf[0..5].* = .{ "chrome50", "edge13", "safari10", "firefox43", "opera37" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2017 - 2017 => { - entries_buf[0..5].* = .{ "chrome58", "edge15", "safari11", "firefox52", "opera45" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2018 - 2018 => { - entries_buf[0..5].* = .{ "chrome63", "edge79", "safari12", "firefox58", "opera50" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2019 - 2019 => { - entries_buf[0..5].* = .{ "chrome73", "edge79", "safari12.1", "firefox64", "opera60" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2020 - 2020 => { - entries_buf[0..5].* = .{ "chrome80", "edge80", "safari14.1", "firefox80", "opera67" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2021 - 2021 => { - entries_buf[0..5].* = .{ "chrome85", "edge85", "safari14.1", "firefox80", "opera71" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2022 - 2022 => { - entries_buf[0..5].* = .{ "chrome94", "edge94", "safari16.4", "firefox93", "opera80" }; - break :entries_without_es entries_buf[0..5]; - }, - // https://caniuse.com/?search=es2023 - 2023 => { - entries_buf[0..4].* = .{ "chrome110", "edge110", "safari16.4", "opera96" }; - break :entries_without_es entries_buf[0..4]; - }, - else => { - if (@inComptime()) { - @compileLog("Invalid target: " ++ str); - } - return error.UnsupportedCSSTarget; - }, - } - }; - - for_loop: for (entries_without_es) |entry| { - if (bun.strings.eql(entry, "esnext")) continue; - const maybe_idx: ?usize = maybe_idx: { - for (entry, 0..) |c, i| { - if (std.ascii.isDigit(c)) break :maybe_idx i; - } - break :maybe_idx null; - }; - - if (maybe_idx) |idx| { - const Browser = enum { - chrome, - edge, - firefox, - ie, - ios_saf, - opera, - safari, - no_mapping, - }; - const Map = bun.ComptimeStringMap(Browser, .{ - .{ "chrome", Browser.chrome }, - .{ "edge", Browser.edge }, - .{ "firefox", Browser.firefox }, - .{ "hermes", Browser.no_mapping }, - .{ "ie", Browser.ie }, - .{ "ios", Browser.ios_saf }, - .{ "node", Browser.no_mapping }, - .{ "opera", Browser.opera }, - .{ "rhino", Browser.no_mapping }, - .{ "safari", Browser.safari }, - }); - const browser = Map.get(entry[0..idx]); - if (browser == null or browser.? == .no_mapping) continue; // No mapping available - - const major, const minor = major_minor: { - const version_str = entry[idx..]; - const dot_index = std.mem.indexOfScalar(u8, version_str, '.') orelse version_str.len; - const major = std.fmt.parseInt(u16, version_str[0..dot_index], 10) catch continue; - const minor = if (dot_index < version_str.len) - std.fmt.parseInt(u16, version_str[dot_index + 1 ..], 10) catch 0 - else - 0; - break :major_minor .{ major, minor }; - }; - - const version: u32 = (@as(u32, major) << 16) | @as(u32, minor << 8); - switch (browser.?) { - inline else => |browser_name| { - if (@field(browsers, @tagName(browser_name)) == null or - version < @field(browsers, @tagName(browser_name)).?) - { - @field(browsers, @tagName(browser_name)) = version; - } - continue :for_loop; - }, - } - } - } - } - - return browsers; - } -}; - -/// Autogenerated by build-prefixes.js -/// Features to explicitly enable or disable. -pub const Features = packed struct(u32) { - nesting: bool = false, - not_selector_list: bool = false, - dir_selector: bool = false, - lang_selector_list: bool = false, - is_selector: bool = false, - text_decoration_thickness_percent: bool = false, - media_interval_syntax: bool = false, - media_range_syntax: bool = false, - custom_media_queries: bool = false, - clamp_function: bool = false, - color_function: bool = false, - oklab_colors: bool = false, - lab_colors: bool = false, - p3_colors: bool = false, - hex_alpha_colors: bool = false, - space_separated_color_notation: bool = false, - font_family_system_ui: bool = false, - double_position_gradients: bool = false, - vendor_prefixes: bool = false, - logical_properties: bool = false, - __unused: u12 = 0, - - pub const selectors: @This() = .{ - .nesting = true, - .not_selector_list = true, - .dir_selector = true, - .lang_selector_list = true, - .is_selector = true, - }; - pub const media_queries: @This() = .{ - .media_interval_syntax = true, - .media_range_syntax = true, - .custom_media_queries = true, - }; - pub const colors: @This() = .{ - .color_function = true, - .oklab_colors = true, - .lab_colors = true, - .p3_colors = true, - .hex_alpha_colors = true, - .space_separated_color_notation = true, - }; -}; - -const std = @import("std"); - -const bun = @import("bun"); -const bits = bun.bits; diff --git a/src/css/values/alpha.zig b/src/css/values/alpha.zig deleted file mode 100644 index aeb841113049..000000000000 --- a/src/css/values/alpha.zig +++ /dev/null @@ -1,45 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage; - -/// A CSS [``](https://www.w3.org/TR/css-color-4/#typedef-alpha-value), -/// used to represent opacity. -/// -/// Parses either a `` or ``, but is always stored and serialized as a number. -pub const AlphaValue = struct { - v: f32, - - pub fn parse(input: *css.Parser) Result(AlphaValue) { - // For some reason NumberOrPercentage.parse makes zls crash, using this instead. - const val: NumberOrPercentage = switch (@call(.auto, @field(NumberOrPercentage, "parse"), .{input})) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const final = switch (val) { - .percentage => |percent| AlphaValue{ .v = percent.v }, - .number => |num| AlphaValue{ .v = num }, - }; - return .{ .result = final }; - } - - pub fn toCss(this: *const AlphaValue, dest: *css.Printer) css.PrintErr!void { - return CSSNumberFns.toCss(&this.v, dest); - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const std = @import("std"); diff --git a/src/css/values/angle.zig b/src/css/values/angle.zig deleted file mode 100644 index 1a2815ee53a0..000000000000 --- a/src/css/values/angle.zig +++ /dev/null @@ -1,306 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const Calc = css.css_values.calc.Calc; - -const Tag = enum(u8) { - deg = 1, - rad = 2, - grad = 4, - turn = 8, -}; - -/// A CSS [``](https://www.w3.org/TR/css-values-4/#angles) value. -/// -/// Angles may be explicit or computed by `calc()`, but are always stored and serialized -/// as their computed value. -pub const Angle = union(Tag) { - /// An angle in degrees. There are 360 degrees in a full circle. - deg: CSSNumber, - /// An angle in radians. There are 2π radians in a full circle. - rad: CSSNumber, - /// An angle in gradians. There are 400 gradians in a full circle. - grad: CSSNumber, - /// An angle in turns. There is 1 turn in a full circle. - turn: CSSNumber, - - // ~toCssImpl - const This = @This(); - - pub fn parse(input: *css.Parser) Result(Angle) { - return Angle.parseInternal(input, false); - } - - fn parseInternal(input: *css.Parser, allow_unitless_zero: bool) Result(Angle) { - if (input.tryParse(Calc(Angle).parse, .{}).asValue()) |calc_value| { - if (calc_value == .value) return .{ .result = calc_value.value.* }; - // Angles are always compatible, so they will always compute to a value. - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - - const location = input.currentSourceLocation(); - const token = switch (input.next()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - switch (token.*) { - .dimension => |*dim| { - const value = dim.num.value; - const unit = dim.unit; - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("deg", unit)) { - return .{ .result = Angle{ .deg = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("grad", unit)) { - return .{ .result = Angle{ .grad = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("turn", unit)) { - return .{ .result = Angle{ .turn = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("rad", unit)) { - return .{ .result = Angle{ .rad = value } }; - } else { - return .{ .err = location.newUnexpectedTokenError(token.*) }; - } - }, - .number => |num| { - if (num.value == 0.0 and allow_unitless_zero) return .{ .result = Angle.zero() }; - }, - else => {}, - } - return .{ .err = location.newUnexpectedTokenError(token.*) }; - } - - pub fn parseWithUnitlessZero(input: *css.Parser) Result(Angle) { - return Angle.parseInternal(input, true); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - const value, const unit = switch (this.*) { - .deg => |val| .{ val, "deg" }, - .grad => |val| .{ val, "grad" }, - .rad => |val| brk: { - const deg = this.toDegrees(); - - // We print 5 digits of precision by default. - // Switch to degrees if length is smaller than rad. - if (css.f32_length_with_5_digits(deg) < css.f32_length_with_5_digits(val)) { - break :brk .{ deg, "deg" }; - } else { - break :brk .{ val, "rad" }; - } - }, - .turn => |val| .{ val, "turn" }, - }; - css.serializer.serializeDimension(value, unit, dest) catch return dest.addFmtError(); - } - - pub fn toCssWithUnitlessZero(this: *const This, dest: *Printer) PrintErr!void { - if (this.isZero()) { - const v: f32 = 0.0; - try CSSNumberFns.toCss(&v, dest); - } else { - return this.toCss(dest); - } - } - - pub fn tryFromAngle(angle: Angle) ?This { - return angle; - } - - pub fn tryFromToken(token: *const css.Token) css.Maybe(Angle, void) { - if (token.* == .dimension) { - const value = token.dimension.num.value; - const unit = token.dimension.unit; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "deg")) { - return .{ .result = .{ .deg = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "grad")) { - return .{ .result = .{ .grad = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "turn")) { - return .{ .result = .{ .turn = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "rad")) { - return .{ .result = .{ .rad = value } }; - } - } - return .{ .err = {} }; - } - - /// Returns the angle in radians. - pub fn toRadians(this: *const Angle) CSSNumber { - const RAD_PER_DEG: f32 = std.math.pi / 180.0; - return switch (this.*) { - .deg => |deg| return deg * RAD_PER_DEG, - .rad => |rad| return rad, - .grad => |grad| return grad * 180.0 / 200.0 * RAD_PER_DEG, - .turn => |turn| return turn * 360.0 * RAD_PER_DEG, - }; - } - - /// Returns the angle in degrees. - pub fn toDegrees(this: *const Angle) CSSNumber { - const DEG_PER_RAD: f32 = 180.0 / std.math.pi; - switch (this.*) { - .deg => |deg| return deg, - .rad => |rad| return rad * DEG_PER_RAD, - .grad => |grad| return grad * 180.0 / 200.0, - .turn => |turn| return turn * 360.0, - } - } - - pub fn zero() Angle { - return .{ .deg = 0.0 }; - } - - pub fn isZero(this: *const Angle) bool { - const v = switch (this.*) { - .deg => |deg| deg, - .rad => |rad| rad, - .grad => |grad| grad, - .turn => |turn| turn, - }; - return v == 0.0; - } - - pub fn intoCalc(this: *const Angle, allocator: std.mem.Allocator) Calc(Angle) { - return Calc(Angle){ - .value = bun.create(allocator, Angle, this.*), - }; - } - - pub fn map(this: *const Angle, comptime opfn: *const fn (f32) f32) Angle { - return switch (this.*) { - .deg => |deg| .{ .deg = opfn(deg) }, - .rad => |rad| .{ .rad = opfn(rad) }, - .grad => |grad| .{ .grad = opfn(grad) }, - .turn => |turn| .{ .turn = opfn(turn) }, - }; - } - - pub fn tryMap(this: *const Angle, comptime opfn: *const fn (f32) f32) ?Angle { - return map(this, opfn); - } - - pub fn addInternal(this: Angle, _: std.mem.Allocator, other: Angle) Angle { - return this.add(other); - } - - pub fn add(this: Angle, rhs: Angle) Angle { - const addfn = struct { - pub fn add(_: void, a: f32, b: f32) f32 { - return a + b; - } - }; - return Angle.op(&this, &rhs, {}, addfn.add); - } - - pub fn tryAdd(this: *const Angle, _: std.mem.Allocator, rhs: *const Angle) ?Angle { - return .{ .deg = this.toDegrees() + rhs.toDegrees() }; - } - - pub fn eql(lhs: *const Angle, rhs: *const Angle) bool { - return lhs.toDegrees() == rhs.toDegrees(); - } - - pub fn mulF32(this: Angle, _: std.mem.Allocator, other: f32) Angle { - // return Angle.op(&this, &other, Angle.mulF32); - return switch (this) { - .deg => |v| .{ .deg = v * other }, - .rad => |v| .{ .rad = v * other }, - .grad => |v| .{ .grad = v * other }, - .turn => |v| .{ .turn = v * other }, - }; - } - - pub fn partialCmp(this: *const Angle, other: *const Angle) ?std.math.Order { - return css.generic.partialCmpF32(&this.toDegrees(), &other.toDegrees()); - } - - pub fn tryOp( - this: *const Angle, - other: *const Angle, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, - ) ?Angle { - return Angle.op(this, other, ctx, op_fn); - } - - pub fn tryOpTo( - this: *const Angle, - other: *const Angle, - comptime R: type, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R, - ) ?R { - return Angle.opTo(this, other, R, ctx, op_fn); - } - - pub fn op( - this: *const Angle, - other: *const Angle, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, - ) Angle { - // PERF: not sure if this is faster - const self_tag: u16 = @intFromEnum(this.*); - const other_tag: u16 = @intFromEnum(other.*); - const DEG: u16 = @intFromEnum(Tag.deg); - const GRAD: u16 = @intFromEnum(Tag.grad); - const RAD: u16 = @intFromEnum(Tag.rad); - const TURN: u16 = @intFromEnum(Tag.turn); - - const switch_val: u16 = self_tag | (other_tag << 8); - return switch (switch_val) { - DEG | (DEG << 8) => Angle{ .deg = op_fn(ctx, this.deg, other.deg) }, - RAD | (RAD << 8) => Angle{ .rad = op_fn(ctx, this.rad, other.rad) }, - GRAD | (GRAD << 8) => Angle{ .grad = op_fn(ctx, this.grad, other.grad) }, - TURN | (TURN << 8) => Angle{ .turn = op_fn(ctx, this.turn, other.turn) }, - else => Angle{ .deg = op_fn(ctx, this.toDegrees(), other.toDegrees()) }, - }; - } - - pub fn opTo( - this: *const Angle, - other: *const Angle, - comptime T: type, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) T, - ) T { - // PERF: not sure if this is faster - const self_tag: u8 = @intFromEnum(this.*); - const other_tag: u8 = @intFromEnum(this.*); - const DEG: u8 = @intFromEnum(Tag.deg); - const GRAD: u8 = @intFromEnum(Tag.grad); - const RAD: u8 = @intFromEnum(Tag.rad); - const TURN: u8 = @intFromEnum(Tag.turn); - - const switch_val: u8 = self_tag | other_tag; - return switch (switch_val) { - DEG | DEG => op_fn(ctx, this.deg, other.deg), - RAD | RAD => op_fn(ctx, this.rad, other.rad), - GRAD | GRAD => op_fn(ctx, this.grad, other.grad), - TURN | TURN => op_fn(ctx, this.turn, other.turn), - else => op_fn(ctx, this.toDegrees(), other.toDegrees()), - }; - } - - pub fn sign(this: *const Angle) f32 { - return switch (this.*) { - .deg, .rad, .grad, .turn => |v| CSSNumberFns.sign(&v), - }; - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A CSS [``](https://www.w3.org/TR/css-values-4/#typedef-angle-percentage) value. -/// May be specified as either an angle or a percentage that resolves to an angle. -pub const AnglePercentage = css.css_values.percentage.DimensionPercentage(Angle); - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/values/calc.zig b/src/css/values/calc.zig deleted file mode 100644 index 5aa80656fe5f..000000000000 --- a/src/css/values/calc.zig +++ /dev/null @@ -1,1892 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Angle = css.css_values.angle.Angle; -const Length = css.css_values.length.Length; -const LengthValue = css.css_values.length.LengthValue; -const Percentage = css.css_values.percentage.Percentage; -const DimensionPercentage = css.css_values.percentage.DimensionPercentage; -const Time = css.css_values.time.Time; - -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; - -const eql = css.generic.eql; -const deepClone = css.deepClone; - -pub fn needsDeinit(comptime V: type) bool { - return switch (V) { - Length => true, - DimensionPercentage(Angle) => true, - DimensionPercentage(LengthValue) => true, - Percentage => false, - Angle => false, - Time => false, - f32 => false, - else => @compileError("Can't tell if " ++ @typeName(V) ++ " needs deinit, please add it to the switch statement."), - }; -} - -pub fn needsDeepclone(comptime V: type) bool { - return switch (V) { - Length => true, - DimensionPercentage(Angle) => true, - DimensionPercentage(LengthValue) => true, - Percentage => false, - Angle => false, - Time => false, - f32 => false, - else => @compileError("Can't tell if " ++ @typeName(V) ++ " needs deepclone, please add it to the switch statement."), - }; -} - -const Tag_ = enum(u8) { - /// A literal value. - value = 1, - /// A literal number. - number = 2, - /// A sum of two calc expressions. - sum = 4, - /// A product of a number and another calc expression. - product = 8, - /// A math function, such as `calc()`, `min()`, or `max()`. - function = 16, -}; - -const CalcUnit = enum { - abs, - acos, - asin, - atan, - atan2, - calc, - clamp, - cos, - exp, - hypot, - log, - max, - min, - mod, - pow, - rem, - round, - sign, - sin, - sqrt, - tan, - - pub const Map = bun.ComptimeEnumMap(CalcUnit); -}; - -/// A mathematical expression used within the `calc()` function. -/// -/// This type supports generic value types. Values such as `Length`, `Percentage`, -/// `Time`, and `Angle` support `calc()` expressions. -pub fn Calc(comptime V: type) type { - const needs_deinit = needsDeinit(V); - const needs_deepclone = needsDeepclone(V); - - return union(Tag) { - /// A literal value. - /// PERF: this pointer feels unnecessary if V is small - value: *V, - /// A literal number. - number: CSSNumber, - /// A sum of two calc expressions. - sum: struct { - left: *This, - right: *This, - }, - /// A product of a number and another calc expression. - product: struct { - number: CSSNumber, - expression: *This, - }, - /// A math function, such as `calc()`, `min()`, or `max()`. - function: *MathFunction(V), - - const Tag = Tag_; - - const This = @This(); - - pub fn deepClone(this: *const This, allocator: Allocator) This { - return switch (this.*) { - .value => |v| { - return .{ - .value = bun.create( - allocator, - V, - if (needs_deepclone) v.deepClone(allocator) else v.*, - ), - }; - }, - .number => this.*, - .sum => |sum| { - return .{ .sum = .{ - .left = bun.create(allocator, This, sum.left.deepClone(allocator)), - .right = bun.create(allocator, This, sum.right.deepClone(allocator)), - } }; - }, - .product => |product| { - return .{ - .product = .{ - .number = product.number, - .expression = bun.create(allocator, This, product.expression.deepClone(allocator)), - }, - }; - }, - .function => |function| { - return .{ - .function = bun.create( - allocator, - MathFunction(V), - function.deepClone(allocator), - ), - }; - }, - }; - } - - pub fn deinit(this: *This, allocator: Allocator) void { - return switch (this.*) { - .value => |v| { - if (comptime needs_deinit) { - v.deinit(allocator); - } - allocator.destroy(this.value); - }, - .number => {}, - .sum => |sum| { - sum.left.deinit(allocator); - sum.right.deinit(allocator); - allocator.destroy(sum.left); - allocator.destroy(sum.right); - }, - .product => |product| { - product.expression.deinit(allocator); - allocator.destroy(product.expression); - }, - .function => |function| { - function.deinit(allocator); - allocator.destroy(function); - }, - }; - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return switch (this.*) { - .value => |a| return other.* == .value and css.generic.eql(V, a, other.value), - .number => |*a| return other.* == .number and css.generic.eql(f32, a, &other.number), - .sum => |s| return other.* == .sum and s.left.eql(other.sum.left) and s.right.eql(other.sum.right), - .product => |p| return other.* == .product and p.number == other.product.number and p.expression.eql(other.product.expression), - .function => |f| return other.* == .function and f.eql(other.function), - }; - } - - fn mulValueF32(lhs: V, allocator: Allocator, rhs: f32) V { - return switch (V) { - f32 => lhs * rhs, - else => lhs.mulF32(allocator, rhs), - }; - } - - // TODO: addValueOwned - pub fn addValue(allocator: Allocator, lhs: V, rhs: V) V { - return switch (V) { - f32 => return lhs + rhs, - else => lhs.addInternal(allocator, rhs), - }; - } - - // TODO: intoValueOwned - pub fn intoValue(this: @This(), allocator: std.mem.Allocator) Result(V) { - switch (V) { - Angle => return switch (this) { - .value => |v| .{ .result = v.* }, - else => .{ .err = css.ParseError(css.ParserError){ - .kind = .{ .custom = .{ .unexpected_value = .{ - .expected = "angle value", - .received = @tagName(this), - } } }, - .location = css.SourceLocation{ .line = 0, .column = 0 }, - } }, - }, - CSSNumber => return switch (this) { - .value => |v| .{ .result = v.* }, - .number => |n| .{ .result = n }, - else => .{ .err = css.ParseError(css.ParserError){ - .kind = .{ .custom = .{ .unexpected_value = .{ - .expected = "number value", - .received = @tagName(this), - } } }, - .location = css.SourceLocation{ .line = 0, .column = 0 }, - } }, - }, - Length => return .{ .result = Length{ - .calc = bun.create(allocator, Calc(Length), this), - } }, - Percentage => return switch (this) { - .value => |v| .{ .result = v.* }, - else => .{ .result = Percentage{ .v = std.math.nan(f32) } }, - }, - Time => return switch (this) { - .value => |v| .{ .result = v.* }, - else => .{ .err = css.ParseError(css.ParserError){ - .kind = .{ .custom = .{ .unexpected_value = .{ - .expected = "time value", - .received = @tagName(this), - } } }, - .location = css.SourceLocation{ .line = 0, .column = 0 }, - } }, - }, - DimensionPercentage(LengthValue) => return .{ .result = DimensionPercentage(LengthValue){ .calc = bun.create( - allocator, - Calc(DimensionPercentage(LengthValue)), - this, - ) } }, - DimensionPercentage(Angle) => return .{ .result = DimensionPercentage(Angle){ .calc = bun.create( - allocator, - Calc(DimensionPercentage(Angle)), - this, - ) } }, - else => @compileError("Unimplemented, intoValue() for V = " ++ @typeName(V)), - } - } - - pub fn intoCalc(val: V, allocator: std.mem.Allocator) This { - return switch (V) { - f32 => .{ .value = bun.create(allocator, f32, val) }, - else => val.intoCalc(allocator), - }; - } - - // TODO: change to addOwned() - pub fn add(this: @This(), allocator: std.mem.Allocator, rhs: @This()) Result(@This()) { - if (this == .value and rhs == .value) { - // PERF: we can reuse the allocation here - return .{ .result = intoCalc(addValue(allocator, this.value.*, rhs.value.*), allocator) }; - } else if (this == .number and rhs == .number) { - return .{ .result = .{ .number = this.number + rhs.number } }; - } else if (this == .value) { - // PERF: we can reuse the allocation here - const rhs_value = switch (intoValue(rhs, allocator)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = intoCalc(addValue(allocator, this.value.*, rhs_value), allocator) }; - } else if (rhs == .value) { - // PERF: we can reuse the allocation here - const this_value = switch (intoValue(this, allocator)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = intoCalc(addValue(allocator, this_value, rhs.value.*), allocator) }; - } else if (this == .function) { - return .{ .result = This{ - .sum = .{ - .left = bun.create(allocator, This, this), - .right = bun.create(allocator, This, rhs), - }, - } }; - } else if (rhs == .function) { - return .{ .result = This{ - .sum = .{ - .left = bun.create(allocator, This, this), - .right = bun.create(allocator, This, rhs), - }, - } }; - } else { - const this_value = switch (intoValue(this, allocator)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const rhs_value = switch (intoValue(rhs, allocator)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = intoCalc(addValue(allocator, this_value, rhs_value), allocator) }; - } - } - - // TODO: users of this and `parseWith` don't need the pointer and often throwaway heap allocated values immediately - // use temp allocator or something? - pub fn parse(input: *css.Parser) Result(This) { - const Fn = struct { - pub fn parseWithFn(_: void, _: []const u8) ?This { - return null; - } - }; - return parseWith(input, {}, Fn.parseWithFn); - } - - pub fn parseWith( - input: *css.Parser, - ctx: anytype, - comptime parseIdent: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(This) { - const location = input.currentSourceLocation(); - const f = switch (input.expectFunction()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - switch (CalcUnit.Map.getAnyCase(f) orelse return .{ .err = location.newUnexpectedTokenError(.{ .ident = f }) }) { - .calc => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - return This.parseSum(i, self.ctx, parseIdent); - } - }; - var closure = Closure{ .ctx = ctx }; - const calc = switch (input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (calc == .value or calc == .number) return .{ .result = calc }; - return .{ .result = This{ - .function = bun.create( - input.allocator(), - MathFunction(V), - MathFunction(V){ .calc = calc }, - ), - } }; - }, - .min => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(ArrayList(This)) { - return i.parseCommaSeparatedWithCtx(This, self, @This().parseOne); - } - pub fn parseOne(self: *@This(), i: *css.Parser) Result(This) { - return This.parseSum(i, self.ctx, parseIdent); - } - }; - var closure = Closure{ .ctx = ctx }; - var reduced = switch (input.parseNestedBlock(ArrayList(This), &closure, Closure.parseNestedBlockFn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - // PERF(alloc): i don't like this additional allocation - // can we use stack fallback here if the common case is that there will be 1 argument? - This.reduceArgs(input.allocator(), &reduced, std.math.Order.lt); - // var reduced: ArrayList(This) = This.reduceArgs(&args, std.math.Order.lt); - if (reduced.items.len == 1) { - defer reduced.deinit(input.allocator()); - return .{ .result = reduced.swapRemove(0) }; - } - return .{ .result = This{ - .function = bun.create( - input.allocator(), - MathFunction(V), - MathFunction(V){ .min = reduced }, - ), - } }; - }, - .max => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(ArrayList(This)) { - return i.parseCommaSeparatedWithCtx(This, self, @This().parseOne); - } - pub fn parseOne(self: *@This(), i: *css.Parser) Result(This) { - return This.parseSum(i, self.ctx, parseIdent); - } - }; - var closure = Closure{ .ctx = ctx }; - var reduced = switch (input.parseNestedBlock(ArrayList(This), &closure, Closure.parseNestedBlockFn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - // PERF: i don't like this additional allocation - This.reduceArgs(input.allocator(), &reduced, std.math.Order.gt); - // var reduced: ArrayList(This) = This.reduceArgs(&args, std.math.Order.gt); - if (reduced.items.len == 1) { - return .{ .result = reduced.orderedRemove(0) }; - } - return .{ .result = This{ - .function = bun.create( - input.allocator(), - MathFunction(V), - MathFunction(V){ .max = reduced }, - ), - } }; - }, - .clamp => { - const ClosureResult = struct { ?This, This, ?This }; - const Closure = struct { - ctx: @TypeOf(ctx), - - pub fn parseNestedBlock(self: *@This(), i: *css.Parser) Result(ClosureResult) { - const min = switch (This.parseSum(i, self, parseIdentWrapper)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const center = switch (This.parseSum(i, self, parseIdentWrapper)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const max = switch (This.parseSum(i, self, parseIdentWrapper)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ min, center, max } }; - } - - pub fn parseIdentWrapper(self: *@This(), ident: []const u8) ?This { - return parseIdent(self.ctx, ident); - } - }; - var closure = Closure{ - .ctx = ctx, - }; - var min, var center, var max = switch (input.parseNestedBlock( - ClosureResult, - &closure, - Closure.parseNestedBlock, - )) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - // According to the spec, the minimum should "win" over the maximum if they are in the wrong order. - const cmp = if (max != null and max.? == .value and center == .value) - css.generic.partialCmp(V, center.value, max.?.value) - else - null; - - // If center is known to be greater than the maximum, replace it with maximum and remove the max argument. - // Otherwise, if center is known to be less than the maximum, remove the max argument. - if (cmp) |cmp_val| { - if (cmp_val == std.math.Order.gt) { - const val = max.?; - center = val; - max = null; - } else { - min = null; - } - } - - const switch_val: u8 = (@as(u8, @intFromBool(min != null)) << 1) | (@as(u8, @intFromBool(min != null))); - // switch (min, max) - return .{ .result = switch (switch_val) { - 0b00 => center, - 0b10 => This{ - .function = bun.create( - input.allocator(), - MathFunction(V), - MathFunction(V){ - .max = arr2( - input.allocator(), - min.?, - center, - ), - }, - ), - }, - 0b01 => This{ - .function = bun.create( - input.allocator(), - MathFunction(V), - MathFunction(V){ - .min = arr2( - input.allocator(), - max.?, - center, - ), - }, - ), - }, - 0b11 => This{ - .function = bun.create( - input.allocator(), - MathFunction(V), - MathFunction(V){ - .clamp = .{ - .min = min.?, - .center = center, - .max = max.?, - }, - }, - ), - }, - else => unreachable, - } }; - }, - .round => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - const strategy = if (i.tryParse(RoundingStrategy.parse, .{}).asValue()) |s| brk: { - if (i.expectComma().asErr()) |e| return .{ .err = e }; - break :brk s; - } else RoundingStrategy.default(); - - const OpAndFallbackCtx = struct { - strategy: RoundingStrategy, - - pub fn op(this: *const @This(), a: f32, b: f32) f32 { - return round({}, a, b, this.strategy); - } - - pub fn fallback(this: *const @This(), a: This, b: This) MathFunction(V) { - return MathFunction(V){ - .round = .{ - .strategy = this.strategy, - .value = a, - .interval = b, - }, - }; - } - }; - var ctx_for_op_and_fallback = OpAndFallbackCtx{ - .strategy = strategy, - }; - return This.parseMathFn( - i, - &ctx_for_op_and_fallback, - OpAndFallbackCtx.op, - OpAndFallbackCtx.fallback, - self.ctx, - parseIdent, - ); - } - }; - var closure = Closure{ - .ctx = ctx, - }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .rem => { - const Closure = struct { - ctx: @TypeOf(ctx), - - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - return This.parseMathFn( - i, - {}, - @This().rem, - mathFunctionRem, - self.ctx, - parseIdent, - ); - } - - pub fn rem(_: void, a: f32, b: f32) f32 { - return @mod(a, b); - } - pub fn mathFunctionRem(_: void, a: This, b: This) MathFunction(V) { - return MathFunction(V){ - .rem = .{ - .dividend = a, - .divisor = b, - }, - }; - } - }; - var closure = Closure{ - .ctx = ctx, - }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .mod => { - const Closure = struct { - ctx: @TypeOf(ctx), - - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - return This.parseMathFn( - i, - {}, - @This().modulo, - mathFunctionMod, - self.ctx, - parseIdent, - ); - } - - pub fn modulo(_: void, a: f32, b: f32) f32 { - // return ((a % b) + b) % b; - return @mod((@mod(a, b) + b), b); - } - pub fn mathFunctionMod(_: void, a: This, b: This) MathFunction(V) { - return MathFunction(V){ - .mod_ = .{ - .dividend = a, - .divisor = b, - }, - }; - } - }; - var closure = Closure{ - .ctx = ctx, - }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .sin => { - return This.parseTrig(input, .sin, false, ctx, parseIdent); - }, - .cos => { - return This.parseTrig(input, .cos, false, ctx, parseIdent); - }, - .tan => { - return This.parseTrig(input, .tan, false, ctx, parseIdent); - }, - .asin => { - return This.parseTrig(input, .asin, true, ctx, parseIdent); - }, - .acos => { - return This.parseTrig(input, .acos, true, ctx, parseIdent); - }, - .atan => { - return This.parseTrig(input, .atan, true, ctx, parseIdent); - }, - .atan2 => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - const res = switch (This.parseAtan2(i, self.ctx, parseIdent)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (css.generic.tryFromAngle(V, res)) |v| { - return .{ .result = This{ - .value = bun.create( - i.allocator(), - V, - v, - ), - } }; - } - - return .{ .err = i.newCustomError(css.ParserError{ .invalid_value = {} }) }; - } - }; - var closure = Closure{ .ctx = ctx }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .pow => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - const a = switch (This.parseNumeric(i, self.ctx, parseIdent)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - if (i.expectComma().asErr()) |e| return .{ .err = e }; - - const b = switch (This.parseNumeric(i, self.ctx, parseIdent)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = This{ - .number = bun.powf(a, b), - } }; - } - }; - var closure = Closure{ .ctx = ctx }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .log => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - const value = switch (This.parseNumeric(i, self.ctx, parseIdent)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (i.tryParse(css.Parser.expectComma, .{}).isOk()) { - const base = switch (This.parseNumeric(i, self.ctx, parseIdent)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = This{ .number = std.math.log(f32, base, value) } }; - } - return .{ .result = This{ .number = std.math.log(f32, std.math.e, value) } }; - } - }; - var closure = Closure{ .ctx = ctx }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .sqrt => { - return This.parseNumericFn(input, .sqrt, ctx, parseIdent); - }, - .exp => { - return This.parseNumericFn(input, .exp, ctx, parseIdent); - }, - .hypot => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - var args = switch (i.parseCommaSeparatedWithCtx(This, self, parseOne)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const val = switch (This.parseHypot(i.allocator(), &args)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - if (val) |v| return .{ .result = v }; - - return .{ .result = This{ - .function = bun.create( - i.allocator(), - MathFunction(V), - MathFunction(V){ .hypot = args }, - ), - } }; - } - - pub fn parseOne(self: *@This(), i: *css.Parser) Result(This) { - return This.parseSum(i, self.ctx, parseIdent); - } - }; - var closure = Closure{ .ctx = ctx }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .abs => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - const v = switch (This.parseSum(i, self.ctx, parseIdent)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = if (This.applyMap(&v, i.allocator(), absf)) |vv| vv else This{ - .function = bun.create( - i.allocator(), - MathFunction(V), - MathFunction(V){ .abs = v }, - ), - }, - }; - } - }; - var closure = Closure{ .ctx = ctx }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - .sign => { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - const v = switch (This.parseSum(i, self.ctx, parseIdent)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - switch (v) { - .number => |*n| return .{ .result = This{ .number = std.math.sign(n.*) } }, - .value => |v2| { - const MapFn = struct { - pub fn sign(s: f32) f32 { - return std.math.sign(s); - } - }; - // First map so we ignore percentages, which must be resolved to their - // computed value in order to determine the sign. - if (css.generic.tryMap(V, v2, MapFn.sign)) |new_v| { - // sign() alwasy resolves to a number. - return .{ - .result = This{ - // .number = css.generic.trySign(V, &new_v) orelse bun.unreachablePanic("sign always resolved to a number.", .{}), - .number = css.generic.trySign(V, &new_v) orelse @panic("sign() always resolves to a number."), - }, - }; - } - }, - else => {}, - } - - return .{ .result = This{ - .function = bun.create( - i.allocator(), - MathFunction(V), - MathFunction(V){ .sign = v }, - ), - } }; - } - }; - var closure = Closure{ .ctx = ctx }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - }, - } - } - - pub fn parseNumericFn(input: *css.Parser, comptime op: enum { sqrt, exp }, ctx: anytype, comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This) Result(This) { - const Closure = struct { ctx: @TypeOf(ctx) }; - var closure = Closure{ .ctx = ctx }; - return input.parseNestedBlock(This, &closure, struct { - pub fn parseNestedBlockFn(self: *Closure, i: *css.Parser) Result(This) { - const v = switch (This.parseNumeric(i, self.ctx, parse_ident)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - return .{ - .result = This{ - .number = switch (op) { - .sqrt => std.math.sqrt(v), - .exp => std.math.exp(v), - }, - }, - }; - } - }.parseNestedBlockFn); - } - - pub fn parseMathFn( - input: *css.Parser, - ctx_for_op_and_fallback: anytype, - comptime op: *const fn (@TypeOf(ctx_for_op_and_fallback), f32, f32) f32, - comptime fallback: *const fn (@TypeOf(ctx_for_op_and_fallback), This, This) MathFunction(V), - ctx_for_parse_ident: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx_for_parse_ident), []const u8) ?This, - ) Result(This) { - const a = switch (This.parseSum(input, ctx_for_parse_ident, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const b = switch (This.parseSum(input, ctx_for_parse_ident, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const val = This.applyOp(&a, &b, input.allocator(), ctx_for_op_and_fallback, op) orelse This{ - .function = bun.create( - input.allocator(), - MathFunction(V), - fallback(ctx_for_op_and_fallback, a, b), - ), - }; - - return .{ .result = val }; - } - - pub fn parseSum( - input: *css.Parser, - ctx: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(This) { - var cur = switch (This.parseProduct(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - while (true) { - const start = input.state(); - const tok = switch (input.nextIncludingWhitespace()) { - .result => |vv| vv, - .err => { - input.reset(&start); - break; - }, - }; - - if (tok.* == .whitespace) { - if (input.isExhausted()) { - break; // allow trailing whitespace - } - const next_tok = switch (input.next()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (next_tok.* == .delim and next_tok.delim == '+') { - const next = switch (This.parseProduct(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - cur = switch (cur.add(input.allocator(), next)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - } else if (next_tok.* == .delim and next_tok.delim == '-') { - var rhs = switch (This.parseProduct(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - rhs = rhs.mulF32(input.allocator(), -1.0); - cur = switch (cur.add(input.allocator(), rhs)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - } else { - return .{ .err = input.newUnexpectedTokenError(next_tok.*) }; - } - continue; - } - input.reset(&start); - break; - } - - return .{ .result = cur }; - } - - pub fn parseProduct( - input: *css.Parser, - ctx: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(This) { - var node = switch (This.parseValue(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - while (true) { - const start = input.state(); - const tok = switch (input.next()) { - .result => |vv| vv, - .err => { - input.reset(&start); - break; - }, - }; - - if (tok.* == .delim and tok.delim == '*') { - // At least one of the operands must be a number. - const rhs = switch (This.parseValue(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (rhs == .number) { - node = node.mulF32(input.allocator(), rhs.number); - } else if (node == .number) { - const val = node.number; - node = rhs; - node = node.mulF32(input.allocator(), val); - } else { - return .{ .err = input.newUnexpectedTokenError(.{ .delim = '*' }) }; - } - } else if (tok.* == .delim and tok.delim == '/') { - const rhs = switch (This.parseValue(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (rhs == .number) { - const val = rhs.number; - if (val != 0.0) { - node = node.mulF32(input.allocator(), 1.0 / val); - continue; - } - } - return .{ .err = input.newCustomError(css.ParserError{ .invalid_value = {} }) }; - } else { - input.reset(&start); - break; - } - } - return .{ .result = node }; - } - - pub fn parseValue( - input: *css.Parser, - ctx: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(This) { - // Parse nested calc() and other math functions. - if (input.tryParse(This.parse, .{}).asValue()) |_calc| { - const calc: This = _calc; - switch (calc) { - .function => |f| return switch (f.*) { - .calc => |c| .{ .result = c }, - else => .{ .result = .{ .function = f } }, - }, - else => return .{ .result = calc }, - } - } - - if (input.tryParse(css.Parser.expectParenthesisBlock, .{}).isOk()) { - const Closure = struct { - ctx: @TypeOf(ctx), - pub fn parseNestedBlockFn(self: *@This(), i: *css.Parser) Result(This) { - return This.parseSum(i, self.ctx, parse_ident); - } - }; - var closure = Closure{ - .ctx = ctx, - }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBlockFn); - } - - if (input.tryParse(css.Parser.expectNumber, .{}).asValue()) |num| { - return .{ .result = .{ .number = num } }; - } - - if (input.tryParse(Constant.parse, .{}).asValue()) |constant| { - return .{ .result = .{ .number = constant.intoF32() } }; - } - - const location = input.currentSourceLocation(); - if (input.tryParse(css.Parser.expectIdent, .{}).asValue()) |ident| { - if (parse_ident(ctx, ident)) |c| { - return .{ .result = c }; - } - - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - - const value = switch (input.tryParse(css.generic.parseFor(V), .{})) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ - .value = bun.create( - input.allocator(), - V, - value, - ), - } }; - } - - pub fn parseTrig( - input: *css.Parser, - comptime trig_fn_kind: enum { - sin, - cos, - tan, - asin, - acos, - atan, - }, - to_angle: bool, - ctx: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(This) { - const trig_fn = struct { - pub fn run(x: f32) f32 { - const mathfn = comptime switch (trig_fn_kind) { - .sin => std.math.sin, - .cos => std.math.cos, - .tan => std.math.tan, - .asin => std.math.asin, - .acos => std.math.acos, - .atan => std.math.atan, - }; - return mathfn(x); - } - }; - const Closure = struct { - ctx: @TypeOf(ctx), - to_angle: bool, - - pub fn parseNestedBockFn(this: *@This(), i: *css.Parser) Result(This) { - const v = switch (Calc(Angle).parseSum( - i, - this, - @This().parseIdentFn, - )) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const rad = rad: { - switch (v) { - .value => |angle| { - if (!this.to_angle) break :rad trig_fn.run(angle.toRadians()); - }, - .number => break :rad trig_fn.run(v.number), - else => {}, - } - return .{ .err = i.newCustomError(css.ParserError{ .invalid_value = {} }) }; - }; - - if (this.to_angle and !std.math.isNan(rad)) { - if (css.generic.tryFromAngle(V, .{ .rad = rad })) |val| { - return .{ .result = .{ - .value = bun.create( - i.allocator(), - V, - val, - ), - } }; - } - return .{ .err = i.newCustomError(css.ParserError{ .invalid_value = {} }) }; - } else { - return .{ .result = .{ .number = rad } }; - } - } - - pub fn parseIdentFn(this: *@This(), ident: []const u8) ?Calc(Angle) { - const v = parse_ident(this.ctx, ident) orelse return null; - if (v == .number) return .{ .number = v.number }; - return null; - } - }; - var closure = Closure{ - .ctx = ctx, - .to_angle = to_angle, - }; - return input.parseNestedBlock(This, &closure, Closure.parseNestedBockFn); - } - - pub fn ParseIdentNone(comptime Ctx: type, comptime Value: type) type { - return struct { - pub fn func(_: Ctx, _: []const u8) ?Calc(Value) { - return null; - } - }; - } - - pub fn parseAtan2( - input: *css.Parser, - ctx: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(Angle) { - const Ctx = @TypeOf(ctx); - - // atan2 supports arguments of any , , or , even ones that wouldn't - // normally be supported by V. The only requirement is that the arguments be of the same type. - // Try parsing with each type, and return the first one that parses successfully. - if (tryParseAtan2Args(Ctx, Length, input, ctx).asValue()) |v| { - return .{ .result = v }; - } - - if (tryParseAtan2Args(Ctx, Percentage, input, ctx).asValue()) |v| { - return .{ .result = v }; - } - - if (tryParseAtan2Args(Ctx, Angle, input, ctx).asValue()) |v| { - return .{ .result = v }; - } - - if (tryParseAtan2Args(Ctx, Time, input, ctx).asValue()) |v| { - return .{ .result = v }; - } - - const Closure = struct { - ctx: @TypeOf(ctx), - - pub fn parseIdentFn(self: *@This(), ident: []const u8) ?Calc(CSSNumber) { - const v = parse_ident(self.ctx, ident) orelse return null; - if (v == .number) return .{ .number = v.number }; - return null; - } - }; - var closure = Closure{ - .ctx = ctx, - }; - return Calc(CSSNumber).parseAtan2Args(input, &closure, Closure.parseIdentFn); - } - - inline fn tryParseAtan2Args( - comptime Ctx: type, - comptime Value: type, - input: *css.Parser, - ctx: Ctx, - ) Result(Angle) { - const func = ParseIdentNone(Ctx, Value).func; - return input.tryParseImpl(Result(Angle), Calc(Value).parseAtan2Args, .{ input, ctx, func }); - } - - pub fn parseAtan2Args( - input: *css.Parser, - ctx: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(Angle) { - const a = switch (This.parseSum(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const b = switch (This.parseSum(input, ctx, parse_ident)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - if (a == .value and b == .value) { - const Fn = struct { - pub fn opToFn(_: void, x: f32, y: f32) Angle { - return .{ .rad = std.math.atan2(x, y) }; - } - }; - if (css.generic.tryOpTo(V, Angle, a.value, b.value, {}, Fn.opToFn)) |v| { - return .{ .result = v }; - } - } else if (a == .number and b == .number) { - return .{ .result = Angle{ .rad = std.math.atan2(a.number, b.number) } }; - } else { - // doo nothing - } - - // We don't have a way to represent arguments that aren't angles, so just error. - // This will fall back to an unparsed property, leaving the atan2() function intact. - return .{ .err = input.newCustomError(css.ParserError{ .invalid_value = {} }) }; - } - - pub fn parseNumeric( - input: *css.Parser, - ctx: anytype, - comptime parse_ident: *const fn (@TypeOf(ctx), []const u8) ?This, - ) Result(f32) { - const Closure = struct { - ctx: @TypeOf(ctx), - - pub fn parseIdentFn(self: *@This(), ident: []const u8) ?Calc(CSSNumber) { - const v = parse_ident(self.ctx, ident) orelse return null; - if (v == .number) return .{ .number = v.number }; - return null; - } - }; - var closure = Closure{ - .ctx = ctx, - }; - const v: Calc(CSSNumber) = switch (Calc(CSSNumber).parseSum(input, &closure, Closure.parseIdentFn)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const val = switch (v) { - .number => v.number, - .value => v.value.*, - else => return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - }; - return .{ .result = val }; - } - - pub fn parseHypot(allocator: Allocator, args: *ArrayList(This)) Result(?This) { - if (args.items.len == 1) { - const v = args.items[0]; - args.items[0] = This{ .number = 0 }; - return .{ .result = v }; - } - - if (args.items.len == 2) { - return .{ .result = This.applyOp(&args.items[0], &args.items[1], allocator, {}, hypot) }; - } - - var i: usize = 0; - const first = if (This.applyMap( - &args.items[0], - allocator, - powi2, - )) |v| v else return .{ .result = null }; - i += 1; - var errored: bool = false; - var sum: This = first; - for (args.items[i..]) |*arg| { - const Fn = struct { - pub fn applyOpFn(_: void, a: f32, b: f32) f32 { - return a + bun.powf(b, 2); - } - }; - sum = This.applyOp(&sum, arg, allocator, {}, Fn.applyOpFn) orelse { - errored = true; - break; - }; - } - - if (errored) return .{ .result = null }; - - return .{ .result = This.applyMap(&sum, allocator, sqrtf32) }; - } - - pub fn applyOp( - a: *const This, - b: *const This, - allocator: std.mem.Allocator, - ctx: anytype, - comptime op: *const fn (@TypeOf(ctx), f32, f32) f32, - ) ?This { - if (a.* == .value and b.* == .value) { - if (css.generic.tryOp(V, a.value, b.value, ctx, op)) |v| { - return This{ - .value = bun.create( - allocator, - V, - v, - ), - }; - } - return null; - } - - if (a.* == .number and b.* == .number) { - return This{ - .number = op(ctx, a.number, b.number), - }; - } - - return null; - } - - pub fn applyMap(this: *const This, allocator: Allocator, comptime op: *const fn (f32) f32) ?This { - switch (this.*) { - .number => |n| return This{ .number = op(n) }, - .value => |v| { - if (css.generic.tryMap(V, v, op)) |new_v| { - return This{ - .value = bun.create( - allocator, - V, - new_v, - ), - }; - } - }, - else => {}, - } - - return null; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - const was_in_calc = dest.in_calc; - dest.in_calc = true; - - const res = toCssImpl(this, dest); - - dest.in_calc = was_in_calc; - return res; - } - - pub fn toCssImpl(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .value => |v| v.toCss(dest), - .number => |n| CSSNumberFns.toCss(&n, dest), - .sum => |sum| { - const a = sum.left; - const b = sum.right; - try a.toCss(dest); - // White space is always required. - if (b.isSignNegative()) { - try dest.writeStr(" - "); - var b2 = b.deepClone(dest.allocator).mulF32(dest.allocator, -1.0); - defer b2.deinit(dest.allocator); - try b2.toCss(dest); - } else { - try dest.writeStr(" + "); - try b.toCss(dest); - } - return; - }, - .product => { - const num = this.product.number; - const calc = this.product.expression; - if (@abs(num) < 1.0) { - const div = 1.0 / num; - try calc.toCss(dest); - try dest.delim('/', true); - try CSSNumberFns.toCss(&div, dest); - } else { - try CSSNumberFns.toCss(&num, dest); - try dest.delim('*', true); - try calc.toCss(dest); - } - }, - .function => |f| return f.toCss(dest), - }; - } - - pub fn trySign(this: *const @This()) ?f32 { - return switch (this.*) { - .value => |v| return switch (V) { - f32 => css.signfns.signF32(v), - else => v.trySign(), - }, - .number => |n| css.signfns.signF32(n), - else => null, - }; - } - - pub fn isSignNegative(this: *const @This()) bool { - return css.signfns.isSignNegative(this.trySign() orelse return false); - } - - pub fn mulF32(this: @This(), allocator: Allocator, other: f32) This { - if (other == 1.0) { - return this; - } - - return switch (this) { - // PERF: why not reuse the allocation here? - .value => This{ .value = bun.create(allocator, V, mulValueF32(this.value.*, allocator, other)) }, - .number => This{ .number = this.number * other }, - // PERF: why not reuse the allocation here? - .sum => This{ .sum = .{ - .left = bun.create( - allocator, - This, - this.sum.left.mulF32(allocator, other), - ), - .right = bun.create( - allocator, - This, - this.sum.right.mulF32(allocator, other), - ), - } }, - .product => { - const num = this.product.number * other; - if (num == 1.0) { - return this.product.expression.*; - } - return This{ - .product = .{ - .number = num, - .expression = this.product.expression, - }, - }; - }, - .function => switch (this.function.*) { - // PERF: why not reuse the allocation here? - .calc => This{ - .function = bun.create( - allocator, - MathFunction(V), - MathFunction(V){ - .calc = this.function.calc.mulF32(allocator, other), - }, - ), - }, - else => This{ - .product = .{ - .number = other, - .expression = bun.create(allocator, This, this), - }, - }, - }, - }; - } - - /// PERF: - /// I don't like how this function requires allocating a second ArrayList - /// I am pretty sure we could do this reduction in place, or do it as the - /// arguments are being parsed. - fn reduceArgs(allocator: Allocator, args: *ArrayList(This), order: std.math.Order) void { - // Reduces the arguments of a min() or max() expression, combining compatible values. - // e.g. min(1px, 1em, 2px, 3in) => min(1px, 1em) - var reduced = ArrayList(This){}; - - for (args.items) |*arg| { - var found: ??*This = null; - switch (arg.*) { - .value => |val| { - for (reduced.items) |*b| { - switch (b.*) { - .value => |v| { - const result = css.generic.partialCmp(V, val, v); - if (result != null) { - if (result == order) { - found = b; - break; - } else { - found = @as(?*This, null); - break; - } - } - }, - else => {}, - } - } - }, - else => {}, - } - - if (found) |__r| { - if (__r) |r| { - r.* = arg.*; - // set to dummy value since we moved it into `reduced` - arg.* = This{ .number = 420 }; - continue; - } - } else { - bun.handleOom(reduced.append(allocator, arg.*)); - // set to dummy value since we moved it into `reduced` - arg.* = This{ .number = 420 }; - continue; - } - arg.deinit(allocator); - arg.* = This{ .number = 420 }; - } - - css.deepDeinit(This, allocator, args); - args.* = reduced; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .sum => |*args| return args.left.isCompatible(browsers) and args.right.isCompatible(browsers), - .product => |*args| return args.expression.isCompatible(browsers), - .function => |f| f.isCompatible(browsers), - .value => |v| v.isCompatible(browsers), - .number => true, - }; - } - }; -} - -/// A CSS math function. -/// -/// Math functions may be used in most properties and values that accept numeric -/// values, including lengths, percentages, angles, times, etc. -pub fn MathFunction(comptime V: type) type { - return union(enum) { - /// The `calc()` function. - calc: ThisCalc, - /// The `min()` function. - min: ArrayList(ThisCalc), - /// The `max()` function. - max: ArrayList(ThisCalc), - /// The `clamp()` function. - clamp: struct { - min: ThisCalc, - center: ThisCalc, - max: ThisCalc, - }, - /// The `round()` function. - round: struct { - strategy: RoundingStrategy, - value: ThisCalc, - interval: ThisCalc, - }, - /// The `rem()` function. - rem: struct { - dividend: ThisCalc, - divisor: ThisCalc, - }, - /// The `mod()` function. - mod_: struct { - dividend: ThisCalc, - divisor: ThisCalc, - }, - /// The `abs()` function. - abs: ThisCalc, - /// The `sign()` function. - sign: ThisCalc, - /// The `hypot()` function. - hypot: ArrayList(ThisCalc), - - const ThisCalc = Calc(V); - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return switch (this.*) { - .calc => |a| return other.* == .calc and a.eql(&other.calc), - .min => |*a| return other.* == .min and css.generic.eqlList(ThisCalc, a, &other.min), - .max => |*a| return other.* == .max and css.generic.eqlList(ThisCalc, a, &other.max), - .clamp => |*a| return other.* == .clamp and a.min.eql(&other.clamp.min) and a.center.eql(&other.clamp.center) and a.max.eql(&other.clamp.max), - .round => |*a| return other.* == .round and a.strategy == other.round.strategy and a.value.eql(&other.round.value) and a.interval.eql(&other.round.interval), - .rem => |*a| return other.* == .rem and a.dividend.eql(&other.rem.dividend) and a.divisor.eql(&other.rem.divisor), - .mod_ => |*a| return other.* == .mod_ and a.dividend.eql(&other.mod_.dividend) and a.divisor.eql(&other.mod_.divisor), - .abs => |*a| return other.* == .abs and a.eql(&other.abs), - .sign => |*a| return other.* == .sign and a.eql(&other.sign), - .hypot => |*a| return other.* == .hypot and css.generic.eqlList(ThisCalc, a, &other.hypot), - }; - } - - pub fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return switch (this.*) { - .calc => |*calc| .{ .calc = calc.deepClone(allocator) }, - .min => |*min| .{ .min = css.deepClone(ThisCalc, allocator, min) }, - .max => |*max| .{ .max = css.deepClone(ThisCalc, allocator, max) }, - .clamp => |*clamp| .{ - .clamp = .{ - .min = clamp.min.deepClone(allocator), - .center = clamp.center.deepClone(allocator), - .max = clamp.max.deepClone(allocator), - }, - }, - .round => |*rnd| .{ .round = .{ - .strategy = rnd.strategy, - .value = rnd.value.deepClone(allocator), - .interval = rnd.interval.deepClone(allocator), - } }, - .rem => |*rem| .{ .rem = .{ - .dividend = rem.dividend.deepClone(allocator), - .divisor = rem.divisor.deepClone(allocator), - } }, - .mod_ => |*mod_| .{ .mod_ = .{ - .dividend = mod_.dividend.deepClone(allocator), - .divisor = mod_.divisor.deepClone(allocator), - } }, - .abs => |*abs| .{ .abs = abs.deepClone(allocator) }, - .sign => |*sign| .{ .sign = sign.deepClone(allocator) }, - .hypot => |*hyp| .{ - .hypot = css.deepClone(ThisCalc, allocator, hyp), - }, - }; - } - - pub fn deinit(this: *@This(), allocator: Allocator) void { - switch (this.*) { - .calc => |*calc| calc.deinit(allocator), - .min => |*min| css.deepDeinit(ThisCalc, allocator, min), - .max => |*max| css.deepDeinit(ThisCalc, allocator, max), - .clamp => |*clamp| { - clamp.min.deinit(allocator); - clamp.center.deinit(allocator); - clamp.max.deinit(allocator); - }, - .round => |*rnd| { - rnd.value.deinit(allocator); - rnd.interval.deinit(allocator); - }, - .rem => |*rem| { - rem.dividend.deinit(allocator); - rem.divisor.deinit(allocator); - }, - .mod_ => |*mod_| { - mod_.dividend.deinit(allocator); - mod_.divisor.deinit(allocator); - }, - .abs => |*abs| { - abs.deinit(allocator); - }, - .sign => |*sign| { - sign.deinit(allocator); - }, - .hypot => |*hyp| { - css.deepDeinit(ThisCalc, allocator, hyp); - }, - } - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .calc => |*calc| { - try dest.writeStr("calc("); - try calc.toCss(dest); - try dest.writeChar(')'); - }, - .min => |*args| { - try dest.writeStr("min("); - var first = true; - for (args.items) |*arg| { - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - try arg.toCss(dest); - } - try dest.writeChar(')'); - }, - .max => |*args| { - try dest.writeStr("max("); - var first = true; - for (args.items) |*arg| { - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - try arg.toCss(dest); - } - try dest.writeChar(')'); - }, - .clamp => |*clamp| { - try dest.writeStr("clamp("); - try clamp.min.toCss(dest); - try dest.delim(',', false); - try clamp.center.toCss(dest); - try dest.delim(',', false); - try clamp.max.toCss(dest); - try dest.writeChar(')'); - }, - .round => |*rnd| { - try dest.writeStr("round("); - if (rnd.strategy != RoundingStrategy.default()) { - try rnd.strategy.toCss(dest); - try dest.delim(',', false); - } - try rnd.value.toCss(dest); - try dest.delim(',', false); - try rnd.interval.toCss(dest); - try dest.writeChar(')'); - }, - .rem => |*rem| { - try dest.writeStr("rem("); - try rem.dividend.toCss(dest); - try dest.delim(',', false); - try rem.divisor.toCss(dest); - try dest.writeChar(')'); - }, - .mod_ => |*mod_| { - try dest.writeStr("mod("); - try mod_.dividend.toCss(dest); - try dest.delim(',', false); - try mod_.divisor.toCss(dest); - try dest.writeChar(')'); - }, - .abs => |*v| { - try dest.writeStr("abs("); - try v.toCss(dest); - try dest.writeChar(')'); - }, - .sign => |*v| { - try dest.writeStr("sign("); - try v.toCss(dest); - try dest.writeChar(')'); - }, - .hypot => |*args| { - try dest.writeStr("hypot("); - var first = true; - for (args.items) |*arg| { - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - try arg.toCss(dest); - } - try dest.writeChar(')'); - }, - }; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - const F = css.compat.Feature; - return switch (this.*) { - .calc => |*c| F.isCompatible(F.calc_function, browsers) and c.isCompatible(browsers), - .min => |*m| F.isCompatible(F.min_function, browsers) and brk: { - for (m.items) |*arg| { - if (!arg.isCompatible(browsers)) { - break :brk false; - } - } - break :brk true; - }, - .max => |*m| F.isCompatible(F.max_function, browsers) and brk: { - for (m.items) |*arg| { - if (!arg.isCompatible(browsers)) { - break :brk false; - } - } - break :brk true; - }, - .clamp => |*c| F.isCompatible(F.clamp_function, browsers) and - c.min.isCompatible(browsers) and - c.center.isCompatible(browsers) and - c.max.isCompatible(browsers), - .round => |*r| F.isCompatible(F.round_function, browsers) and - r.value.isCompatible(browsers) and - r.interval.isCompatible(browsers), - .rem => |*r| F.isCompatible(F.rem_function, browsers) and - r.dividend.isCompatible(browsers) and - r.divisor.isCompatible(browsers), - .mod_ => |*m| F.isCompatible(F.mod_function, browsers) and - m.dividend.isCompatible(browsers) and - m.divisor.isCompatible(browsers), - .abs => |*a| F.isCompatible(F.abs_function, browsers) and - a.isCompatible(browsers), - .sign => |*s| F.isCompatible(F.sign_function, browsers) and - s.isCompatible(browsers), - .hypot => |*h| F.isCompatible(F.hypot_function, browsers) and brk: { - for (h.items) |*arg| { - if (!arg.isCompatible(browsers)) { - break :brk false; - } - } - break :brk true; - }, - }; - } - }; -} - -/// A [rounding strategy](https://www.w3.org/TR/css-values-4/#typedef-rounding-strategy), -/// as used in the `round()` function. -pub const RoundingStrategy = enum { - /// Round to the nearest integer. - nearest, - /// Round up (ceil). - up, - /// Round down (floor). - down, - /// Round toward zero (truncate). - @"to-zero", - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn default() RoundingStrategy { - return .nearest; - } -}; - -fn arr2(allocator: std.mem.Allocator, a: anytype, b: anytype) ArrayList(@TypeOf(a)) { - const T = @TypeOf(a); - if (T != @TypeOf(b)) { - @compileError("arr2: types must match"); - } - var arr = ArrayList(T){}; - bun.handleOom(arr.appendSlice(allocator, &.{ a, b })); - return arr; -} - -fn round(_: void, value: f32, to: f32, strategy: RoundingStrategy) f32 { - const v = value / to; - return switch (strategy) { - .down => @floor(v) * to, - .up => @ceil(v) * to, - .nearest => @round(v) * to, - .@"to-zero" => @trunc(v) * to, - }; -} - -fn hypot(_: void, a: f32, b: f32) f32 { - return std.math.hypot(a, b); -} - -fn powi2(v: f32) f32 { - return bun.powf(v, 2); -} - -fn sqrtf32(v: f32) f32 { - return std.math.sqrt(v); -} -/// A mathematical constant. -pub const Constant = enum { - /// The base of the natural logarithm - e, - /// The ratio of a circle's circumference to its diameter - pi, - /// infinity - infinity, - /// -infinity - @"-infinity", - /// Not a number. - nan, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn intoF32(this: *const @This()) f32 { - return switch (this.*) { - .e => std.math.e, - .pi => std.math.pi, - .infinity => std.math.inf(f32), - .@"-infinity" => -std.math.inf(f32), - .nan => std.math.nan(f32), - }; - } -}; - -fn absf(a: f32) f32 { - return @abs(a); -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/values/color.zig b/src/css/values/color.zig deleted file mode 100644 index b1acc1ff8316..000000000000 --- a/src/css/values/color.zig +++ /dev/null @@ -1,4716 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const Result = css.Result; - -const Percentage = css.css_values.percentage.Percentage; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const Calc = css.css_values.calc.Calc; -const Angle = css.css_values.angle.Angle; - -const Printer = css.Printer; -const PrintErr = css.PrintErr; - -pub fn UnboundedColorGamut(comptime T: type) type { - return struct { - pub fn inGamut(_: *const T) bool { - return true; - } - - pub fn clip(this: *const T) T { - return this.*; - } - }; -} - -pub fn HslHwbColorGamut(comptime T: type, comptime a: []const u8, comptime b: []const u8) type { - return struct { - pub fn inGamut(this: *const T) bool { - return @field(this, a) >= 0.0 and - @field(this, a) <= 1.0 and - @field(this, b) >= 0.0 and - @field(this, b) <= 1.0; - } - - pub fn clip(this: *const T) T { - var result: T = this.*; - // result.h = this.h % 360.0; - result.h = @mod(this.h, 360.0); - @field(result, a) = bun.clamp(@field(this, a), 0.0, 1.0); - @field(result, b) = bun.clamp(@field(this, b), 0.0, 1.0); - result.alpha = bun.clamp(this.alpha, 0.0, 1.0); - return result; - } - }; -} - -/// A CSS `` value. -/// -/// CSS supports many different color spaces to represent colors. The most common values -/// are stored as RGBA using a single byte per component. Less common values are stored -/// using a `Box` to reduce the amount of memory used per color. -/// -/// Each color space is represented as a struct that implements the `From` and `Into` traits -/// for all other color spaces, so it is possible to convert between color spaces easily. -/// In addition, colors support interpolation as in the `color-mix()` function. -pub const CssColor = union(enum) { - /// The `currentColor` keyword. - current_color, - /// A value in the RGB color space, including values parsed as hex colors, or the `rgb()`, `hsl()`, and `hwb()` functions. - rgba: RGBA, - /// A value in a LAB color space, including the `lab()`, `lch()`, `oklab()`, and `oklch()` functions. - lab: *LABColor, - /// A value in a predefined color space, e.g. `display-p3`. - predefined: *PredefinedColor, - /// A floating point representation of an RGB, HSL, or HWB color when it contains `none` components. - float: *FloatColor, - /// The `light-dark()` function. - light_dark: struct { - // TODO: why box the two fields separately? why not one allocation? - light: *CssColor, - dark: *CssColor, - - pub fn takeLightFreeDark(this: *const @This(), allocator: Allocator) *CssColor { - const ret = this.light; - this.dark.deinit(allocator); - allocator.destroy(this.dark); - return ret; - } - - pub fn takeDarkFreeLight(this: *const @This(), allocator: Allocator) *CssColor { - const ret = this.dark; - this.light.deinit(allocator); - allocator.destroy(this.light); - return ret; - } - - pub fn __generateHash() void {} - }, - /// A system color keyword. - system: SystemColor, - - const This = @This(); - - pub const jsFunctionColor = @import("../../css_jsc/color_js.zig").jsFunctionColor; - - pub fn isCompatible(this: *const CssColor, browsers: css.targets.Browsers) bool { - return switch (this.*) { - .current_color, .rgba, .float => true, - .lab => |lab| switch (lab.*) { - .lab, .lch => css.Feature.isCompatible(.lab_colors, browsers), - .oklab, .oklch => css.Feature.isCompatible(.oklab_colors, browsers), - }, - .predefined => |predefined| switch (predefined.*) { - .display_p3 => css.Feature.isCompatible(.p3_colors, browsers), - else => css.Feature.isCompatible(.color_function, browsers), - }, - .light_dark => |light_dark| css.Feature.isCompatible(.light_dark, browsers) and - light_dark.light.isCompatible(browsers) and - light_dark.dark.isCompatible(browsers), - .system => |system| system.isCompatible(browsers), - }; - } - - pub fn toCss( - this: *const This, - dest: *Printer, - ) PrintErr!void { - switch (this.*) { - .current_color => try dest.writeStr("currentColor"), - .rgba => |*color| { - if (color.alpha == 255) { - const hex: u32 = (@as(u32, color.red) << 16) | (@as(u32, color.green) << 8) | @as(u32, color.blue); - if (shortColorName(hex)) |name| return dest.writeStr(name); - - const compact = compactHex(hex); - if (hex == expandHex(compact)) { - try dest.writeFmt("#{x:0>3}", .{compact}); - } else { - try dest.writeFmt("#{x:0>6}", .{hex}); - } - } else { - // If the #rrggbbaa syntax is not supported by the browser targets, output rgba() - if (dest.targets.shouldCompileSame(.hex_alpha_colors)) { - // If the browser doesn't support `#rrggbbaa` color syntax, it is converted to `transparent` when compressed(minify = true). - // https://www.w3.org/TR/css-color-4/#transparent-black - if (dest.minify and color.red == 0 and color.green == 0 and color.blue == 0 and color.alpha == 0) { - return dest.writeStr("transparent"); - } else { - try dest.writeFmt("rgba({d}", .{color.red}); - try dest.delim(',', false); - try dest.writeFmt("{d}", .{color.green}); - try dest.delim(',', false); - try dest.writeFmt("{d}", .{color.blue}); - try dest.delim(',', false); - - // Try first with two decimal places, then with three. - var rounded_alpha = @round(color.alphaF32() * 100.0) / 100.0; - const clamped: u8 = bun.intFromFloat(u8, @min( - @max( - @round(rounded_alpha * 255.0), - 0.0, - ), - 255.0, - )); - if (clamped != color.alpha) { - rounded_alpha = @round(color.alphaF32() * 1000.0) / 1000.0; - } - - try CSSNumberFns.toCss(&rounded_alpha, dest); - try dest.writeChar(')'); - return; - } - } - - const hex: u32 = (@as(u32, color.red) << 24) | - (@as(u32, color.green) << 16) | - (@as(u32, color.blue) << 8) | - (@as(u32, color.alpha)); - const compact = compactHex(hex); - if (hex == expandHex(compact)) { - try dest.writeFmt("#{x:0>4}", .{compact}); - } else { - try dest.writeFmt("#{x:0>8}", .{hex}); - } - } - return; - }, - .lab => |_lab| { - return switch (_lab.*) { - .lab => |*lab| writeComponents( - "lab", - lab.l, - lab.a, - lab.b, - lab.alpha, - dest, - ), - .lch => |*lch| writeComponents( - "lch", - lch.l, - lch.c, - lch.h, - lch.alpha, - dest, - ), - .oklab => |*oklab| writeComponents( - "oklab", - oklab.l, - oklab.a, - oklab.b, - oklab.alpha, - dest, - ), - .oklch => |*oklch| writeComponents( - "oklch", - oklch.l, - oklch.c, - oklch.h, - oklch.alpha, - dest, - ), - }; - }, - .predefined => |predefined| return writePredefined(predefined, dest), - .float => |*float| { - // Serialize as hex. - const srgb = SRGB.fromFloatColor(float.*); - const as_css_color = srgb.intoCssColor(dest.allocator); - defer as_css_color.deinit(dest.allocator); - try as_css_color.toCss(dest); - }, - .light_dark => |*light_dark| { - if (!dest.targets.isCompatible(css.compat.Feature.light_dark)) { - try dest.writeStr("var(--buncss-light"); - try dest.delim(',', false); - try light_dark.light.toCss(dest); - try dest.writeChar(')'); - try dest.whitespace(); - try dest.writeStr("var(--buncss-dark"); - try dest.delim(',', false); - try light_dark.dark.toCss(dest); - return dest.writeChar(')'); - } - - try dest.writeStr("light-dark("); - try light_dark.light.toCss(dest); - try dest.delim(',', false); - try light_dark.dark.toCss(dest); - return dest.writeChar(')'); - }, - .system => |*system| return system.toCss(dest), - } - } - - pub const ParseResult = Result(CssColor); - pub fn parse(input: *css.Parser) ParseResult { - const location = input.currentSourceLocation(); - const token = switch (input.next()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - switch (token.*) { - .unrestrictedhash, .idhash => |v| { - const r, const g, const b, const a = css.color.parseHashColor(v) orelse return .{ .err = location.newUnexpectedTokenError(token.*) }; - return .{ .result = .{ - .rgba = RGBA.new(r, g, b, a), - } }; - }, - .ident => |value| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(value, "currentcolor")) { - return .{ .result = .current_color }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(value, "transparent")) { - return .{ .result = .{ - .rgba = RGBA.transparent(), - } }; - } else { - if (css.color.parseNamedColor(value)) |named| { - const r, const g, const b = named; - return .{ .result = .{ .rgba = RGBA.new(r, g, b, 255.0) } }; - // } else if (SystemColor.parseString(value)) |system_color| { - } else if (css.parse_utility.parseString(input.allocator(), SystemColor, value, SystemColor.parse).asValue()) |system_color| { - return .{ .result = .{ .system = system_color } }; - } else return .{ .err = location.newUnexpectedTokenError(token.*) }; - } - }, - .function => |name| return parseColorFunction(location, name, input), - else => return .{ - .err = location.newUnexpectedTokenError(token.*), - }, - } - } - - pub fn deinit(this: CssColor, allocator: Allocator) void { - switch (this) { - .current_color => {}, - .rgba => {}, - .lab => { - allocator.destroy(this.lab); - }, - .predefined => { - allocator.destroy(this.predefined); - }, - .float => { - allocator.destroy(this.float); - }, - .light_dark => { - this.light_dark.light.deinit(allocator); - this.light_dark.dark.deinit(allocator); - allocator.destroy(this.light_dark.light); - allocator.destroy(this.light_dark.dark); - }, - .system => {}, - } - } - - pub fn deepClone(this: *const CssColor, allocator: Allocator) CssColor { - return switch (this.*) { - .current_color => .current_color, - .rgba => |rgba| CssColor{ .rgba = rgba }, - .lab => |lab| CssColor{ .lab = bun.create(allocator, LABColor, lab.*) }, - .predefined => |pre| CssColor{ .predefined = bun.create(allocator, PredefinedColor, pre.*) }, - .float => |float| CssColor{ .float = bun.create(allocator, FloatColor, float.*) }, - .light_dark => CssColor{ - .light_dark = .{ - .light = bun.create(allocator, CssColor, this.light_dark.light.deepClone(allocator)), - .dark = bun.create(allocator, CssColor, this.light_dark.dark.deepClone(allocator)), - }, - }, - .system => |sys| CssColor{ .system = sys }, - }; - } - - pub fn toLightDark(this: *const CssColor, allocator: Allocator) CssColor { - return switch (this.*) { - .light_dark => this.deepClone(allocator), - else => .{ - .light_dark = .{ - .light = bun.create(allocator, CssColor, this.deepClone(allocator)), - .dark = bun.create(allocator, CssColor, this.deepClone(allocator)), - }, - }, - }; - } - - /// Mixes this color with another color, including the specified amount of each. - /// Implemented according to the [`color-mix()`](https://www.w3.org/TR/css-color-5/#color-mix) function. - // PERF: these little allocations feel bad - pub fn interpolate( - this: *const CssColor, - allocator: Allocator, - comptime T: type, - p1_: f32, - other: *const CssColor, - p2_: f32, - method: HueInterpolationMethod, - ) ?CssColor { - var p1 = p1_; - var p2 = p2_; - - if (this.* == .current_color or other.* == .current_color) { - return null; - } - - if (this.* == .light_dark or other.* == .light_dark) { - const this_light_dark = this.toLightDark(allocator); - const other_light_dark = other.toLightDark(allocator); - - const al = this_light_dark.light_dark.light; - const ad = this_light_dark.light_dark.dark; - - const bl = other_light_dark.light_dark.light; - const bd = other_light_dark.light_dark.dark; - - return .{ - .light_dark = .{ - .light = bun.create( - allocator, - CssColor, - al.interpolate(allocator, T, p1, bl, p2, method) orelse return null, - ), - .dark = bun.create( - allocator, - CssColor, - ad.interpolate(allocator, T, p1, bd, p2, method) orelse return null, - ), - }, - }; - } - - const check_converted = struct { - fn run(color: *const CssColor) css.Result(bool) { - bun.debugAssert(color.* != .light_dark and color.* != .current_color); - return switch (color.*) { - .rgba => .{ .result = T == RGBA }, - .lab => |lab| .{ .result = switch (lab.*) { - .lab => T == LAB, - .lch => T == LCH, - .oklab => T == OKLAB, - .oklch => T == OKLCH, - } }, - .predefined => |pre| .{ .result = switch (pre.*) { - .srgb => T == SRGB, - .srgb_linear => T == SRGBLinear, - .display_p3 => T == P3, - .a98 => T == A98, - .prophoto => T == ProPhoto, - .rec2020 => T == Rec2020, - .xyz_d50 => T == XYZd50, - .xyz_d65 => T == XYZd65, - } }, - .float => |f| .{ .result = switch (f.*) { - .rgb => T == SRGB, - .hsl => T == HSL, - .hwb => T == HWB, - } }, - // System colors cannot be converted to specific color spaces at parse time - .system => .{ .err = css.ParseError(css.ParserError){ - .kind = .{ .custom = .{ .unexpected_value = .{ - .expected = "convertible color", - .received = "system color", - } } }, - .location = css.SourceLocation{ .line = 0, .column = 0 }, - } }, - // We checked these above - .light_dark, .current_color => unreachable, - }; - } - }; - - const converted_first = switch (check_converted.run(this)) { - .result => |v| v, - .err => return null, - }; - const converted_second = switch (check_converted.run(other)) { - .result => |v| v, - .err => return null, - }; - - // https://drafts.csswg.org/css-color-5/#color-mix-result - var first_color = T.tryFromCssColor(this) orelse return null; - var second_color = T.tryFromCssColor(other) orelse return null; - - if (converted_first and !first_color.inGamut()) { - first_color = mapGamut(T, first_color); - } - - if (converted_second and !second_color.inGamut()) { - second_color = mapGamut(T, second_color); - } - - // https://www.w3.org/TR/css-color-4/#powerless - if (converted_first) { - first_color.adjustPowerlessComponents(); - } - - if (converted_second) { - second_color.adjustPowerlessComponents(); - } - - // https://drafts.csswg.org/css-color-4/#interpolation-missing - first_color.fillMissingComponents(&second_color); - second_color.fillMissingComponents(&first_color); - - // https://www.w3.org/TR/css-color-4/#hue-interpolation - first_color.adjustHue(&second_color, method); - - // https://www.w3.org/TR/css-color-4/#interpolation-alpha - first_color.premultiply(); - second_color.premultiply(); - - // https://drafts.csswg.org/css-color-5/#color-mix-percent-norm - var alpha_multiplier = p1 + p2; - if (alpha_multiplier != 1.0) { - p1 = p1 / alpha_multiplier; - p2 = p2 / alpha_multiplier; - if (alpha_multiplier > 1.0) { - alpha_multiplier = 1.0; - } - } - - var result_color = first_color.interpolate(p1, &second_color, p2); - - result_color.unpremultiply(alpha_multiplier); - - return result_color.intoCssColor(allocator); - } - - pub fn lightDarkOwned(allocator: Allocator, light: CssColor, dark: CssColor) CssColor { - return CssColor{ - .light_dark = .{ - .light = bun.create(allocator, CssColor, light), - .dark = bun.create(allocator, CssColor, dark), - }, - }; - } - - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: ColorFallbackKind) CssColor { - if (this.* == .rgba) return this.deepClone(allocator); - - return switch (kind.asBits()) { - ColorFallbackKind.RGB.asBits() => this.toRGB(allocator).?, - ColorFallbackKind.P3.asBits() => this.toP3(allocator).?, - ColorFallbackKind.LAB.asBits() => this.toLAB(allocator).?, - else => bun.unreachablePanic("Expected RGBA, P3, LAB fallback. This is a bug in Bun.", .{}), - }; - } - - pub fn getFallbacks(this: *@This(), allocator: Allocator, targets: css.targets.Targets) css.SmallList(CssColor, 2) { - const fallbacks = this.getNecessaryFallbacks(targets); - - var res = css.SmallList(CssColor, 2){}; - - if (fallbacks.rgb) { - res.appendAssumeCapacity(this.toRGB(allocator).?); - } - - if (fallbacks.p3) { - res.appendAssumeCapacity(this.toP3(allocator).?); - } - - if (fallbacks.lab) { - const foo = this.toLAB(allocator).?; - this.* = foo; - } - - return res; - } - - /// Returns the color fallback types needed for the given browser targets. - pub fn getNecessaryFallbacks(this: *const @This(), targets: css.targets.Targets) ColorFallbackKind { - // Get the full set of possible fallbacks, and remove the highest one, which - // will replace the original declaration. The remaining fallbacks need to be added. - const fallbacks = this.getPossibleFallbacks(targets); - return fallbacks.difference(fallbacks.highest()); - } - - pub fn getPossibleFallbacks(this: *const @This(), targets: css.targets.Targets) ColorFallbackKind { - // Fallbacks occur in levels: Oklab -> Lab -> P3 -> RGB. We start with all levels - // below and including the authored color space, and remove the ones that aren't - // compatible with our browser targets. - var fallbacks = switch (this.*) { - .current_color, .rgba, .float, .system => return ColorFallbackKind{}, - .lab => |lab| brk: { - if (lab.* == .lab or lab.* == .lch and targets.shouldCompileSame(.lab_colors)) - break :brk ColorFallbackKind.andBelow(.{ .lab = true }); - if (lab.* == .oklab or lab.* == .oklch and targets.shouldCompileSame(.oklab_colors)) - break :brk ColorFallbackKind.andBelow(.{ .oklab = true }); - return ColorFallbackKind{}; - }, - .predefined => |predefined| brk: { - if (predefined.* == .display_p3 and targets.shouldCompileSame(.p3_colors)) break :brk ColorFallbackKind.andBelow(.{ .p3 = true }); - if (targets.shouldCompileSame(.color_function)) break :brk ColorFallbackKind.andBelow(.{ .lab = true }); - return ColorFallbackKind{}; - }, - .light_dark => |*ld| { - return bun.bits.@"or"(ColorFallbackKind, ld.light.getPossibleFallbacks(targets), ld.dark.getPossibleFallbacks(targets)); - }, - }; - - if (fallbacks.oklab) { - if (!targets.shouldCompileSame(.oklab_colors)) { - fallbacks = fallbacks.difference(ColorFallbackKind.andBelow(.{ .lab = true })); - } - } - - if (fallbacks.lab) { - if (!targets.shouldCompileSame(.lab_colors)) { - fallbacks = fallbacks.difference(ColorFallbackKind.andBelow(.{ .p3 = true })); - } else if (targets.browsers != null and css.compat.Feature.isPartiallyCompatible(&css.compat.Feature.lab_colors, targets.browsers.?)) { - // We don't need P3 if Lab is supported by some of our targets. - // No browser implements Lab but not P3. - fallbacks.p3 = false; - } - } - - if (fallbacks.p3) { - if (!targets.shouldCompileSame(.p3_colors)) { - fallbacks.rgb = false; - } else if (fallbacks.highest() != ColorFallbackKind.P3 and - (targets.browsers == null or !css.compat.Feature.isPartiallyCompatible(&css.compat.Feature.p3_colors, targets.browsers.?))) - { - // Remove P3 if it isn't supported by any targets, and wasn't the - // original authored color. - fallbacks.p3 = false; - } - } - - return fallbacks; - } - - pub fn default() @This() { - return .{ .rgba = RGBA.transparent() }; - } - - pub fn eql(this: *const This, other: *const This) bool { - if (@intFromEnum(this.*) != @intFromEnum(other.*)) return false; - - return switch (this.*) { - .current_color => true, - .rgba => std.meta.eql(this.rgba, other.rgba), - .lab => std.meta.eql(this.lab.*, other.lab.*), - .predefined => std.meta.eql(this.predefined.*, other.predefined.*), - .float => std.meta.eql(this.float.*, other.float.*), - .light_dark => this.light_dark.light.eql(other.light_dark.light) and this.light_dark.dark.eql(other.light_dark.dark), - .system => this.system == other.system, - }; - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn toRGB(this: *const @This(), allocator: Allocator) ?CssColor { - if (this.* == .light_dark) { - return CssColor{ .light_dark = .{ - .light = bun.create(allocator, CssColor, this.light_dark.light.toRGB(allocator) orelse return null), - .dark = bun.create(allocator, CssColor, this.light_dark.dark.toRGB(allocator) orelse return null), - } }; - } - return CssColor{ .rgba = RGBA.tryFromCssColor(this) orelse return null }; - } - - pub fn toP3(this: *const @This(), allocator: Allocator) ?CssColor { - return switch (this.*) { - .light_dark => |ld| blk: { - const light = ld.light.toP3(allocator) orelse break :blk null; - const dark = ld.dark.toP3(allocator) orelse break :blk null; - break :blk .{ - .light_dark = .{ - .light = bun.create(allocator, CssColor, light), - .dark = bun.create(allocator, CssColor, dark), - }, - }; - }, - else => return .{ .predefined = bun.create(allocator, PredefinedColor, .{ .display_p3 = P3.tryFromCssColor(this) orelse return null }) }, - }; - } - - pub fn toLAB(this: *const @This(), allocator: Allocator) ?CssColor { - return switch (this.*) { - .light_dark => |ld| blk: { - const light = ld.light.toLAB(allocator) orelse break :blk null; - const dark = ld.dark.toLAB(allocator) orelse break :blk null; - break :blk .{ - .light_dark = .{ - .light = bun.create(allocator, CssColor, light), - .dark = bun.create(allocator, CssColor, dark), - }, - }; - }, - else => .{ .lab = bun.create(allocator, LABColor, .{ .lab = LAB.tryFromCssColor(this) orelse return null }) }, - }; - } -}; - -pub fn parseColorFunction(location: css.SourceLocation, function: []const u8, input: *css.Parser) Result(CssColor) { - var parser = ComponentParser.new(true); - - const ColorFunctions = enum { lab, oklab, lch, oklch, color, hsl, hsla, hwb, rgb, rgba, @"color-mix", @"light-dark" }; - const Map = bun.ComptimeEnumMap(ColorFunctions); - - if (Map.getASCIIICaseInsensitive(function)) |val| { - return switch (val) { - .lab => parseLab(LAB, input, &parser, struct { - fn callback(l: f32, a: f32, b: f32, alpha: f32) LABColor { - return .{ .lab = .{ .l = l, .a = a, .b = b, .alpha = alpha } }; - } - }.callback), - .oklab => parseLab(OKLAB, input, &parser, struct { - fn callback(l: f32, a: f32, b: f32, alpha: f32) LABColor { - return .{ .oklab = .{ .l = l, .a = a, .b = b, .alpha = alpha } }; - } - }.callback), - .lch => parseLch(LCH, input, &parser, struct { - fn callback(l: f32, c: f32, h: f32, alpha: f32) LABColor { - return .{ .lch = .{ .l = l, .c = c, .h = h, .alpha = alpha } }; - } - }.callback), - .oklch => parseLch(OKLCH, input, &parser, struct { - fn callback(l: f32, c: f32, h: f32, alpha: f32) LABColor { - return .{ .oklch = .{ .l = l, .c = c, .h = h, .alpha = alpha } }; - } - }.callback), - .color => parsePredefined(input, &parser), - .hsl, .hsla => parseHslHwb(HSL, input, &parser, true, struct { - fn callback(allocator: Allocator, h: f32, s: f32, l: f32, a: f32) CssColor { - const hsl = HSL{ .h = h, .s = s, .l = l, .alpha = a }; - if (!std.math.isNan(h) and !std.math.isNan(s) and !std.math.isNan(l) and !std.math.isNan(a)) { - return CssColor{ .rgba = hsl.into(.RGBA) }; - } else { - return CssColor{ .float = bun.create(allocator, FloatColor, .{ .hsl = hsl }) }; - } - } - }.callback), - .hwb => parseHslHwb(HWB, input, &parser, false, struct { - fn callback(allocator: Allocator, h: f32, w: f32, b: f32, a: f32) CssColor { - const hwb = HWB{ .h = h, .w = w, .b = b, .alpha = a }; - if (!std.math.isNan(h) and !std.math.isNan(w) and !std.math.isNan(b) and !std.math.isNan(a)) { - return CssColor{ .rgba = hwb.into(.RGBA) }; - } else { - return CssColor{ .float = bun.create(allocator, FloatColor, .{ .hwb = hwb }) }; - } - } - }.callback), - .rgb, .rgba => parseRgb(input, &parser), - .@"color-mix" => input.parseNestedBlock(CssColor, {}, struct { - pub fn parseFn(_: void, i: *css.Parser) Result(CssColor) { - return parseColorMix(i); - } - }.parseFn), - .@"light-dark" => input.parseNestedBlock(CssColor, {}, struct { - fn callback(_: void, i: *css.Parser) Result(CssColor) { - const light = switch (switch (CssColor.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }) { - .light_dark => |ld| ld.takeLightFreeDark(i.allocator()), - else => |v| bun.create(i.allocator(), CssColor, v), - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const dark = switch (switch (CssColor.parse(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }) { - .light_dark => |ld| ld.takeDarkFreeLight(i.allocator()), - else => |v| bun.create(i.allocator(), CssColor, v), - }; - return .{ .result = .{ - .light_dark = .{ - .light = light, - .dark = dark, - }, - } }; - } - }.callback), - }; - } - return .{ .err = location.newUnexpectedTokenError(.{ .ident = function }) }; -} - -pub fn parseRGBComponents(input: *css.Parser, parser: *ComponentParser) Result(struct { f32, f32, f32, bool }) { - const red = switch (parser.parseNumberOrPercentage(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }; - - const is_legacy_syntax = parser.from == null and - !std.math.isNan(red.unitValue()) and - input.tryParse(css.Parser.expectComma, .{}).isOk(); - - const r, const g, const b = if (is_legacy_syntax) switch (red) { - .number => |v| brk: { - const r = bun.clamp(@round(v.value), 0.0, 255.0); - const g = switch (parser.parseNumber(input)) { - .err => |e| return .{ .err = e }, - .result => |vv| bun.clamp(@round(vv), 0.0, 255.0), - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const b = switch (parser.parseNumber(input)) { - .err => |e| return .{ .err = e }, - .result => |vv| bun.clamp(@round(vv), 0.0, 255.0), - }; - break :brk .{ r, g, b }; - }, - .percentage => |v| brk: { - const r = bun.clamp(@round(v.unit_value * 255.0), 0.0, 255.0); - const g = switch (parser.parsePercentage(input)) { - .err => |e| return .{ .err = e }, - .result => |vv| bun.clamp(@round(vv * 255.0), 0.0, 255.0), - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const b = switch (parser.parsePercentage(input)) { - .err => |e| return .{ .err = e }, - .result => |vv| bun.clamp(@round(vv * 255.0), 0.0, 255.0), - }; - break :brk .{ r, g, b }; - }, - } else blk: { - const getComponent = struct { - fn get(value: NumberOrPercentage) f32 { - return switch (value) { - .number => |v| if (std.math.isNan(v.value)) v.value else bun.clamp(@round(v.value), 0.0, 255.0) / 255.0, - .percentage => |v| bun.clamp(v.unit_value, 0.0, 1.0), - }; - } - }.get; - - const r = getComponent(red); - const g = getComponent(switch (parser.parseNumberOrPercentage(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }); - const b = getComponent(switch (parser.parseNumberOrPercentage(input)) { - .err => |e| return .{ .err = e }, - .result => |v| v, - }); - break :blk .{ r, g, b }; - }; - - if (is_legacy_syntax and (std.math.isNan(g) or std.math.isNan(b))) { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - return .{ .result = .{ r, g, b, is_legacy_syntax } }; -} - -pub fn parseHSLHWBComponents(comptime T: type, input: *css.Parser, parser: *ComponentParser, allows_legacy: bool) Result(struct { f32, f32, f32, bool }) { - _ = T; // autofix - const h = switch (parseAngleOrNumber(input, parser)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const is_legacy_syntax = allows_legacy and - parser.from == null and - !std.math.isNan(h) and - input.tryParse(css.Parser.expectComma, .{}).isOk(); - const a = switch (parser.parsePercentage(input)) { - .result => |v| bun.clamp(v, 0.0, 1.0), - .err => |e| return .{ .err = e }, - }; - if (is_legacy_syntax) { - if (input.expectColon().asErr()) |e| return .{ .err = e }; - } - const b = switch (parser.parsePercentage(input)) { - .result => |v| bun.clamp(v, 0.0, 1.0), - .err => |e| return .{ .err = e }, - }; - if (is_legacy_syntax and (std.math.isNan(a) or std.math.isNan(b))) { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - return .{ .result = .{ h, a, b, is_legacy_syntax } }; -} - -pub fn mapGamut(comptime T: type, color: T) T { - const conversion_target = comptime ConvertTo.fromType(T); - const JND: f32 = 0.02; - const EPSILON: f32 = 0.00001; - - // https://www.w3.org/TR/css-color-4/#binsearch - var current: OKLCH = color.into(.OKLCH); - - // If lightness is >= 100%, return pure white. - if (@abs(current.l - 1.0) < EPSILON or current.l > 1.0) { - const oklch = OKLCH{ - .l = 1.0, - .c = 0.0, - .h = 0.0, - .alpha = current.alpha, - }; - return oklch.into(conversion_target); - } - - // If lightness <= 0%, return pure black. - if (current.l < EPSILON) { - const oklch = OKLCH{ - .l = 0.0, - .c = 0.0, - .h = 0.0, - .alpha = current.alpha, - }; - return oklch.into(conversion_target); - } - - var min: f32 = 0.0; - var max = current.c; - - while ((max - min) > EPSILON) { - const chroma = (min + max) / 2.0; - current.c = chroma; - - const converted = current.into(conversion_target); - if (converted.inGamut()) { - min = chroma; - continue; - } - - const clipped = converted.clip(); - const delta_e = deltaEok(T, clipped, current); - if (delta_e < JND) { - return clipped; - } - - max = chroma; - } - - return current.into(conversion_target); -} - -pub fn deltaEok(comptime T: type, _a: T, _b: OKLCH) f32 { - // https://www.w3.org/TR/css-color-4/#color-difference-OK - const a: OKLAB = _a.into(.OKLAB); - const b: OKLAB = _b.into(.OKLAB); - - const delta_l = a.l - b.l; - const delta_a = a.a - b.a; - const delta_b = a.b - b.b; - - return @sqrt( - bun.powf(delta_l, 2) + - bun.powf(delta_a, 2) + - bun.powf(delta_b, 2), - ); -} - -pub fn parseLab( - comptime T: type, - input: *css.Parser, - parser: *ComponentParser, - comptime func: *const fn (f32, f32, f32, f32) LABColor, -) Result(CssColor) { - const Closure = struct { - parser: *ComponentParser, - - pub fn parsefn(this: *@This(), i: *css.Parser) Result(CssColor) { - return this.parser.parseRelative(i, T, CssColor, @This().innerfn, .{}); - } - - pub fn innerfn(i: *css.Parser, p: *ComponentParser) Result(CssColor) { - // f32::max() does not propagate NaN, so use clamp for now until f32::maximum() is stable. - const l = bun.clamp( - switch (p.parsePercentage(i)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, - 0.0, - std.math.floatMax(f32), - ); - const a = switch (p.parseNumber(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const b = switch (p.parseNumber(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const alpha = switch (parseAlpha(i, p)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const lab = func(l, a, b, alpha); - const heap_lab = bun.create(i.allocator(), LABColor, lab); - heap_lab.* = lab; - return .{ .result = CssColor{ .lab = heap_lab } }; - } - }; - var closure = Closure{ - .parser = parser, - }; - // https://www.w3.org/TR/css-color-4/#funcdef-lab - return input.parseNestedBlock( - CssColor, - &closure, - Closure.parsefn, - ); -} - -pub fn parseLch( - comptime T: type, - input: *css.Parser, - parser: *ComponentParser, - comptime func: *const fn ( - f32, - f32, - f32, - f32, - ) LABColor, -) Result(CssColor) { - const Closure = struct { - parser: *ComponentParser, - - pub fn parseNestedBlockFn(this: *@This(), i: *css.Parser) Result(CssColor) { - return this.parser.parseRelative(i, T, CssColor, @This().parseRelativeFn, .{this}); - } - - pub fn parseRelativeFn(i: *css.Parser, p: *ComponentParser, this: *@This()) Result(CssColor) { - _ = this; // autofix - if (p.from) |*from| { - // Relative angles should be normalized. - // https://www.w3.org/TR/css-color-5/#relative-LCH - // from.components[2] %= 360.0; - from.components[2] = @mod(from.components[2], 360.0); - if (from.components[2] < 0.0) { - from.components[2] += 360.0; - } - } - - const l = bun.clamp( - switch (p.parsePercentage(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - 0.0, - std.math.floatMax(f32), - ); - const c = bun.clamp( - switch (p.parseNumber(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - 0.0, - std.math.floatMax(f32), - ); - const h = switch (parseAngleOrNumber(i, p)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const alpha = switch (parseAlpha(i, p)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const lab = func(l, c, h, alpha); - return .{ - .result = .{ - .lab = bun.create(i.allocator(), LABColor, lab), - }, - }; - } - }; - - var closure = Closure{ - .parser = parser, - }; - - return input.parseNestedBlock(CssColor, &closure, Closure.parseNestedBlockFn); -} - -/// Parses the hsl() and hwb() functions. -/// The results of this function are stored as floating point if there are any `none` components. -/// https://drafts.csswg.org/css-color-4/#the-hsl-notation -pub fn parseHslHwb( - comptime T: type, - input: *css.Parser, - parser: *ComponentParser, - allows_legacy: bool, - comptime func: *const fn ( - Allocator, - f32, - f32, - f32, - f32, - ) CssColor, -) Result(CssColor) { - const Closure = struct { - parser: *ComponentParser, - allows_legacy: bool, - - pub fn parseNestedBlockFn(this: *@This(), i: *css.Parser) Result(CssColor) { - return this.parser.parseRelative(i, T, CssColor, @This().parseRelativeFn, .{this}); - } - - pub fn parseRelativeFn(i: *css.Parser, p: *ComponentParser, this: *@This()) Result(CssColor) { - const h, const a, const b, const is_legacy = switch (parseHslHwbComponents(T, i, p, this.allows_legacy)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const alpha = switch (if (is_legacy) parseLegacyAlpha(i, p) else parseAlpha(i, p)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = func(i.allocator(), h, a, b, alpha) }; - } - }; - - var closure = Closure{ - .parser = parser, - .allows_legacy = allows_legacy, - }; - - return input.parseNestedBlock(CssColor, &closure, Closure.parseNestedBlockFn); -} - -pub fn parseHslHwbComponents( - comptime T: type, - input: *css.Parser, - parser: *ComponentParser, - allows_legacy: bool, -) Result(struct { f32, f32, f32, bool }) { - _ = T; // autofix - const h = switch (parseAngleOrNumber(input, parser)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const is_legacy_syntax = allows_legacy and - parser.from == null and - !std.math.isNan(h) and - input.tryParse(css.Parser.expectComma, .{}).isOk(); - - const a = bun.clamp( - switch (parser.parsePercentage(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - 0.0, - 1.0, - ); - - if (is_legacy_syntax) { - if (input.expectComma().asErr()) |e| return .{ .err = e }; - } - - const b = bun.clamp( - switch (parser.parsePercentage(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - 0.0, - 1.0, - ); - - if (is_legacy_syntax and (std.math.isNan(a) or std.math.isNan(b))) { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - - return .{ .result = .{ h, a, b, is_legacy_syntax } }; -} - -pub fn parseAngleOrNumber(input: *css.Parser, parser: *const ComponentParser) Result(f32) { - const result = switch (parser.parseAngleOrNumber(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = switch (result) { - .number => |v| v.value, - .angle => |v| v.degrees, - }, - }; -} - -fn parseRgb(input: *css.Parser, parser: *ComponentParser) Result(CssColor) { - // https://drafts.csswg.org/css-color-4/#rgb-functions - - const Closure = struct { - p: *ComponentParser, - - pub fn parseNestedBlockFn(this: *@This(), i: *css.Parser) Result(CssColor) { - return this.p.parseRelative(i, SRGB, CssColor, @This().parseRelativeFn, .{this}); - } - - pub fn parseRelativeFn(i: *css.Parser, p: *ComponentParser, this: *@This()) Result(CssColor) { - _ = this; // autofix - const r, const g, const b, const is_legacy = switch (parseRGBComponents(i, p)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const alpha = switch (if (is_legacy) parseLegacyAlpha(i, p) else parseAlpha(i, p)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (!std.math.isNan(r) and - !std.math.isNan(g) and - !std.math.isNan(b) and - !std.math.isNan(alpha)) - { - if (is_legacy) return .{ - .result = .{ - .rgba = RGBA.new( - bun.intFromFloat(u8, r), - bun.intFromFloat(u8, g), - bun.intFromFloat(u8, b), - alpha, - ), - }, - }; - - return .{ - .result = .{ - .rgba = RGBA.fromFloats( - r, - g, - b, - alpha, - ), - }, - }; - } else { - return .{ - .result = .{ - .float = bun.create( - i.allocator(), - FloatColor, - .{ - .rgb = .{ - .r = r, - .g = g, - .b = b, - .alpha = alpha, - }, - }, - ), - }, - }; - } - } - }; - var closure = Closure{ - .p = parser, - }; - return input.parseNestedBlock(CssColor, &closure, Closure.parseNestedBlockFn); -} - -// pub fn parseRgbComponents(input: *css.Parser, parser: *ComponentParser) Result(struct { -// f32, -// f32, -// f32, -// bool, -// }) { -// const red = switch (parser.parseNumberOrPercentage(input)) { -// .result => |vv| vv, -// .err => |e| return .{ .err = e }, -// }; -// const is_legacy_syntax = parser.from == null and !std.math.isNan(red.unitValue()) and input.tryParse(css.Parser.expectComma, .{}).isOk(); - -// const r, const g, const b = if (is_legacy_syntax) switch (red) { -// .number => |num| brk: { -// const r = bun.clamp(@round(num.value), 0.0, 255.0); -// const g = bun.clamp( -// @round( -// switch (parser.parseNumber(input)) { -// .result => |vv| vv, -// .err => |e| return .{ .err = e }, -// }, -// ), -// 0.0, -// 255.0, -// ); -// if (input.expectComma().asErr()) |e| return .{ .err = e }; -// const b = bun.clamp( -// @round( -// switch (parser.parseNumber(input)) { -// .result => |vv| vv, -// .err => |e| return .{ .err = e }, -// }, -// ), -// 0.0, -// 255.0, -// ); -// break :brk .{ r, g, b }; -// }, -// .percentage => |per| brk: { -// const unit_value = per.unit_value; -// const r = bun.clamp(@round(unit_value * 255.0), 0.0, 255.0); -// const g = bun.clamp( -// @round( -// switch (parser.parsePercentage(input)) { -// .result => |vv| vv, -// .err => |e| return .{ .err = e }, -// } * 255.0, -// ), -// 0.0, -// 255.0, -// ); -// if (input.expectComma().asErr()) |e| return .{ .err = e }; -// const b = bun.clamp( -// @round( -// switch (parser.parsePercentage(input)) { -// .result => |vv| vv, -// .err => |e| return .{ .err = e }, -// } * 255.0, -// ), -// 0.0, -// 255.0, -// ); -// break :brk .{ r, g, b }; -// }, -// } else brk: { -// const get = struct { -// pub fn component(value: NumberOrPercentage) f32 { -// return switch (value) { -// .number => |num| { -// const v = num.value; -// if (std.math.isNan(v)) return v; -// return bun.clamp(@round(v), 0.0, 255.0) / 255.0; -// }, -// .percentage => |per| bun.clamp(per.unit_value, 0.0, 1.0), -// }; -// } -// }; -// const r = get.component(red); -// const g = get.component( -// switch (parser.parseNumberOrPercentage(input)) { -// .result => |vv| vv, -// .err => |e| return .{ .err = e }, -// }, -// ); -// const b = get.component( -// switch (parser.parseNumberOrPercentage(input)) { -// .result => |vv| vv, -// .err => |e| return .{ .err = e }, -// }, -// ); -// break :brk .{ r, g, b }; -// }; - -// if (is_legacy_syntax and (std.math.isNan(g) or std.math.isNan(b))) { -// return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; -// } - -// return .{ .result = .{ r, g, b, is_legacy_syntax } }; -// } - -fn parseLegacyAlpha(input: *css.Parser, parser: *const ComponentParser) Result(f32) { - if (!input.isExhausted()) { - if (input.expectComma().asErr()) |e| return .{ .err = e }; - return .{ .result = bun.clamp( - switch (parseNumberOrPercentage(input, parser)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }, - 0.0, - 1.0, - ) }; - } - return .{ .result = 1.0 }; -} - -fn parseAlpha(input: *css.Parser, parser: *const ComponentParser) Result(f32) { - const res = if (input.tryParse(css.Parser.expectDelim, .{'/'}).isOk()) - bun.clamp(switch (parseNumberOrPercentage(input, parser)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, 0.0, 1.0) - else - 1.0; - - return .{ .result = res }; -} - -pub fn parseNumberOrPercentage(input: *css.Parser, parser: *const ComponentParser) Result(f32) { - const result = switch (parser.parseNumberOrPercentage(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return switch (result) { - .number => |value| .{ .result = value.value }, - .percentage => |value| .{ .result = value.unit_value }, - }; -} - -// Copied from an older version of cssparser. -/// A color with red, green, blue, and alpha components, in a byte each. -pub const RGBA = struct { - /// The red component. - red: u8, - /// The green component. - green: u8, - /// The blue component. - blue: u8, - /// The alpha component. - alpha: u8, - - /// Convert the color into another color format. - pub const into = ColorIntoMixin(@This(), .RGBA).into; - - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - - pub fn new(red: u8, green: u8, blue: u8, alpha: f32) RGBA { - return RGBA{ - .red = red, - .green = green, - .blue = blue, - .alpha = clamp_unit_f32(alpha), - }; - } - - /// Constructs a new RGBA value from float components. It expects the red, - /// green, blue and alpha channels in that order, and all values will be - /// clamped to the 0.0 ... 1.0 range. - pub fn fromFloats(red: f32, green: f32, blue: f32, alpha: f32) RGBA { - return RGBA.new( - clamp_unit_f32(red), - clamp_unit_f32(green), - clamp_unit_f32(blue), - alpha, - ); - } - - pub fn transparent() RGBA { - return RGBA.new(0, 0, 0, 0.0); - } - - /// Returns the red channel in a floating point number form, from 0 to 1. - pub fn redF32(this: *const RGBA) f32 { - return @as(f32, @floatFromInt(this.red)) / 255.0; - } - - /// Returns the green channel in a floating point number form, from 0 to 1. - pub fn greenF32(this: *const RGBA) f32 { - return @as(f32, @floatFromInt(this.green)) / 255.0; - } - - /// Returns the blue channel in a floating point number form, from 0 to 1. - pub fn blueF32(this: *const RGBA) f32 { - return @as(f32, @floatFromInt(this.blue)) / 255.0; - } - - /// Returns the alpha channel in a floating point number form, from 0 to 1. - pub fn alphaF32(this: *const RGBA) f32 { - return @as(f32, @floatFromInt(this.alpha)) / 255.0; - } - - pub fn intoSRGB(rgb: *const RGBA) SRGB { - return SRGB{ - .r = rgb.redF32(), - .g = rgb.greenF32(), - .b = rgb.blueF32(), - .alpha = rgb.alphaF32(), - }; - } -}; - -fn clamp_unit_f32(val: f32) u8 { - // Whilst scaling by 256 and flooring would provide - // an equal distribution of integers to percentage inputs, - // this is not what Gecko does so we instead multiply by 255 - // and round (adding 0.5 and flooring is equivalent to rounding) - // - // Chrome does something similar for the alpha value, but not - // the rgb values. - // - // See https://bugzilla.mozilla.org/show_bug.cgi?id=1340484 - // - // Clamping to 256 and rounding after would let 1.0 map to 256, and - // `256.0_f32 as u8` is undefined behavior: - // - // https://github.com/rust-lang/rust/issues/10184 - return clamp_floor_256_f32(val * 255.0); -} - -fn clamp_floor_256_f32(val: f32) u8 { - return bun.intFromFloat(u8, @min(255.0, @max(0.0, @round(val)))); - // val.round().max(0.).min(255.) as u8 -} - -/// A color in a LAB color space, including the `lab()`, `lch()`, `oklab()`, and `oklch()` functions. -pub const LABColor = union(enum) { - /// A `lab()` color. - lab: LAB, - /// An `lch()` color. - lch: LCH, - /// An `oklab()` color. - oklab: OKLAB, - /// An `oklch()` color. - oklch: OKLCH, - - pub fn newLAB(l: f32, a: f32, b: f32, alpha: f32) LABColor { - return LABColor{ - .lab = LAB.new(l, a, b, alpha), - }; - } - - pub fn newOKLAB(l: f32, a: f32, b: f32, alpha: f32) LABColor { - return LABColor{ - .lab = OKLAB.new(l, a, b, alpha), - }; - } - - pub fn newLCH(l: f32, a: f32, b: f32, alpha: f32) LABColor { - return LABColor{ - .lab = LCH.new(l, a, b, alpha), - }; - } - - pub fn newOKLCH(l: f32, a: f32, b: f32, alpha: f32) LABColor { - return LABColor{ - .lab = LCH.new(l, a, b, alpha), - }; - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// A color in a predefined color space, e.g. `display-p3`. -pub const PredefinedColor = union(enum) { - /// A color in the `srgb` color space. - srgb: SRGB, - /// A color in the `srgb-linear` color space. - srgb_linear: SRGBLinear, - /// A color in the `display-p3` color space. - display_p3: P3, - /// A color in the `a98-rgb` color space. - a98: A98, - /// A color in the `prophoto-rgb` color space. - prophoto: ProPhoto, - /// A color in the `rec2020` color space. - rec2020: Rec2020, - /// A color in the `xyz-d50` color space. - xyz_d50: XYZd50, - /// A color in the `xyz-d65` color space. - xyz_d65: XYZd65, - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// A floating point representation of color types that -/// are usually stored as RGBA. These are used when there -/// are any `none` components, which are represented as NaN. -pub const FloatColor = union(enum) { - /// An RGB color. - rgb: SRGB, - /// An HSL color. - hsl: HSL, - /// An HWB color. - hwb: HWB, - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// A CSS [system color](https://drafts.csswg.org/css-color/#css-system-colors) keyword. -/// *NOTE* these are intentionally in flat case -pub const SystemColor = enum { - /// Background of accented user interface controls. - accentcolor, - /// Text of accented user interface controls. - accentcolortext, - /// Text in active links. For light backgrounds, traditionally red. - activetext, - /// The base border color for push buttons. - buttonborder, - /// The face background color for push buttons. - buttonface, - /// Text on push buttons. - buttontext, - /// Background of application content or documents. - canvas, - /// Text in application content or documents. - canvastext, - /// Background of input fields. - field, - /// Text in input fields. - fieldtext, - /// Disabled text. (Often, but not necessarily, gray.) - graytext, - /// Background of selected text, for example from ::selection. - highlight, - /// Text of selected text. - highlighttext, - /// Text in non-active, non-visited links. For light backgrounds, traditionally blue. - linktext, - /// Background of text that has been specially marked (such as by the HTML mark element). - mark, - /// Text that has been specially marked (such as by the HTML mark element). - marktext, - /// Background of selected items, for example a selected checkbox. - selecteditem, - /// Text of selected items. - selecteditemtext, - /// Text in visited links. For light backgrounds, traditionally purple. - visitedtext, - - // Deprecated colors: https://drafts.csswg.org/css-color/#deprecated-system-colors - - /// Active window border. Same as ButtonBorder. - activeborder, - /// Active window caption. Same as Canvas. - activecaption, - /// Background color of multiple document interface. Same as Canvas. - appworkspace, - /// Desktop background. Same as Canvas. - background, - /// The color of the border facing the light source for 3-D elements that appear 3-D due to one layer of surrounding border. Same as ButtonFace. - buttonhighlight, - /// The color of the border away from the light source for 3-D elements that appear 3-D due to one layer of surrounding border. Same as ButtonFace. - buttonshadow, - /// Text in caption, size box, and scrollbar arrow box. Same as CanvasText. - captiontext, - /// Inactive window border. Same as ButtonBorder. - inactiveborder, - /// Inactive window caption. Same as Canvas. - inactivecaption, - /// Color of text in an inactive caption. Same as GrayText. - inactivecaptiontext, - /// Background color for tooltip controls. Same as Canvas. - infobackground, - /// Text color for tooltip controls. Same as CanvasText. - infotext, - /// Menu background. Same as Canvas. - menu, - /// Text in menus. Same as CanvasText. - menutext, - /// Scroll bar gray area. Same as Canvas. - scrollbar, - /// The color of the darker (generally outer) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border. Same as ButtonBorder. - threeddarkshadow, - /// The face background color for 3-D elements that appear 3-D due to two concentric layers of surrounding border. Same as ButtonFace. - threedface, - /// The color of the lighter (generally outer) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border. Same as ButtonBorder. - threedhighlight, - /// The color of the darker (generally inner) of the two borders facing the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border. Same as ButtonBorder. - threedlightshadow, - /// The color of the lighter (generally inner) of the two borders away from the light source for 3-D elements that appear 3-D due to two concentric layers of surrounding border. Same as ButtonBorder. - threedshadow, - /// Window background. Same as Canvas. - window, - /// Window frame. Same as ButtonBorder. - windowframe, - /// Text in windows. Same as CanvasText. - windowtext, - - pub fn isCompatible(this: SystemColor, browsers: css.targets.Browsers) bool { - return switch (this) { - .accentcolor, .accentcolortext => css.Feature.isCompatible(.accent_system_color, browsers), - else => true, - }; - } - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -/// A color in the [CIE Lab](https://www.w3.org/TR/css-color-4/#cie-lab) color space. -pub const LAB = struct { - /// The lightness component. - l: f32, - /// The a component. - a: f32, - /// The b component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const types = colorspace_impl.types; - pub const channels = colorspace_impl.channels; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = UnboundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - pub const adjustPowerlessComponents = AdjustPowerlessLAB(@This()).adjustPowerlessComponents; - const interpolate_impl = DeriveInterpolate(@This(), "l", "a", "b"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - const recangular_impl = RecangularPremultiply(@This(), "l", "a", "b"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .LAB).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .LAB); - - pub const ChannelTypeMap = .{ - .l = ChannelType{ .percentage = true }, - .a = ChannelType{ .number = true }, - .b = ChannelType{ .number = true }, - }; - - pub fn adjustHue(_: *@This(), _: *@This(), _: HueInterpolationMethod) void {} -}; - -/// A color in the [`sRGB`](https://www.w3.org/TR/css-color-4/#predefined-sRGB) color space. -pub const SRGB = struct { - /// The red component. - r: f32, - /// The green component. - g: f32, - /// The blue component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = BoundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - const interpolate_impl = DeriveInterpolate(@This(), "r", "g", "b"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - const recangular_impl = RecangularPremultiply(@This(), "r", "g", "b"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .SRGB).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .SRGB); - - pub const ChannelTypeMap = .{ - .r = ChannelType{ .percentage = true }, - .g = ChannelType{ .percentage = true }, - .b = ChannelType{ .percentage = true }, - }; - - pub fn adjustPowerlessComponents(_: *@This()) void {} - pub fn adjustHue(_: *@This(), _: *@This(), _: HueInterpolationMethod) void {} - - pub fn intoRGBA(_rgb: *const SRGB) RGBA { - const rgb = _rgb.resolve(); - return RGBA.fromFloats( - rgb.r, - rgb.g, - rgb.b, - rgb.alpha, - ); - } -}; - -/// A color in the [`hsl`](https://www.w3.org/TR/css-color-4/#the-hsl-notation) color space. -pub const HSL = struct { - /// The hue component. - h: f32, - /// The saturation component. - s: f32, - /// The lightness component. - l: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = HslHwbColorGamut(@This(), "s", "l"); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - const polar_impl = PolarPremultiply(@This(), "s", "l"); - pub const premultiply = polar_impl.premultiply; - pub const unpremultiply = polar_impl.unpremultiply; - const interpolate_impl = DeriveInterpolate(@This(), "h", "s", "l"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .HSL).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .HSL); - - pub const ChannelTypeMap = .{ - .h = ChannelType{ .angle = true }, - .s = ChannelType{ .percentage = true }, - .l = ChannelType{ .percentage = true }, - }; - - pub fn adjustPowerlessComponents(this: *HSL) void { - // If the saturation of an HSL color is 0%, then the hue component is powerless. - // If the lightness of an HSL color is 0% or 100%, both the saturation and hue components are powerless. - if (@abs(this.s) < std.math.floatEps(f32)) { - this.h = std.math.nan(f32); - } - - if (@abs(this.l) < std.math.floatEps(f32) or @abs(this.l - 1.0) < std.math.floatEps(f32)) { - this.h = std.math.nan(f32); - this.s = std.math.nan(f32); - } - } - - pub fn adjustHue(this: *HSL, other: *HSL, method: HueInterpolationMethod) void { - _ = method.interpolate(&this.h, &other.h); - } -}; - -/// A color in the [`hwb`](https://www.w3.org/TR/css-color-4/#the-hwb-notation) color space. -pub const HWB = struct { - /// The hue component. - h: f32, - /// The whiteness component. - w: f32, - /// The blackness component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = HslHwbColorGamut(@This(), "w", "b"); - pub const inGamut = gamut_impl.inGamut; - pub const clip = gamut_impl.clip; - - const polar_impl = PolarPremultiply(@This(), "w", "b"); - pub const premultiply = polar_impl.premultiply; - pub const unpremultiply = polar_impl.unpremultiply; - const interpolate_impl = DeriveInterpolate(@This(), "h", "w", "b"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .HWB).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .HWB); - - pub const ChannelTypeMap = .{ - .h = ChannelType{ .angle = true }, - .w = ChannelType{ .percentage = true }, - .b = ChannelType{ .percentage = true }, - }; - - pub fn adjustPowerlessComponents(this: *HWB) void { - // If white+black is equal to 100% (after normalization), it defines an achromatic color, - // i.e. some shade of gray, without any hint of the chosen hue. In this case, the hue component is powerless. - if (@abs(this.w + this.b - 1.0) < std.math.floatEps(f32)) { - this.h = std.math.nan(f32); - } - } - - pub fn adjustHue(this: *HWB, other: *HWB, method: HueInterpolationMethod) void { - _ = method.interpolate(&this.h, &other.h); - } -}; - -/// A color in the [`sRGB-linear`](https://www.w3.org/TR/css-color-4/#predefined-sRGB-linear) color space. -pub const SRGBLinear = struct { - /// The red component. - r: f32, - /// The green component. - g: f32, - /// The blue component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = BoundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - const interpolate_impl = DeriveInterpolate(@This(), "r", "g", "b"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - const recangular_impl = RecangularPremultiply(@This(), "r", "g", "b"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .SRGBLinear).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .SRGBLinear); - - pub const ChannelTypeMap = .{ - .r = ChannelType{ .angle = true }, - .g = ChannelType{ .percentage = true }, - .b = ChannelType{ .percentage = true }, - }; - - pub fn adjustPowerlessComponents(_: *@This()) void {} - pub fn adjustHue(_: *@This(), _: *@This(), _: HueInterpolationMethod) void {} -}; - -/// A color in the [`display-p3`](https://www.w3.org/TR/css-color-4/#predefined-display-p3) color space. -pub const P3 = struct { - /// The red component. - r: f32, - /// The green component. - g: f32, - /// The blue component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = BoundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .P3).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .P3); - - pub const ChannelTypeMap = .{ - .r = ChannelType{ .percentage = true }, - .g = ChannelType{ .percentage = true }, - .b = ChannelType{ .percentage = true }, - }; -}; - -/// A color in the [`a98-rgb`](https://www.w3.org/TR/css-color-4/#predefined-a98-rgb) color space. -pub const A98 = struct { - /// The red component. - r: f32, - /// The green component. - g: f32, - /// The blue component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = BoundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .A98).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .A98); - - pub const ChannelTypeMap = .{ - .r = ChannelType{ .percentage = true }, - .g = ChannelType{ .percentage = true }, - .b = ChannelType{ .percentage = true }, - }; -}; - -/// A color in the [`prophoto-rgb`](https://www.w3.org/TR/css-color-4/#predefined-prophoto-rgb) color space. -pub const ProPhoto = struct { - /// The red component. - r: f32, - /// The green component. - g: f32, - /// The blue component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = BoundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .ProPhoto).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .ProPhoto); - - pub const ChannelTypeMap = .{ - .r = ChannelType{ .percentage = true }, - .g = ChannelType{ .percentage = true }, - .b = ChannelType{ .percentage = true }, - }; -}; - -/// A color in the [`rec2020`](https://www.w3.org/TR/css-color-4/#predefined-rec2020) color space. -pub const Rec2020 = struct { - /// The red component. - r: f32, - /// The green component. - g: f32, - /// The blue component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = BoundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .Rec2020).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .Rec2020); - - pub const ChannelTypeMap = .{ - .r = ChannelType{ .percentage = true }, - .g = ChannelType{ .percentage = true }, - .b = ChannelType{ .percentage = true }, - }; -}; - -/// A color in the [`xyz-d50`](https://www.w3.org/TR/css-color-4/#predefined-xyz) color space. -pub const XYZd50 = struct { - /// The x component. - x: f32, - /// The y component. - y: f32, - /// The z component. - z: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = UnboundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - const interpolate_impl = DeriveInterpolate(@This(), "x", "y", "z"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - const recangular_impl = RecangularPremultiply(@This(), "x", "y", "z"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .XYZd50).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .XYZd50); - - pub const ChannelTypeMap = .{ - .x = ChannelType{ .percentage = true }, - .y = ChannelType{ .percentage = true }, - .z = ChannelType{ .percentage = true }, - }; -}; - -/// A color in the [`xyz-d65`](https://www.w3.org/TR/css-color-4/#predefined-xyz) color space. -pub const XYZd65 = struct { - /// The x component. - x: f32, - /// The y component. - y: f32, - /// The z component. - z: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = UnboundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - const interpolate_impl = DeriveInterpolate(@This(), "x", "y", "z"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - const recangular_impl = RecangularPremultiply(@This(), "x", "y", "z"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .XYZd65).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .XYZd65); - - pub const ChannelTypeMap = .{ - .x = ChannelType{ .percentage = true }, - .y = ChannelType{ .percentage = true }, - .z = ChannelType{ .percentage = true }, - }; - - pub fn adjustPowerlessComponents(_: *@This()) void {} - pub fn adjustHue(_: *@This(), _: *@This(), _: HueInterpolationMethod) void {} -}; - -/// A color in the [CIE LCH](https://www.w3.org/TR/css-color-4/#cie-lab) color space. -pub const LCH = struct { - /// The lightness component. - l: f32, - /// The chroma component. - c: f32, - /// The hue component. - h: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = UnboundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - const powerless_lch_impl = AdjustPowerlessLCH(@This()); - pub const adjustPowerlessComponents = powerless_lch_impl.adjustPowerlessComponents; - pub const adjustHue = powerless_lch_impl.adjustHue; - const interpolate_impl = DeriveInterpolate(@This(), "l", "c", "h"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - const recangular_impl = RecangularPremultiply(@This(), "l", "c", "h"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .LCH).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .LCH); - - pub const ChannelTypeMap = .{ - .l = ChannelType{ .percentage = true }, - .c = ChannelType{ .number = true }, - .h = ChannelType{ .angle = true }, - }; -}; - -/// A color in the [OKLab](https://www.w3.org/TR/css-color-4/#ok-lab) color space. -pub const OKLAB = struct { - /// The lightness component. - l: f32, - /// The a component. - a: f32, - /// The b component. - b: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = UnboundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - pub const adjustPowerlessComponents = AdjustPowerlessLAB(@This()).adjustPowerlessComponents; - const interpolate_impl = DeriveInterpolate(@This(), "l", "a", "b"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - const recangular_impl = RecangularPremultiply(@This(), "l", "a", "b"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .OKLAB).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .OKLAB); - - pub const ChannelTypeMap = .{ - .l = ChannelType{ .percentage = true }, - .a = ChannelType{ .number = true }, - .b = ChannelType{ .number = true }, - }; - - pub fn adjustHue(_: *@This(), _: *@This(), _: HueInterpolationMethod) void {} -}; - -/// A color in the [OKLCH](https://www.w3.org/TR/css-color-4/#ok-lab) color space. -pub const OKLCH = struct { - /// The lightness component. - l: f32, - /// The chroma component. - c: f32, - /// The hue component. - h: f32, - /// The alpha component. - alpha: f32, - - const colorspace_impl = DefineColorspace(@This(), ChannelTypeMap); - pub const components = colorspace_impl.components; - pub const channels = colorspace_impl.channels; - pub const types = colorspace_impl.types; - pub const resolveMissing = colorspace_impl.resolveMissing; - pub const resolve = colorspace_impl.resolve; - const conversions_impl = ColorspaceConversions(@This()); - pub const fromLABColor = conversions_impl.fromLABColor; - pub const fromPredefinedColor = conversions_impl.fromPredefinedColor; - pub const fromFloatColor = conversions_impl.fromFloatColor; - pub const tryFromCssColor = conversions_impl.tryFromCssColor; - pub const hash = conversions_impl.hash; - const gamut_impl = UnboundedColorGamut(@This()); - pub const clip = gamut_impl.clip; - pub const inGamut = gamut_impl.inGamut; - - const powerless_lch_impl = AdjustPowerlessLCH(@This()); - pub const adjustPowerlessComponents = powerless_lch_impl.adjustPowerlessComponents; - pub const adjustHue = powerless_lch_impl.adjustHue; - const interpolate_impl = DeriveInterpolate(@This(), "l", "c", "h"); - pub const fillMissingComponents = interpolate_impl.fillMissingComponents; - pub const interpolate = interpolate_impl.interpolate; - - const recangular_impl = RecangularPremultiply(@This(), "l", "c", "h"); - pub const premultiply = recangular_impl.premultiply; - pub const unpremultiply = recangular_impl.unpremultiply; - - /// Convert this color into another color format. - pub const into = ColorIntoMixin(@This(), .OKLCH).into; - pub const intoCssColor = ImplementIntoCssColor(@This(), .OKLCH); - - pub const ChannelTypeMap = .{ - .l = ChannelType{ .percentage = true }, - .c = ChannelType{ .number = true }, - .h = ChannelType{ .angle = true }, - }; -}; - -pub const ComponentParser = struct { - allow_none: bool, - from: ?RelativeComponentParser, - - pub fn new(allow_none: bool) ComponentParser { - return ComponentParser{ - .allow_none = allow_none, - .from = null, - }; - } - - /// `func` must be a function like: - /// fn (*css.Parser, *ComponentParser, ...args) - pub fn parseRelative( - this: *ComponentParser, - input: *css.Parser, - comptime T: type, - comptime C: type, - comptime func: anytype, - args_: anytype, - ) Result(C) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"from"}).isOk()) { - const from = switch (CssColor.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return this.parseFrom(from, input, T, C, func, args_); - } - - const args = bun.meta.ConcatArgs2(func, input, this, args_); - return @call(.auto, func, args); - } - - pub fn parseFrom( - this: *ComponentParser, - from: CssColor, - input: *css.Parser, - comptime T: type, - comptime C: type, - comptime func: anytype, - args_: anytype, - ) Result(C) { - if (from == .light_dark) { - const state = input.state(); - const light = switch (this.parseFrom(from.light_dark.light.*, input, T, C, func, args_)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - input.reset(&state); - const dark = switch (this.parseFrom(from.light_dark.dark.*, input, T, C, func, args_)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = C.lightDarkOwned(input.allocator(), light, dark) }; - } - - const new_from = if (T.tryFromCssColor(&from)) |v| v.resolve() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - - this.from = RelativeComponentParser.new(&new_from); - - const args = bun.meta.ConcatArgs2(func, input, this, args_); - return @call(.auto, func, args); - } - - pub fn parseNumberOrPercentage(this: *const ComponentParser, input: *css.Parser) Result(NumberOrPercentage) { - if (this.from) |*from| { - if (input.tryParse(RelativeComponentParser.parseNumberOrPercentage, .{from}).asValue()) |res| { - return .{ .result = res }; - } - } - - if (input.tryParse(CSSNumberFns.parse, .{}).asValue()) |value| { - return .{ .result = NumberOrPercentage{ .number = .{ .value = value } } }; - } else if (input.tryParse(Percentage.parse, .{}).asValue()) |value| { - return .{ - .result = NumberOrPercentage{ - .percentage = .{ .unit_value = value.v }, - }, - }; - } else if (this.allow_none) { - if (input.expectIdentMatching("none").asErr()) |e| return .{ .err = e }; - return .{ .result = NumberOrPercentage{ - .number = .{ - .value = std.math.nan(f32), - }, - } }; - } else { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - } - - pub fn parseAngleOrNumber(this: *const ComponentParser, input: *css.Parser) Result(css.color.AngleOrNumber) { - if (this.from) |*from| { - if (input.tryParse(RelativeComponentParser.parseAngleOrNumber, .{from}).asValue()) |res| { - return .{ .result = res }; - } - } - - if (input.tryParse(Angle.parse, .{}).asValue()) |angle| { - return .{ - .result = .{ - .angle = .{ - .degrees = angle.toDegrees(), - }, - }, - }; - } else if (input.tryParse(CSSNumberFns.parse, .{}).asValue()) |value| { - return .{ - .result = .{ - .number = .{ - .value = value, - }, - }, - }; - } else if (this.allow_none) { - if (input.expectIdentMatching("none").asErr()) |e| return .{ .err = e }; - return .{ - .result = .{ - .number = .{ - .value = std.math.nan(f32), - }, - }, - }; - } else { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - } - - pub fn parsePercentage(this: *const ComponentParser, input: *css.Parser) Result(f32) { - if (this.from) |*from| { - if (input.tryParse(RelativeComponentParser.parsePercentage, .{from}).asValue()) |res| { - return .{ .result = res }; - } - } - - if (input.tryParse(Percentage.parse, .{}).asValue()) |val| { - return .{ .result = val.v }; - } else if (this.allow_none) { - if (input.expectIdentMatching("none").asErr()) |e| return .{ .err = e }; - return .{ .result = std.math.nan(f32) }; - } else { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - } - - pub fn parseNumber(this: *const ComponentParser, input: *css.Parser) Result(f32) { - if (this.from) |*from| { - if (input.tryParse(RelativeComponentParser.parseNumber, .{from}).asValue()) |res| { - return .{ .result = res }; - } - } - - if (input.tryParse(CSSNumberFns.parse, .{}).asValue()) |val| { - return .{ .result = val }; - } else if (this.allow_none) { - if (input.expectIdentMatching("none").asErr()) |e| return .{ .err = e }; - return .{ .result = std.math.nan(f32) }; - } else { - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - } -}; - -/// Either a number or a percentage. -pub const NumberOrPercentage = union(enum) { - /// ``. - number: struct { - /// The numeric value parsed, as a float. - value: f32, - }, - /// `` - percentage: struct { - /// The value as a float, divided by 100 so that the nominal range is - /// 0.0 to 1.0. - unit_value: f32, - }, - - /// Return the value as a percentage. - pub fn unitValue(this: *const NumberOrPercentage) f32 { - return switch (this.*) { - .number => |v| v.value, - .percentage => |v| v.unit_value, - }; - } - - /// Return the value as a number with a percentage adjusted to the - /// `percentage_basis`. - pub fn value(this: *const NumberOrPercentage, percentage_basis: f32) f32 { - return switch (this.*) { - .number => |v| v.value, - .percentage => |v| v.unit_value * percentage_basis, - }; - } -}; - -const RelativeComponentParser = struct { - names: struct { []const u8, []const u8, []const u8 }, - components: struct { f32, f32, f32, f32 }, - types: struct { ChannelType, ChannelType, ChannelType }, - - pub fn new(color: anytype) RelativeComponentParser { - return RelativeComponentParser{ - .names = color.channels(), - .components = color.components(), - .types = color.types(), - }; - } - - pub fn parseAngleOrNumber(input: *css.Parser, this: *const RelativeComponentParser) Result(css.color.AngleOrNumber) { - if (input.tryParse( - RelativeComponentParser.parseIdent, - .{ - this, - ChannelType{ .angle = true, .number = true }, - }, - ).asValue()) |value| { - return .{ .result = .{ - .number = .{ - .value = value, - }, - } }; - } - - if (input.tryParse( - RelativeComponentParser.parseCalc, - .{ - this, - ChannelType{ .angle = true, .number = true }, - }, - ).asValue()) |value| { - return .{ .result = .{ - .number = .{ - .value = value, - }, - } }; - } - - const Closure = struct { - angle: Angle, - parser: *const RelativeComponentParser, - pub fn tryParseFn(i: *css.Parser, t: *@This()) Result(Angle) { - if (Calc(Angle).parseWith(i, t, @This().calcParseIdentFn).asValue()) |val| { - if (val == .value) { - return .{ .result = val.value.* }; - } - } - return .{ .err = i.newCustomError(css.ParserError.invalid_value) }; - } - - pub fn calcParseIdentFn(t: *@This(), ident: []const u8) ?Calc(Angle) { - const value = t.parser.getIdent(ident, ChannelType{ .angle = true, .number = true }) orelse return null; - t.angle = .{ .deg = value }; - return Calc(Angle){ - .value = &t.angle, - }; - } - }; - var closure = Closure{ - .angle = undefined, - .parser = this, - }; - if (input.tryParse(Closure.tryParseFn, .{&closure}).asValue()) |value| { - return .{ .result = .{ - .angle = .{ - .degrees = value.toDegrees(), - }, - } }; - } - - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn parseNumberOrPercentage(input: *css.Parser, this: *const RelativeComponentParser) Result(NumberOrPercentage) { - if (input.tryParse(RelativeComponentParser.parseIdent, .{ this, ChannelType{ .percentage = true, .number = true } }).asValue()) |value| { - return .{ .result = NumberOrPercentage{ .percentage = .{ .unit_value = value } } }; - } - - if (input.tryParse(RelativeComponentParser.parseCalc, .{ this, ChannelType{ .percentage = true, .number = true } }).asValue()) |value| { - return .{ .result = NumberOrPercentage{ - .percentage = .{ - .unit_value = value, - }, - } }; - } - - { - const Closure = struct { - parser: *const RelativeComponentParser, - percentage: Percentage = .{ .v = 0 }, - - pub fn parsefn(i: *css.Parser, self: *@This()) Result(Percentage) { - if (Calc(Percentage).parseWith(i, self, @This().calcparseident).asValue()) |calc_value| { - if (calc_value == .value) return .{ .result = calc_value.value.* }; - } - return .{ .err = i.newCustomError(css.ParserError.invalid_value) }; - } - - pub fn calcparseident(self: *@This(), ident: []const u8) ?Calc(Percentage) { - const v = self.parser.getIdent(ident, ChannelType{ .percentage = true, .number = true }) orelse return null; - self.percentage = .{ .v = v }; - // value variant is a *Percentage - // but we immediately dereference it and discard the pointer - // so using a field on this closure struct instead of making a gratuitous allocation - return .{ - .value = &self.percentage, - }; - } - }; - var closure = Closure{ - .parser = this, - }; - if (input.tryParse(Closure.parsefn, .{ - &closure, - }).asValue()) |value| { - return .{ .result = NumberOrPercentage{ - .percentage = .{ - .unit_value = value.v, - }, - } }; - } - } - - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn parsePercentage( - input: *css.Parser, - this: *const RelativeComponentParser, - ) Result(f32) { - if (input.tryParse(RelativeComponentParser.parseIdent, .{ this, ChannelType{ .percentage = true } }).asValue()) |value| { - return .{ .result = value }; - } - - const Closure = struct { self: *const RelativeComponentParser, temp: Percentage = .{ .v = 0 } }; - var _closure = Closure{ .self = this }; - if (input.tryParse(struct { - pub fn parseFn(i: *css.Parser, closure: *Closure) Result(Percentage) { - const calc_value = switch (Calc(Percentage).parseWith(i, closure, parseIdentFn)) { - .result => |v| v, - .err => return .{ .err = i.newCustomError(css.ParserError.invalid_value) }, - }; - if (calc_value == .value) return .{ .result = calc_value.value.* }; - return .{ .err = i.newCustomError(css.ParserError.invalid_value) }; - } - - pub fn parseIdentFn(closure: *Closure, ident: []const u8) ?Calc(Percentage) { - const v = closure.self.getIdent(ident, ChannelType{ .percentage = true }) orelse return null; - closure.temp = .{ .v = v }; - return Calc(Percentage){ .value = &closure.temp }; - } - }.parseFn, .{&_closure}).asValue()) |value| { - return .{ .result = value.v }; - } - - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn parseNumber( - input: *css.Parser, - this: *const RelativeComponentParser, - ) Result(f32) { - if (input.tryParse( - RelativeComponentParser.parseIdent, - .{ this, ChannelType{ .number = true } }, - ).asValue()) |value| { - return .{ .result = value }; - } - - if (input.tryParse( - RelativeComponentParser.parseCalc, - .{ this, ChannelType{ .number = true } }, - ).asValue()) |value| { - return .{ .result = value }; - } - - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn parseIdent( - input: *css.Parser, - this: *const RelativeComponentParser, - allowed_types: ChannelType, - ) Result(f32) { - const v = this.getIdent( - switch (input.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, - allowed_types, - ) orelse return .{ .err = input.newErrorForNextToken() }; - return .{ .result = v }; - } - - pub fn parseCalc( - input: *css.Parser, - this: *const RelativeComponentParser, - allowed_types: ChannelType, - ) Result(f32) { - const Closure = struct { - p: *const RelativeComponentParser, - allowed_types: ChannelType, - - pub fn parseIdentFn(self: *@This(), ident: []const u8) ?Calc(f32) { - const v = self.p.getIdent(ident, self.allowed_types) orelse return null; - return .{ .number = v }; - } - }; - var closure = Closure{ - .p = this, - .allowed_types = allowed_types, - }; - if (Calc(f32).parseWith(input, &closure, Closure.parseIdentFn).asValue()) |calc_val| { - // PERF: I don't like this redundant allocation - if (calc_val == .value) return .{ .result = calc_val.value.* }; - if (calc_val == .number) return .{ .result = calc_val.number }; - } - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - - pub fn getIdent( - this: *const RelativeComponentParser, - ident: []const u8, - allowed_types: ChannelType, - ) ?f32 { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, this.names[0]) and - bits.intersects(ChannelType, allowed_types, this.types[0])) - { - return this.components[0]; - } - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, this.names[1]) and - bits.intersects(ChannelType, allowed_types, this.types[1])) - { - return this.components[1]; - } - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, this.names[2]) and - bits.intersects(ChannelType, allowed_types, this.types[2])) - { - return this.components[2]; - } - - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "alpha") and allowed_types.percentage) { - return this.components[3]; - } - - return null; - } -}; - -/// A channel type for a color space. -/// TODO(zack): why tf is this bitflags? -pub const ChannelType = packed struct(u8) { - /// Channel represents a percentage. - percentage: bool = false, - /// Channel represents an angle. - angle: bool = false, - /// Channel represents a number. - number: bool = false, - __unused: u5 = 0, -}; - -pub fn parsePredefined(input: *css.Parser, parser: *ComponentParser) Result(CssColor) { - const Closure = struct { p: *ComponentParser }; - var closure = Closure{ - .p = parser, - }; - const res = switch (input.parseNestedBlock(CssColor, &closure, struct { - // https://www.w3.org/TR/css-color-4/#color-function - pub fn parseFn(this: *Closure, i: *css.Parser) Result(CssColor) { - const from: ?CssColor = if (i.tryParse(css.Parser.expectIdentMatching, .{"from"}).isOk()) - switch (CssColor.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } - else - null; - - const colorspace = switch (i.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - - if (from) |f| { - if (f == .light_dark) { - const state = i.state(); - const light = switch (parsePredefinedRelative(i, this.p, colorspace, f.light_dark.light)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - i.reset(&state); - const dark = switch (parsePredefinedRelative(i, this.p, colorspace, f.light_dark.dark)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = CssColor{ - .light_dark = .{ - .light = bun.create( - i.allocator(), - CssColor, - light, - ), - .dark = bun.create( - i.allocator(), - CssColor, - dark, - ), - }, - } }; - } - } - - return parsePredefinedRelative(i, this.p, colorspace, if (from) |*f| f else null); - } - }.parseFn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = res }; -} - -pub fn parsePredefinedRelative( - input: *css.Parser, - parser: *ComponentParser, - colorspace: []const u8, - _from: ?*const CssColor, -) Result(CssColor) { - const location = input.currentSourceLocation(); - if (_from) |from| { - parser.from = set_from: { - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("srgb", colorspace)) { - break :set_from RelativeComponentParser.new( - if (SRGB.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("srgb-linear", colorspace)) { - break :set_from RelativeComponentParser.new( - if (SRGBLinear.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("display-p3", colorspace)) { - break :set_from RelativeComponentParser.new( - if (P3.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("a98-rgb", colorspace)) { - break :set_from RelativeComponentParser.new( - if (A98.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("prophoto-rgb", colorspace)) { - break :set_from RelativeComponentParser.new( - if (ProPhoto.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("rec2020", colorspace)) { - break :set_from RelativeComponentParser.new( - if (Rec2020.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("xyz-d50", colorspace)) { - break :set_from RelativeComponentParser.new( - if (XYZd50.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("xyz", colorspace) or - bun.strings.eqlCaseInsensitiveASCIIICheckLength("xyz-d65", colorspace)) - { - break :set_from RelativeComponentParser.new( - if (XYZd65.tryFromCssColor(from)) |v| v.resolveMissing() else return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - ); - } else { - return .{ .err = location.newUnexpectedTokenError(.{ .ident = colorspace }) }; - } - }; - } - - // Out of gamut values should not be clamped, i.e. values < 0 or > 1 should be preserved. - // The browser will gamut-map the color for the target device that it is rendered on. - const a = switch (input.tryParse(parseNumberOrPercentage, .{parser})) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const b = switch (input.tryParse(parseNumberOrPercentage, .{parser})) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const c = switch (input.tryParse(parseNumberOrPercentage, .{parser})) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const alpha = switch (parseAlpha(input, parser)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const predefined: PredefinedColor = predefined: { - const Variants = enum { - srgb, - @"srgb-linear", - @"display-p3", - @"a99-rgb", - @"prophoto-rgb", - rec2020, - @"xyz-d50", - @"xyz-d65", - xyz, - }; - const Map = bun.ComptimeEnumMap(Variants); - if (Map.getAnyCase(colorspace)) |ret| { - switch (ret) { - .srgb => break :predefined .{ .srgb = SRGB{ - .r = a, - .g = b, - .b = c, - .alpha = alpha, - } }, - .@"srgb-linear" => break :predefined .{ .srgb_linear = SRGBLinear{ - .r = a, - .g = b, - .b = c, - .alpha = alpha, - } }, - .@"display-p3" => break :predefined .{ .display_p3 = P3{ - .r = a, - .g = b, - .b = c, - .alpha = alpha, - } }, - .@"a99-rgb" => break :predefined .{ .a98 = A98{ - .r = a, - .g = b, - .b = c, - .alpha = alpha, - } }, - .@"prophoto-rgb" => break :predefined .{ .prophoto = ProPhoto{ - .r = a, - .g = b, - .b = c, - .alpha = alpha, - } }, - .rec2020 => break :predefined .{ .rec2020 = Rec2020{ - .r = a, - .g = b, - .b = c, - .alpha = alpha, - } }, - .@"xyz-d50" => break :predefined .{ .xyz_d50 = XYZd50{ - .x = a, - .y = b, - .z = c, - .alpha = alpha, - } }, - .@"xyz-d65", .xyz => break :predefined .{ .xyz_d65 = XYZd65{ - .x = a, - .y = b, - .z = c, - .alpha = alpha, - } }, - } - } else return .{ .err = location.newUnexpectedTokenError(.{ .ident = colorspace }) }; - }; - - return .{ .result = .{ - .predefined = bun.create( - input.allocator(), - PredefinedColor, - predefined, - ), - } }; -} - -/// A color type that is used as a fallback when compiling colors for older browsers. -pub const ColorFallbackKind = packed struct(u8) { - rgb: bool = false, - p3: bool = false, - lab: bool = false, - oklab: bool = false, - __unused: u4 = 0, - - pub const P3 = ColorFallbackKind{ .p3 = true }; - pub const RGB = ColorFallbackKind{ .rgb = true }; - pub const LAB = ColorFallbackKind{ .lab = true }; - pub const OKLAB = ColorFallbackKind{ .oklab = true }; - - pub fn lowest(this: @This()) ColorFallbackKind { - return bun.bits.@"and"( - ColorFallbackKind, - this, - fromBitsTruncate(bun.wrappingNegation(@as(u8, @bitCast(this)))), - ); - } - - pub fn highest(this: @This()) ColorFallbackKind { - // This finds the highest set bit. - if (this.isEmpty()) return ColorFallbackKind{}; - - const zeroes: u3 = @intCast(@as(u4, 7) - bun.bits.leadingZeros(ColorFallbackKind, this)); - return fromBitsTruncate(@as(u8, 1) << zeroes); - } - - pub fn difference(left: @This(), right: @This()) ColorFallbackKind { - return @bitCast(@as(u8, @bitCast(left)) - @as(u8, @bitCast(right))); - } - - pub fn andBelow(this: @This()) ColorFallbackKind { - if (this.isEmpty()) return .{}; - - return bun.bits.@"or"(ColorFallbackKind, this, fromBitsTruncate(@as(u8, @bitCast(this)) - 1)); - } - - pub fn supportsCondition(this: @This()) css.SupportsCondition { - const s = switch (this.asBits()) { - ColorFallbackKind.P3.asBits() => "color(display-p3 0 0 0)", - ColorFallbackKind.LAB.asBits() => "lab(0% 0 0)", - else => bun.unreachablePanic("Expected P3 or LAB. This is a bug in Bun.", .{}), - }; - - return css.SupportsCondition{ - .declaration = .{ - .property_id = .color, - .value = s, - }, - }; - } - - pub fn isEmpty(cfk: ColorFallbackKind) bool { - return @as(u8, @bitCast(cfk)) == 0; - } - - pub inline fn fromBitsTruncate(b: u8) ColorFallbackKind { - var cfk: ColorFallbackKind = @bitCast(b); - cfk.__unused = 0; - return cfk; - } - - pub fn asBits(this: @This()) u8 { - return @bitCast(this); - } -}; - -/// A [color space](https://www.w3.org/TR/css-color-4/#interpolation-space) keyword -/// used in interpolation functions such as `color-mix()`. -pub const ColorSpaceName = enum { - srgb, - @"srgb-linear", - lab, - oklab, - xyz, - @"xyz-d50", - @"xyz-d65", - hsl, - hwb, - lch, - oklch, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -pub fn parseColorMix(input: *css.Parser) Result(CssColor) { - if (input.expectIdentMatching("in").asErr()) |e| return .{ .err = e }; - const method = switch (ColorSpaceName.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const hue_method_: Result(HueInterpolationMethod) = if (switch (method) { - .hsl, .hwb, .lch, .oklch => true, - else => false, - }) brk: { - const hue_method = input.tryParse(HueInterpolationMethod.parse, .{}); - if (hue_method.isOk()) { - if (input.expectIdentMatching("hue").asErr()) |e| return .{ .err = e }; - } - break :brk hue_method; - } else .{ .result = HueInterpolationMethod.shorter }; - - const hue_method = hue_method_.unwrapOr(HueInterpolationMethod.shorter); - if (input.expectComma().asErr()) |e| return .{ .err = e }; - - const first_percent_ = input.tryParse(css.Parser.expectPercentage, .{}); - const first_color = switch (CssColor.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const first_percent = switch (first_percent_) { - .result => |v| v, - .err => switch (input.tryParse(css.Parser.expectPercentage, .{})) { - .result => |vv| vv, - .err => null, - }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - - const second_percent_ = input.tryParse(css.Parser.expectPercentage, .{}); - const second_color = switch (CssColor.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const second_percent = switch (second_percent_) { - .result => |vv| vv, - .err => switch (input.tryParse(css.Parser.expectPercentage, .{})) { - .result => |vv| vv, - .err => null, - }, - }; - - // https://drafts.csswg.org/css-color-5/#color-mix-percent-norm - const p1: f32, const p2: f32 = if (first_percent == null and second_percent == null) .{ @as(f32, 0.5), @as(f32, 0.5) } else brk: { - const p2 = second_percent orelse (@as(f32, 1.0) - first_percent.?); - const p1 = first_percent orelse (@as(f32, 1.0) - second_percent.?); - break :brk .{ p1, p2 }; - }; - - if ((p1 + p2) == 0.0) return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - - const result = switch (method) { - .srgb => first_color.interpolate(input.allocator(), SRGB, p1, &second_color, p2, hue_method), - .@"srgb-linear" => first_color.interpolate(input.allocator(), SRGBLinear, p1, &second_color, p2, hue_method), - .hsl => first_color.interpolate(input.allocator(), HSL, p1, &second_color, p2, hue_method), - .hwb => first_color.interpolate(input.allocator(), HWB, p1, &second_color, p2, hue_method), - .lab => first_color.interpolate(input.allocator(), LAB, p1, &second_color, p2, hue_method), - .lch => first_color.interpolate(input.allocator(), LCH, p1, &second_color, p2, hue_method), - .oklab => first_color.interpolate(input.allocator(), OKLAB, p1, &second_color, p2, hue_method), - .oklch => first_color.interpolate(input.allocator(), OKLCH, p1, &second_color, p2, hue_method), - .xyz, .@"xyz-d65" => first_color.interpolate(input.allocator(), XYZd65, p1, &second_color, p2, hue_method), - .@"xyz-d50" => first_color.interpolate(input.allocator(), XYZd65, p1, &second_color, p2, hue_method), - } orelse return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - - return .{ .result = result }; -} - -/// A hue [interpolation method](https://www.w3.org/TR/css-color-4/#typedef-hue-interpolation-method) -/// used in interpolation functions such as `color-mix()`. -pub const HueInterpolationMethod = enum { - /// Angles are adjusted so that θ₂ - θ₁ ∈ [-180, 180]. - shorter, - /// Angles are adjusted so that θ₂ - θ₁ ∈ {0, [180, 360)}. - longer, - /// Angles are adjusted so that θ₂ - θ₁ ∈ [0, 360). - increasing, - /// Angles are adjusted so that θ₂ - θ₁ ∈ (-360, 0]. - decreasing, - /// No fixup is performed. Angles are interpolated in the same way as every other component. - specified, - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn interpolate( - this: *const HueInterpolationMethod, - a: *f32, - b: *f32, - ) void { - // https://drafts.csswg.org/css-color/#hue-interpolation - if (this.* == .specified) { - // a.* = ((a.* % 360.0) + 360.0) % 360.0; - // b.* = ((b.* % 360.0) + 360.0) % 360.0; - a.* = @mod((@mod(a.*, 360.0) + 360.0), 360.0); - b.* = @mod((@mod(b.*, 360.0) + 360.0), 360.0); - } - - switch (this.*) { - .shorter => { - // https://www.w3.org/TR/css-color-4/#hue-shorter - const delta = b.* - a.*; - if (delta > 180.0) { - a.* += 360.0; - } else if (delta < -180.0) { - b.* += 360.0; - } - }, - .longer => { - // https://www.w3.org/TR/css-color-4/#hue-longer - const delta = b.* - a.*; - if (0.0 < delta and delta < 180.0) { - a.* += 360.0; - } else if (-180.0 < delta and delta < 0.0) { - b.* += 360.0; - } - }, - .increasing => { - // https://www.w3.org/TR/css-color-4/#hue-decreasing - if (b.* < a.*) { - b.* += 360.0; - } - }, - .decreasing => { - // https://www.w3.org/TR/css-color-4/#hue-decreasing - if (a.* < b.*) { - a.* += 360.0; - } - }, - .specified => {}, - } - } -}; - -fn rectangularToPolar(l: f32, a: f32, b: f32) struct { f32, f32, f32 } { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L375 - - var h = std.math.atan2(b, a) * 180.0 / std.math.pi; - if (h < 0.0) { - h += 360.0; - } - - // const c = @sqrt(std.math.powi(f32, a, 2) + std.math.powi(f32, b, 2)); - // PERF: Zig does not have Rust's f32::powi - const c = @sqrt(bun.powf(a, 2) + bun.powf(b, 2)); - - // h = h % 360.0; - h = @mod(h, 360.0); - return .{ l, c, h }; -} - -pub fn ColorspaceConversions(comptime T: type) type { - return struct { - const convert_type: ConvertTo = .fromType(T); - - pub fn fromLABColor(color: *const LABColor) T { - return switch (color.*) { - inline else => |*v| v.into(convert_type), - }; - } - - pub fn fromPredefinedColor(color: *const PredefinedColor) T { - return switch (color.*) { - inline else => |*v| v.into(convert_type), - }; - } - - pub fn fromFloatColor(color: *const FloatColor) T { - return switch (color.*) { - inline else => |*v| v.into(convert_type), - }; - } - - pub fn tryFromCssColor(color: *const CssColor) ?T { - return switch (color.*) { - .rgba => |*rgba| rgba.into(convert_type), - .lab => |lab| fromLABColor(lab), - .predefined => |predefined| fromPredefinedColor(predefined), - .float => |float| fromFloatColor(float), - .current_color => null, - .light_dark => null, - .system => null, - }; - } - - pub fn hash(this: *const T, hasher: *std.hash.Wyhash) void { - return css.implementHash(T, this, hasher); - } - }; -} - -pub fn DefineColorspace(comptime T: type, comptime ChannelTypeMap: anytype) type { - const fields: []const std.builtin.Type.StructField = @typeInfo(T).@"struct".fields; - const a = fields[0].name; - const b = fields[1].name; - const c = fields[2].name; - const alpha = "alpha"; - if (!@hasField(T, "alpha")) { - @compileError("A Colorspace must define an alpha field"); - } - - if (!@hasField(@TypeOf(ChannelTypeMap), a)) { - @compileError("A Colorspace must define a field for each channel, missing: " ++ a); - } - if (!@hasField(@TypeOf(ChannelTypeMap), b)) { - @compileError("A Colorspace must define a field for each channel, missing: " ++ b); - } - if (!@hasField(@TypeOf(ChannelTypeMap), c)) { - @compileError("A Colorspace must define a field for each channel, missing: " ++ c); - } - - return struct { - pub fn components(this: *const T) struct { f32, f32, f32, f32 } { - return .{ - @field(this, a), - @field(this, b), - @field(this, c), - @field(this, alpha), - }; - } - - pub fn channels(_: *const T) struct { []const u8, []const u8, []const u8 } { - return .{ a, b, c }; - } - - pub fn types(_: *const T) struct { ChannelType, ChannelType, ChannelType } { - return .{ - @field(ChannelTypeMap, a), - @field(ChannelTypeMap, b), - @field(ChannelTypeMap, c), - }; - } - - pub fn resolveMissing(this: *const T) T { - var result: T = this.*; - @field(result, a) = if (std.math.isNan(@field(this, a))) 0.0 else @field(this, a); - @field(result, b) = if (std.math.isNan(@field(this, b))) 0.0 else @field(this, b); - @field(result, c) = if (std.math.isNan(@field(this, c))) 0.0 else @field(this, c); - @field(result, alpha) = if (std.math.isNan(@field(this, alpha))) 0.0 else @field(this, alpha); - return result; - } - - pub fn resolve(this: *const T) T { - var resolved = resolveMissing(this); - if (!resolved.inGamut()) { - resolved = mapGamut(T, resolved); - } - return resolved; - } - }; -} - -pub fn BoundedColorGamut(comptime T: type) type { - const fields: []const std.builtin.Type.StructField = std.meta.fields(T); - const a = fields[0].name; - const b = fields[1].name; - const c = fields[2].name; - return struct { - pub fn inGamut(this: *const T) bool { - return @field(this, a) >= 0.0 and - @field(this, a) <= 1.0 and - @field(this, b) >= 0.0 and - @field(this, b) <= 1.0 and - @field(this, c) >= 0.0 and - @field(this, c) <= 1.0; - } - - pub fn clip(this: *const T) T { - var result: T = this.*; - @field(result, a) = bun.clamp(@field(this, a), 0.0, 1.0); - @field(result, b) = bun.clamp(@field(this, b), 0.0, 1.0); - @field(result, c) = bun.clamp(@field(this, c), 0.0, 1.0); - result.alpha = bun.clamp(this.alpha, 0.0, 1.0); - return result; - } - }; -} - -pub fn DeriveInterpolate( - comptime T: type, - comptime a: []const u8, - comptime b: []const u8, - comptime c: []const u8, -) type { - if (!@hasField(T, a)) @compileError("Missing field: " ++ a); - if (!@hasField(T, b)) @compileError("Missing field: " ++ b); - if (!@hasField(T, c)) @compileError("Missing field: " ++ c); - - return struct { - pub fn fillMissingComponents(this: *T, other: *T) void { - if (std.math.isNan(@field(this, a))) { - @field(this, a) = @field(other, a); - } - - if (std.math.isNan(@field(this, b))) { - @field(this, b) = @field(other, b); - } - - if (std.math.isNan(@field(this, c))) { - @field(this, c) = @field(other, c); - } - - if (std.math.isNan(this.alpha)) { - this.alpha = other.alpha; - } - } - - pub fn interpolate(this: *const T, p1: f32, other: *const T, p2: f32) T { - var result: T = undefined; - @field(result, a) = @field(this, a) * p1 + @field(other, a) * p2; - @field(result, b) = @field(this, b) * p1 + @field(other, b) * p2; - @field(result, c) = @field(this, c) * p1 + @field(other, c) * p2; - result.alpha = this.alpha * p1 + other.alpha * p2; - return result; - } - }; -} - -// pub fn DerivePredefined(comptime T: type, comptime predefined_color_field: []const u8) type { -// return struct { -// pub fn -// }; -// } - -pub fn RecangularPremultiply( - comptime T: type, - comptime a: []const u8, - comptime b: []const u8, - comptime c: []const u8, -) type { - if (!@hasField(T, a)) @compileError("Missing field: " ++ a); - if (!@hasField(T, b)) @compileError("Missing field: " ++ b); - if (!@hasField(T, c)) @compileError("Missing field: " ++ c); - return struct { - pub fn premultiply(this: *T) void { - if (!std.math.isNan(this.alpha)) { - @field(this, a) *= this.alpha; - @field(this, b) *= this.alpha; - @field(this, c) *= this.alpha; - } - } - - pub fn unpremultiply(this: *T, alpha_multiplier: f32) void { - if (!std.math.isNan(this.alpha) and this.alpha != 0.0) { - // PERF: precalculate 1/alpha? - @field(this, a) /= this.alpha; - @field(this, b) /= this.alpha; - @field(this, c) /= this.alpha; - this.alpha *= alpha_multiplier; - } - } - }; -} - -pub fn PolarPremultiply( - comptime T: type, - comptime a: []const u8, - comptime b: []const u8, -) type { - if (!@hasField(T, a)) @compileError("Missing field: " ++ a); - if (!@hasField(T, b)) @compileError("Missing field: " ++ b); - return struct { - pub fn premultiply(this: *T) void { - if (!std.math.isNan(this.alpha)) { - @field(this, a) *= this.alpha; - @field(this, b) *= this.alpha; - } - } - - pub fn unpremultiply(this: *T, alpha_multiplier: f32) void { - // this.h %= 360.0; - this.h = @mod(this.h, 360.0); - if (!std.math.isNan(this.alpha)) { - // PERF: precalculate 1/alpha? - @field(this, a) /= this.alpha; - @field(this, b) /= this.alpha; - this.alpha *= alpha_multiplier; - } - } - }; -} - -pub fn AdjustPowerlessLAB(comptime T: type) type { - return struct { - pub fn adjustPowerlessComponents(this: *T) void { - // If the lightness of a LAB color is 0%, both the a and b components are powerless. - if (@abs(this.l) < std.math.floatEps(f32)) { - this.a = std.math.nan(f32); - this.b = std.math.nan(f32); - } - } - }; -} - -pub fn AdjustPowerlessLCH(comptime T: type) type { - return struct { - pub fn adjustPowerlessComponents(this: *T) void { - // If the chroma of an LCH color is 0%, the hue component is powerless. - // If the lightness of an LCH color is 0%, both the hue and chroma components are powerless. - if (@abs(this.c) < std.math.floatEps(f32)) { - this.h = std.math.nan(f32); - } - - if (@abs(this.l) < std.math.floatEps(f32)) { - this.c = std.math.nan(f32); - this.h = std.math.nan(f32); - } - } - - pub fn adjustHue(this: *T, other: *T, method: HueInterpolationMethod) void { - _ = method.interpolate(&this.h, &other.h); - } - }; -} - -pub fn shortColorName(v: u32) ?[]const u8 { - // These names are shorter than their hex codes - return switch (v) { - 0x000080 => "navy", - 0x008000 => "green", - 0x008080 => "teal", - 0x4b0082 => "indigo", - 0x800000 => "maroon", - 0x800080 => "purple", - 0x808000 => "olive", - 0x808080 => "gray", - 0xa0522d => "sienna", - 0xa52a2a => "brown", - 0xc0c0c0 => "silver", - 0xcd853f => "peru", - 0xd2b48c => "tan", - 0xda70d6 => "orchid", - 0xdda0dd => "plum", - 0xee82ee => "violet", - 0xf0e68c => "khaki", - 0xf0ffff => "azure", - 0xf5deb3 => "wheat", - 0xf5f5dc => "beige", - 0xfa8072 => "salmon", - 0xfaf0e6 => "linen", - 0xff0000 => "red", - 0xff6347 => "tomato", - 0xff7f50 => "coral", - 0xffa500 => "orange", - 0xffc0cb => "pink", - 0xffd700 => "gold", - 0xffe4c4 => "bisque", - 0xfffafa => "snow", - 0xfffff0 => "ivory", - else => return null, - }; -} - -// From esbuild: https://github.com/evanw/esbuild/blob/18e13bdfdca5cd3c7a2fae1a8bd739f8f891572c/internal/css_parser/css_decls_color.go#L218 -// 0xAABBCCDD => 0xABCD -pub fn compactHex(v: u32) u32 { - return ((v & 0x0FF00000) >> 12) | ((v & 0x00000FF0) >> 4); -} - -// 0xABCD => 0xAABBCCDD -pub fn expandHex(v: u32) u32 { - return ((v & 0xF000) << 16) | - ((v & 0xFF00) << 12) | - ((v & 0x0FF0) << 8) | - ((v & 0x00FF) << 4) | - (v & 0x000F); -} - -pub fn writeComponents( - name: []const u8, - a: f32, - b: f32, - c: f32, - alpha: f32, - dest: *Printer, -) PrintErr!void { - try dest.writeStr(name); - try dest.writeChar('('); - if (std.math.isNan(a)) { - try dest.writeStr("none"); - } else { - try (Percentage{ .v = a }).toCss(dest); - } - try dest.writeChar(' '); - try writeComponent(b, dest); - try dest.writeChar(' '); - try writeComponent(c, dest); - if (std.math.isNan(alpha) or @abs(alpha - 1.0) > std.math.floatEps(f32)) { - try dest.delim('/', true); - try writeComponent(alpha, dest); - } - return dest.writeChar(')'); -} - -pub fn writeComponent(c: f32, dest: *Printer) PrintErr!void { - if (std.math.isNan(c)) { - return dest.writeStr("none"); - } else { - return CSSNumberFns.toCss(&c, dest); - } -} - -pub fn writePredefined( - predefined: *const PredefinedColor, - dest: *Printer, -) PrintErr!void { - const name, const a, const b, const c, const alpha = switch (predefined.*) { - .srgb => |*rgb| .{ "srgb", rgb.r, rgb.g, rgb.b, rgb.alpha }, - .srgb_linear => |*rgb| .{ "srgb-linear", rgb.r, rgb.g, rgb.b, rgb.alpha }, - .display_p3 => |*rgb| .{ "display-p3", rgb.r, rgb.g, rgb.b, rgb.alpha }, - .a98 => |*rgb| .{ "a98-rgb", rgb.r, rgb.g, rgb.b, rgb.alpha }, - .prophoto => |*rgb| .{ "prophoto-rgb", rgb.r, rgb.g, rgb.b, rgb.alpha }, - .rec2020 => |*rgb| .{ "rec2020", rgb.r, rgb.g, rgb.b, rgb.alpha }, - .xyz_d50 => |*xyz| .{ "xyz-d50", xyz.x, xyz.y, xyz.z, xyz.alpha }, - // "xyz" has better compatibility (Safari 15) than "xyz-d65", and it is shorter. - .xyz_d65 => |*xyz| .{ "xyz", xyz.x, xyz.y, xyz.z, xyz.alpha }, - }; - - try dest.writeStr("color("); - try dest.writeStr(name); - try dest.writeChar(' '); - try writeComponent(a, dest); - try dest.writeChar(' '); - try writeComponent(b, dest); - try dest.writeChar(' '); - try writeComponent(c, dest); - - if (std.math.isNan(alpha) or @abs(alpha - 1.0) > std.math.floatEps(f32)) { - try dest.delim('/', true); - try writeComponent(alpha, dest); - } - - return dest.writeChar(')'); -} - -extern "c" fn powf(f32, f32) f32; - -pub fn gamSrgb(r: f32, g: f32, b: f32) struct { f32, f32, f32 } { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L31 - // convert an array of linear-light sRGB values in the range 0.0-1.0 - // to gamma corrected form - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // For negative values, linear portion extends on reflection - // of axis, then uses reflected pow below that - - const Helpers = struct { - pub fn gamSrgbComponent(c: f32) f32 { - const abs = @abs(c); - if (abs > 0.0031308) { - const sign: f32 = if (c < 0.0) @as(f32, -1.0) else @as(f32, 1.0); - // const x: f32 = bun.powf( abs, 1.0 / 2.4); - const x: f32 = powf(abs, 1.0 / 2.4); - const y: f32 = 1.055 * x; - const z: f32 = y - 0.055; - // return sign * (1.055 * bun.powf( abs, 1.0 / 2.4) - 0.055); - return sign * z; - } - - return 12.92 * c; - } - }; - - const rr = Helpers.gamSrgbComponent(r); - const gg = Helpers.gamSrgbComponent(g); - const bb = Helpers.gamSrgbComponent(b); - return .{ - rr, - gg, - bb, - }; -} - -pub fn linSrgb(r: f32, g: f32, b: f32) struct { f32, f32, f32 } { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L11 - // convert sRGB values where in-gamut values are in the range [0 - 1] - // to linear light (un-companded) form. - // https://en.wikipedia.org/wiki/SRGB - // Extended transfer function: - // for negative values, linear portion is extended on reflection of axis, - // then reflected power function is used. - - const H = struct { - pub fn linSrgbComponent(c: f32) f32 { - const abs = @abs(c); - if (abs < 0.04045) { - return c / 12.92; - } - - const sign: f32 = if (c < 0.0) -1.0 else 1.0; - return sign * bun.powf( - ((abs + 0.055) / 1.055), - 2.4, - ); - } - }; - - return .{ - H.linSrgbComponent(r), - H.linSrgbComponent(g), - H.linSrgbComponent(b), - }; -} - -/// PERF: SIMD? -pub fn multiplyMatrix(m: *const [9]f32, x: f32, y: f32, z: f32) struct { f32, f32, f32 } { - const a = m[0] * x + m[1] * y + m[2] * z; - const b = m[3] * x + m[4] * y + m[5] * z; - const c = m[6] * x + m[7] * y + m[8] * z; - return .{ a, b, c }; -} - -pub fn polarToRectangular(l: f32, c: f32, h: f32) struct { f32, f32, f32 } { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L385 - - const a = c * @cos(h * std.math.pi / 180.0); - const b = c * @sin(h * std.math.pi / 180.0); - return .{ l, a, b }; -} - -const D50: []const f32 = &.{ @floatCast(@as(f64, 0.3457) / @as(f64, 0.3585)), 1.00000, @floatCast((@as(f64, 1.0) - @as(f64, 0.3457) - @as(f64, 0.3585)) / @as(f64, 0.3585)) }; -// const D50: []const f32 = &.{ 0.9642956, 1.0, 0.82510453 }; - -const color_conversions = struct { - pub const convert_RGBA = struct {}; - - pub const convert_LAB = struct { - pub fn intoCssColor(c: *const LAB, allocator: Allocator) CssColor { - return CssColor{ .lab = bun.create( - allocator, - LABColor, - LABColor{ .lab = c.* }, - ) }; - } - - pub fn intoLCH(_lab: *const LAB) LCH { - const lab = _lab.resolveMissing(); - const l, const c, const h = rectangularToPolar(lab.l, lab.a, lab.b); - return LCH{ - .l = l, - .c = c, - .h = h, - .alpha = lab.alpha, - }; - } - - pub fn intoXYZd50(_lab: *const LAB) XYZd50 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L352 - const K: f32 = @floatCast(@as(f64, 24389.0) / @as(f64, 27.0)); // 29^3/3^3 - const E: f32 = @floatCast(@as(f64, 216.0) / @as(f64, 24389.0)); // 6^3/29^3 - - const lab = _lab.resolveMissing(); - const l = lab.l * 100.0; - const a = lab.a; - const b = lab.b; - - // compute f, starting with the luminance-related term - const f1: f32 = (l + 16.0) / 116.0; - const f0: f32 = a / 500.0 + f1; - const f2: f32 = f1 - b / 200.0; - - // compute xyz - const x = if (bun.powf(f0, 3) > E) - bun.powf(f0, 3) - else - (116.0 * f0 - 16.0) / K; - - const y = if (l > K * E) bun.powf((l + 16.0) / 116.0, 3) else l / K; - - const z = if (bun.powf(f2, 3) > E) - bun.powf(f2, 3) - else - (@as(f32, 116.0) * f2 - 16.0) / K; - - const final_x = x * D50[0]; - const final_y = y * D50[1]; - const final_z = z * D50[2]; - - // Compute XYZ by scaling xyz by reference white - return XYZd50{ - .x = final_x, - .y = final_y, - .z = final_z, - .alpha = lab.alpha, - }; - } - }; - - pub const convert_SRGB = struct { - pub fn intoCssColor(srgb: *const SRGB, _: Allocator) CssColor { - // TODO: should we serialize as color(srgb, ...)? - // would be more precise than 8-bit color. - return CssColor{ .rgba = srgb.into(.RGBA) }; - } - - pub fn intoSRGBLinear(rgb: *const SRGB) SRGBLinear { - const srgb = rgb.resolveMissing(); - const r, const g, const b = linSrgb(srgb.r, srgb.g, srgb.b); - return SRGBLinear{ - .r = r, - .g = g, - .b = b, - .alpha = srgb.alpha, - }; - } - - pub fn intoHSL(_rgb: *const SRGB) HSL { - // https://drafts.csswg.org/css-color/#rgb-to-hsl - const rgb = _rgb.resolve(); - const r = rgb.r; - const g = rgb.g; - const b = rgb.b; - const max = @max( - @max(r, g), - b, - ); - const min = @min(@min(r, g), b); - var h = std.math.nan(f32); - var s: f32 = 0.0; - const l = (min + max) / 2.0; - const d = max - min; - - if (d != 0.0) { - s = if (l == 0.0 or l == 1.0) - 0.0 - else - (max - l) / @min(l, 1.0 - l); - - if (max == r) { - h = (g - b) / d + (if (g < b) @as(f32, 6.0) else @as(f32, 0.0)); - } else if (max == g) { - h = (b - r) / d + 2.0; - } else if (max == b) { - h = (r - g) / d + 4.0; - } - - h = h * 60.0; - } - - return HSL{ - .h = h, - .s = s, - .l = l, - .alpha = rgb.alpha, - }; - } - - pub fn intoHWB(_rgb: *const SRGB) HWB { - const rgb = _rgb.resolve(); - const hsl = rgb.into(.HSL); - const r = rgb.r; - const g = rgb.g; - const _b = rgb.b; - const w = @min(@min(r, g), _b); - const b = 1.0 - @max(@max(r, g), _b); - return HWB{ - .h = hsl.h, - .w = w, - .b = b, - .alpha = rgb.alpha, - }; - } - }; - - pub const convert_HSL = struct { - pub fn intoCssColor(c: *const HSL, _: Allocator) CssColor { - // TODO: should we serialize as color(srgb, ...)? - // would be more precise than 8-bit color. - return CssColor{ .rgba = c.into(.RGBA) }; - } - - pub fn intoSRGB(hsl_: *const HSL) SRGB { - // https://drafts.csswg.org/css-color/#hsl-to-rgb - const hsl = hsl_.resolveMissing(); - const h = (hsl.h - 360.0 * @floor(hsl.h / 360.0)) / 360.0; - const r, const g, const b = css.color.hslToRgb(h, hsl.s, hsl.l); - return SRGB{ - .r = r, - .g = g, - .b = b, - .alpha = hsl.alpha, - }; - } - }; - - pub const convert_HWB = struct { - pub fn intoCssColor(c: *const HWB, _: Allocator) CssColor { - // TODO: should we serialize as color(srgb, ...)? - // would be more precise than 8-bit color. - return CssColor{ .rgba = c.into(.RGBA) }; - } - - pub fn intoSRGB(_hwb: *const HWB) SRGB { - // https://drafts.csswg.org/css-color/#hwb-to-rgb - const hwb = _hwb.resolveMissing(); - const h = hwb.h; - const w = hwb.w; - const b = hwb.b; - - if (w + b >= 1.0) { - const gray = w / (w + b); - return SRGB{ - .r = gray, - .g = gray, - .b = gray, - .alpha = hwb.alpha, - }; - } - - var rgba = (HSL{ .h = h, .s = 1.0, .l = 0.5, .alpha = hwb.alpha }).into(.SRGB); - const x = 1.0 - w - b; - rgba.r = rgba.r * x + w; - rgba.g = rgba.g * x + w; - rgba.b = rgba.b * x + w; - return rgba; - } - }; - - pub const convert_SRGBLinear = struct { - pub fn intoPredefinedColor(rgb: *const SRGBLinear) PredefinedColor { - return PredefinedColor{ .srgb_linear = rgb.* }; - } - - pub fn intoCssColor(rgb: *const SRGBLinear, allocator: Allocator) CssColor { - return CssColor{ - .predefined = bun.create( - allocator, - PredefinedColor, - rgb.into(.PredefinedColor), - ), - }; - } - - pub fn intoSRGB(_rgb: *const SRGBLinear) SRGB { - const rgb = _rgb.resolveMissing(); - const r, const g, const b = gamSrgb(rgb.r, rgb.g, rgb.b); - return SRGB{ - .r = r, - .g = g, - .b = b, - .alpha = rgb.alpha, - }; - } - - pub fn intoXYZd65(_rgb: *const SRGBLinear) XYZd65 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L50 - // convert an array of linear-light sRGB values to CIE XYZ - // using sRGB's own white, D65 (no chromatic adaptation) - const MATRIX: [9]f32 = .{ - 0.41239079926595934, - 0.357584339383878, - 0.1804807884018343, - 0.21263900587151027, - 0.715168678767756, - 0.07219231536073371, - 0.01933081871559182, - 0.11919477979462598, - 0.9505321522496607, - }; - - const rgb = _rgb.resolveMissing(); - const x, const y, const z = multiplyMatrix(&MATRIX, rgb.r, rgb.g, rgb.b); - return XYZd65{ - .x = x, - .y = y, - .z = z, - .alpha = rgb.alpha, - }; - } - }; - - pub const convert_P3 = struct { - pub fn intoPredefinedColor(rgb: *const P3) PredefinedColor { - return PredefinedColor{ .display_p3 = rgb.* }; - } - - pub fn intoCssColor(rgb: *const P3, allocator: Allocator) CssColor { - return CssColor{ - .predefined = bun.create( - allocator, - PredefinedColor, - rgb.into(.PredefinedColor), - ), - }; - } - - pub fn intoXYZd65(_p3: *const P3) XYZd65 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L91 - // convert linear-light display-p3 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const MATRIX: [9]f32 = .{ - 0.4865709486482162, - 0.26566769316909306, - 0.1982172852343625, - 0.2289745640697488, - 0.6917385218365064, - 0.079286914093745, - 0.0000000000000000, - 0.04511338185890264, - 1.043944368900976, - }; - - const p3 = _p3.resolveMissing(); - const r, const g, const b = linSrgb(p3.r, p3.g, p3.b); - const x, const y, const z = multiplyMatrix(&MATRIX, r, g, b); - return XYZd65{ - .x = x, - .y = y, - .z = z, - .alpha = p3.alpha, - }; - } - }; - - pub const convert_A98 = struct { - pub fn intoPredefinedColor(rgb: *const A98) PredefinedColor { - return PredefinedColor{ .a98 = rgb.* }; - } - - pub fn intoCssColor(rgb: *const A98, allocator: Allocator) CssColor { - return CssColor{ - .predefined = bun.create( - allocator, - PredefinedColor, - rgb.into(.PredefinedColor), - ), - }; - } - - pub fn intoXYZd65(_a98: *const A98) XYZd65 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L181 - const H = struct { - pub fn linA98rgbComponent(c: f32) f32 { - const sign: f32 = if (c < 0.0) @as(f32, -1.0) else @as(f32, 1.0); - return sign * bun.powf(@abs(c), 563.0 / 256.0); - } - }; - - // convert an array of a98-rgb values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // negative values are also now accepted - const a98 = _a98.resolveMissing(); - const r = H.linA98rgbComponent(a98.r); - const g = H.linA98rgbComponent(a98.g); - const b = H.linA98rgbComponent(a98.b); - - // convert an array of linear-light a98-rgb values to CIE XYZ - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - // has greater numerical precision than section 4.3.5.3 of - // https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf - // but the values below were calculated from first principles - // from the chromaticity coordinates of R G B W - // see matrixmaker.html - const MATRIX: [9]f32 = .{ - 0.5766690429101305, - 0.1855582379065463, - 0.1882286462349947, - 0.29734497525053605, - 0.6273635662554661, - 0.07529145849399788, - 0.02703136138641234, - 0.07068885253582723, - 0.9913375368376388, - }; - - const x, const y, const z = multiplyMatrix(&MATRIX, r, g, b); - return XYZd65{ - .x = x, - .y = y, - .z = z, - .alpha = a98.alpha, - }; - } - }; - - pub const convert_ProPhoto = struct { - pub fn intoPredefinedColor(rgb: *const ProPhoto) PredefinedColor { - return PredefinedColor{ .prophoto = rgb.* }; - } - - pub fn intoCssColor(rgb: *const ProPhoto, allocator: Allocator) CssColor { - return CssColor{ - .predefined = bun.create( - allocator, - PredefinedColor, - rgb.into(.PredefinedColor), - ), - }; - } - - pub fn intoXYZd50(_prophoto: *const ProPhoto) XYZd50 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L118 - // convert an array of prophoto-rgb values - // where in-gamut colors are in the range [0.0 - 1.0] - // to linear light (un-companded) form. - // Transfer curve is gamma 1.8 with a small linear portion - // Extended transfer function - - const H = struct { - pub fn linProPhotoComponent(c: f32) f32 { - const ET2: f32 = 16.0 / 512.0; - const abs = @abs(c); - if (abs <= ET2) { - return c / 16.0; - } - const sign: f32 = if (c < 0.0) -1.0 else 1.0; - return sign * bun.powf(abs, 1.8); - } - }; - - const prophoto = _prophoto.resolveMissing(); - const r = H.linProPhotoComponent(prophoto.r); - const g = H.linProPhotoComponent(prophoto.g); - const b = H.linProPhotoComponent(prophoto.b); - - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L155 - // convert an array of linear-light prophoto-rgb values to CIE XYZ - // using D50 (so no chromatic adaptation needed afterwards) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const MATRIX: [9]f32 = .{ - 0.7977604896723027, - 0.13518583717574031, - 0.0313493495815248, - 0.2880711282292934, - 0.7118432178101014, - 0.00008565396060525902, - 0.0, - 0.0, - 0.8251046025104601, - }; - - const x, const y, const z = multiplyMatrix(&MATRIX, r, g, b); - return XYZd50{ - .x = x, - .y = y, - .z = z, - .alpha = prophoto.alpha, - }; - } - }; - - pub const convert_Rec2020 = struct { - pub fn intoPredefinedColor(rgb: *const Rec2020) PredefinedColor { - return PredefinedColor{ .rec2020 = rgb.* }; - } - - pub fn intoCssColor(rgb: *const Rec2020, allocator: Allocator) CssColor { - return CssColor{ - .predefined = bun.create( - allocator, - PredefinedColor, - rgb.into(.PredefinedColor), - ), - }; - } - - pub fn intoXYZd65(_rec2020: *const Rec2020) XYZd65 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L235 - // convert an array of rec2020 RGB values in the range 0.0 - 1.0 - // to linear light (un-companded) form. - // ITU-R BT.2020-2 p.4 - - const H = struct { - pub fn linRec2020Component(c: f32) f32 { - const A: f32 = 1.09929682680944; - const B: f32 = 0.018053968510807; - - const abs = @abs(c); - if (abs < B * 4.5) { - return c / 4.5; - } - - const sign: f32 = if (c < 0.0) -1.0 else 1.0; - return sign * bun.powf( - (abs + A - 1.0) / A, - 1.0 / 0.45, - ); - } - }; - - const rec2020 = _rec2020.resolveMissing(); - const r = H.linRec2020Component(rec2020.r); - const g = H.linRec2020Component(rec2020.g); - const b = H.linRec2020Component(rec2020.b); - - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L276 - // convert an array of linear-light rec2020 values to CIE XYZ - // using D65 (no chromatic adaptation) - // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - const MATRIX: [9]f32 = .{ - 0.6369580483012914, - 0.14461690358620832, - 0.1688809751641721, - 0.2627002120112671, - 0.6779980715188708, - 0.05930171646986196, - 0.000000000000000, - 0.028072693049087428, - 1.060985057710791, - }; - - const x, const y, const z = multiplyMatrix(&MATRIX, r, g, b); - - return XYZd65{ - .x = x, - .y = y, - .z = z, - .alpha = rec2020.alpha, - }; - } - }; - - pub const convert_XYZd50 = struct { - pub fn intoPredefinedColor(rgb: *const XYZd50) PredefinedColor { - return PredefinedColor{ .xyz_d50 = rgb.* }; - } - - pub fn intoCssColor(rgb: *const XYZd50, allocator: Allocator) CssColor { - return CssColor{ - .predefined = bun.create( - allocator, - PredefinedColor, - rgb.into(.PredefinedColor), - ), - }; - } - - pub fn intoLAB(_xyz: *const XYZd50) LAB { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L332 - // Assuming XYZ is relative to D50, convert to CIE LAB - // from CIE standard, which now defines these as a rational fraction - const E: f32 = 216.0 / 24389.0; // 6^3/29^3 - const K: f32 = 24389.0 / 27.0; // 29^3/3^3 - - // compute xyz, which is XYZ scaled relative to reference white - const xyz = _xyz.resolveMissing(); - const x = xyz.x / D50[0]; - const y = xyz.y / D50[1]; - const z = xyz.z / D50[2]; - - // now compute f - - const f0 = if (x > E) std.math.cbrt(x) else (K * x + 16.0) / 116.0; - - const f1 = if (y > E) std.math.cbrt(y) else (K * y + 16.0) / 116.0; - - const f2 = if (z > E) std.math.cbrt(z) else (K * z + 16.0) / 116.0; - - const l = ((116.0 * f1) - 16.0) / 100.0; - const a = 500.0 * (f0 - f1); - const b = 200.0 * (f1 - f2); - - return LAB{ - .l = l, - .a = a, - .b = b, - .alpha = xyz.alpha, - }; - } - - pub fn intoXYZd65(_xyz: *const XYZd50) XYZd65 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L105 - const MATRIX: [9]f32 = .{ - 0.9554734527042182, - -0.023098536874261423, - 0.0632593086610217, - -0.028369706963208136, - 1.0099954580058226, - 0.021041398966943008, - 0.012314001688319899, - -0.020507696433477912, - 1.3303659366080753, - }; - - const xyz = _xyz.resolveMissing(); - const x, const y, const z = multiplyMatrix(&MATRIX, xyz.x, xyz.y, xyz.z); - return XYZd65{ - .x = x, - .y = y, - .z = z, - .alpha = xyz.alpha, - }; - } - - pub fn intoProPhoto(_xyz: *const XYZd50) ProPhoto { - // convert XYZ to linear-light prophoto-rgb - const MATRIX: [9]f32 = .{ - 1.3457989731028281, - -0.25558010007997534, - -0.05110628506753401, - -0.5446224939028347, - 1.5082327413132781, - 0.02053603239147973, - 0.0, - 0.0, - 1.2119675456389454, - }; - const H = struct { - pub fn gamProPhotoComponent(c: f32) f32 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L137 - // convert linear-light prophoto-rgb in the range 0.0-1.0 - // to gamma corrected form - // Transfer curve is gamma 1.8 with a small linear portion - // TODO for negative values, extend linear portion on reflection of axis, then add pow below that - const ET: f32 = 1.0 / 512.0; - const abs = @abs(c); - if (abs >= ET) { - const sign: f32 = if (c < 0.0) -1.0 else 1.0; - return sign * bun.powf(abs, 1.0 / 1.8); - } - return 16.0 * c; - } - }; - const xyz = _xyz.resolveMissing(); - const r1, const g1, const b1 = multiplyMatrix(&MATRIX, xyz.x, xyz.y, xyz.z); - const r = H.gamProPhotoComponent(r1); - const g = H.gamProPhotoComponent(g1); - const b = H.gamProPhotoComponent(b1); - return ProPhoto{ - .r = r, - .g = g, - .b = b, - .alpha = xyz.alpha, - }; - } - }; - - pub const convert_XYZd65 = struct { - pub fn intoPredefinedColor(rgb: *const XYZd65) PredefinedColor { - return PredefinedColor{ .xyz_d65 = rgb.* }; - } - - pub fn intoCssColor(rgb: *const XYZd65, allocator: Allocator) CssColor { - return CssColor{ - .predefined = bun.create( - allocator, - PredefinedColor, - rgb.into(.PredefinedColor), - ), - }; - } - - pub fn intoXYZd50(_xyz: *const XYZd65) XYZd50 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L319 - - const MATRIX: [9]f32 = .{ - 1.0479298208405488, - 0.022946793341019088, - -0.05019222954313557, - 0.029627815688159344, - 0.990434484573249, - -0.01707382502938514, - -0.009243058152591178, - 0.015055144896577895, - 0.7518742899580008, - }; - - const xyz = _xyz.resolveMissing(); - const x, const y, const z = multiplyMatrix(&MATRIX, xyz.x, xyz.y, xyz.z); - return XYZd50{ - .x = x, - .y = y, - .z = z, - .alpha = xyz.alpha, - }; - } - - pub fn intoSRGBLinear(_xyz: *const XYZd65) SRGBLinear { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L62 - const MATRIX: [9]f32 = .{ - 3.2409699419045226, - -1.537383177570094, - -0.4986107602930034, - -0.9692436362808796, - 1.8759675015077202, - 0.04155505740717559, - 0.05563007969699366, - -0.20397695888897652, - 1.0569715142428786, - }; - - const xyz = _xyz.resolveMissing(); - const r, const g, const b = multiplyMatrix(&MATRIX, xyz.x, xyz.y, xyz.z); - return SRGBLinear{ - .r = r, - .g = g, - .b = b, - .alpha = xyz.alpha, - }; - } - - pub fn intoA98(_xyz: *const XYZd65) A98 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L222 - // convert XYZ to linear-light a98-rgb - - const MATRIX: [9]f32 = .{ - 2.0415879038107465, - -0.5650069742788596, - -0.34473135077832956, - -0.9692436362808795, - 1.8759675015077202, - 0.04155505740717557, - 0.013444280632031142, - -0.11836239223101838, - 1.0151749943912054, - }; - - const H = struct { - pub fn gamA98Component(c: f32) f32 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L193 - // convert linear-light a98-rgb in the range 0.0-1.0 - // to gamma corrected form - // negative values are also now accepted - const sign: f32 = if (c < 0.0) -1.0 else 1.0; - return sign * bun.powf(@abs(c), 256.0 / 563.0); - } - }; - - const xyz = _xyz.resolveMissing(); - const r1, const g1, const b1 = multiplyMatrix(&MATRIX, xyz.x, xyz.y, xyz.z); - const r = H.gamA98Component(r1); - const g = H.gamA98Component(g1); - const b = H.gamA98Component(b1); - return A98{ - .r = r, - .g = g, - .b = b, - .alpha = xyz.alpha, - }; - } - - pub fn intoRec2020(_xyz: *const XYZd65) Rec2020 { - // convert XYZ to linear-light rec2020 - const MATRIX: [9]f32 = .{ - 1.7166511879712674, - -0.35567078377639233, - -0.25336628137365974, - -0.6666843518324892, - 1.6164812366349395, - 0.01576854581391113, - 0.017639857445310783, - -0.042770613257808524, - 0.9421031212354738, - }; - - const H = struct { - pub fn gamRec2020Component(c: f32) f32 { - // convert linear-light rec2020 RGB in the range 0.0-1.0 - // to gamma corrected form - // ITU-R BT.2020-2 p.4 - - const A: f32 = 1.09929682680944; - const B: f32 = 0.018053968510807; - - const abs = @abs(c); - if (abs > B) { - const sign: f32 = if (c < 0.0) -1.0 else 1.0; - return sign * (A * bun.powf(abs, 0.45) - (A - 1.0)); - } - - return 4.5 * c; - } - }; - - const xyz = _xyz.resolveMissing(); - const r1, const g1, const b1 = multiplyMatrix(&MATRIX, xyz.x, xyz.y, xyz.z); - const r = H.gamRec2020Component(r1); - const g = H.gamRec2020Component(g1); - const b = H.gamRec2020Component(b1); - return Rec2020{ - .r = r, - .g = g, - .b = b, - .alpha = xyz.alpha, - }; - } - - pub fn intoOKLAB(_xyz: *const XYZd65) OKLAB { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L400 - const XYZ_TO_LMS: [9]f32 = .{ - 0.8190224432164319, - 0.3619062562801221, - -0.12887378261216414, - 0.0329836671980271, - 0.9292868468965546, - 0.03614466816999844, - 0.048177199566046255, - 0.26423952494422764, - 0.6335478258136937, - }; - - const LMS_TO_OKLAB: [9]f32 = .{ - 0.2104542553, - 0.7936177850, - -0.0040720468, - 1.9779984951, - -2.4285922050, - 0.4505937099, - 0.0259040371, - 0.7827717662, - -0.8086757660, - }; - - const cbrt = std.math.cbrt; - - const xyz = _xyz.resolveMissing(); - const a1, const b1, const c1 = multiplyMatrix(&XYZ_TO_LMS, xyz.x, xyz.y, xyz.z); - const l, const a, const b = multiplyMatrix(&LMS_TO_OKLAB, cbrt(a1), cbrt(b1), cbrt(c1)); - - return OKLAB{ - .l = l, - .a = a, - .b = b, - .alpha = xyz.alpha, - }; - } - - pub fn intoP3(_xyz: *const XYZd65) P3 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L105 - const MATRIX: [9]f32 = .{ - 2.493496911941425, - -0.9313836179191239, - -0.40271078445071684, - -0.8294889695615747, - 1.7626640603183463, - 0.023624685841943577, - 0.03584583024378447, - -0.07617238926804182, - 0.9568845240076872, - }; - - const xyz = _xyz.resolveMissing(); - const r1, const g1, const b1 = multiplyMatrix(&MATRIX, xyz.x, xyz.y, xyz.z); - const r, const g, const b = gamSrgb(r1, g1, b1); // same as sRGB - return P3{ - .r = r, - .g = g, - .b = b, - .alpha = xyz.alpha, - }; - } - }; - - pub const convert_LCH = struct { - pub fn intoCssColor(c: *const LCH, allocator: Allocator) CssColor { - return CssColor{ .lab = bun.create( - allocator, - LABColor, - LABColor{ .lch = c.* }, - ) }; - } - - pub fn intoLAB(_lch: *const LCH) LAB { - const lch = _lch.resolveMissing(); - const l, const a, const b = polarToRectangular(lch.l, lch.c, lch.h); - return LAB{ - .l = l, - .a = a, - .b = b, - .alpha = lch.alpha, - }; - } - }; - - pub const convert_OKLAB = struct { - pub fn intoCssColor(c: *const OKLAB, allocator: Allocator) CssColor { - return CssColor{ .lab = bun.create( - allocator, - LABColor, - LABColor{ .oklab = c.* }, - ) }; - } - - pub fn intoOKLAB(labb: *const OKLAB) OKLAB { - return labb.*; - } - - pub fn intoOKLCH(labb: *const OKLAB) OKLCH { - const lab = labb.resolveMissing(); - const l, const c, const h = rectangularToPolar(lab.l, lab.a, lab.b); - return OKLCH{ - .l = l, - .c = c, - .h = h, - .alpha = lab.alpha, - }; - } - - pub fn intoXYZd65(_lab: *const OKLAB) XYZd65 { - // https://github.com/w3c/csswg-drafts/blob/fba005e2ce9bcac55b49e4aa19b87208b3a0631e/css-color-4/conversions.js#L418 - const LMS_TO_XYZ: [9]f32 = .{ - 1.2268798733741557, - -0.5578149965554813, - 0.28139105017721583, - -0.04057576262431372, - 1.1122868293970594, - -0.07171106666151701, - -0.07637294974672142, - -0.4214933239627914, - 1.5869240244272418, - }; - - const OKLAB_TO_LMS: [9]f32 = .{ - 0.99999999845051981432, - 0.39633779217376785678, - 0.21580375806075880339, - 1.0000000088817607767, - -0.1055613423236563494, - -0.063854174771705903402, - 1.0000000546724109177, - -0.089484182094965759684, - -1.2914855378640917399, - }; - - const lab = _lab.resolveMissing(); - const a, const b, const c = multiplyMatrix(&OKLAB_TO_LMS, lab.l, lab.a, lab.b); - const x, const y, const z = multiplyMatrix( - &LMS_TO_XYZ, - bun.powf(a, 3), - bun.powf(b, 3), - bun.powf(c, 3), - ); - - return XYZd65{ - .x = x, - .y = y, - .z = z, - .alpha = lab.alpha, - }; - } - }; - - pub const convert_OKLCH = struct { - pub fn intoCssColor(c: *const OKLCH, allocator: Allocator) CssColor { - return CssColor{ .lab = bun.create( - allocator, - LABColor, - LABColor{ .oklch = c.* }, - ) }; - } - - pub fn intoOKLAB(_lch: *const OKLCH) OKLAB { - const lch = _lch.resolveMissing(); - const l, const a, const b = polarToRectangular(lch.l, lch.c, lch.h); - return OKLAB{ - .l = l, - .a = a, - .b = b, - .alpha = lch.alpha, - }; - } - - pub fn intoOKLCH(x: *const OKLCH) OKLCH { - return x.*; - } - }; -}; - -pub const ConvertTo = enum { - RGBA, - LAB, - SRGB, - HSL, - HWB, - SRGBLinear, - P3, - A98, - ProPhoto, - Rec2020, - XYZd50, - XYZd65, - LCH, - OKLAB, - OKLCH, - PredefinedColor, - pub fn fromType(comptime T: type) ConvertTo { - return @field(ConvertTo, bun.meta.typeName(T)); - } - pub fn Type(comptime space: ConvertTo) type { - return switch (space) { - .RGBA => RGBA, - .LAB => LAB, - .SRGB => SRGB, - .HSL => HSL, - .HWB => HWB, - .SRGBLinear => SRGBLinear, - .P3 => P3, - .A98 => A98, - .ProPhoto => ProPhoto, - .Rec2020 => Rec2020, - .XYZd50 => XYZd50, - .XYZd65 => XYZd65, - .LCH => LCH, - .OKLAB => OKLAB, - .OKLCH => OKLCH, - .PredefinedColor => PredefinedColor, - }; - } -}; -pub fn ColorIntoMixin(T: type, space: ConvertTo) type { - return struct { - pub const into_names = struct { - const RGBA = "intoRGBA"; - const LAB = "intoLAB"; - const SRGB = "intoSRGB"; - const HSL = "intoHSL"; - const HWB = "intoHWB"; - const SRGBLinear = "intoSRGBLinear"; - const P3 = "intoP3"; - const A98 = "intoA98"; - const ProPhoto = "intoProPhoto"; - const Rec2020 = "intoRec2020"; - const XYZd50 = "intoXYZd50"; - const XYZd65 = "intoXYZd65"; - const LCH = "intoLCH"; - const OKLAB = "intoOKLAB"; - const OKLCH = "intoOKLCH"; - const PredefinedColor = "intoPredefinedColor"; - }; - const ns = "convert_" ++ @tagName(space); - - const handwritten_conversions = @field(color_conversions, ns); - const generated_conversions = @field(generated_color_conversions, ns); - - pub fn into(color: *const T, comptime target_space: ConvertTo) target_space.Type() { - if (target_space == space) return color.*; - - const name = @field(into_names, @tagName(target_space)); - - const function = if (@hasDecl(handwritten_conversions, name)) - @field(handwritten_conversions, name) - else if (@hasDecl(generated_conversions, name)) - @field(generated_conversions, name) - else if (@hasDecl(T, name)) - @field(T, name) - else - @compileError("No conversion from " ++ @tagName(space) ++ " to " ++ @tagName(target_space)); - - return function(color); - } - }; -} - -pub fn ImplementIntoCssColor(comptime T: type, space: ConvertTo) fn (*const T, Allocator) CssColor { - const ns = "convert_" ++ @tagName(space); - return @field(color_conversions, ns).intoCssColor; -} - -const std = @import("std"); -const generated_color_conversions = @import("./color_generated.zig").generated_color_conversions; -const Allocator = std.mem.Allocator; - -const bun = @import("bun"); -const bits = bun.bits; diff --git a/src/css/values/color_generated.rs b/src/css/values/color_generated.rs index b2d7629fd8bb..f2793f2fb785 100644 --- a/src/css/values/color_generated.rs +++ b/src/css/values/color_generated.rs @@ -1,14 +1,4 @@ -//! This file is generated by `color_via.ts`. Do not edit it directly! -//! -//! Generated colorspace conversions: each is an `impl From for Dst`. -//! Handwritten conversions and this generated table are both -//! flattened into the global `From`/`Into` trait graph, so any pair already -//! defined by a handwritten impl in `color.rs` is *omitted* below to avoid the -//! overlapping-impl error (Rust forbids duplicate `From` impls). -//! -//! Omitted (handwritten in `color.rs::gated_full_impl` takes precedence): -//! - `From for RGBA` -//! - `From for RGBA` +//! Hand-maintained colorspace conversion graph. use super::color::{ A98, HSL, HWB, LAB, LCH, OKLAB, OKLCH, P3, ProPhoto, RGBA, Rec2020, SRGB, SRGBLinear, XYZd50, diff --git a/src/css/values/color_generated.zig b/src/css/values/color_generated.zig deleted file mode 100644 index ec8790e53574..000000000000 --- a/src/css/values/color_generated.zig +++ /dev/null @@ -1,946 +0,0 @@ -//!This file is generated by `color_via.ts`. Do not edit it directly! - -pub const generated_color_conversions = struct { - pub const convert_RGBA = struct { - pub fn intoLAB(this: *const RGBA) LAB { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const RGBA) LCH { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.LCH); - } - - pub fn intoOKLAB(this: *const RGBA) OKLAB { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const RGBA) OKLCH { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.OKLCH); - } - - pub fn intoP3(this: *const RGBA) P3 { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const RGBA) SRGBLinear { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const RGBA) A98 { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const RGBA) ProPhoto { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.ProPhoto); - } - - pub fn intoXYZd50(this: *const RGBA) XYZd50 { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.XYZd50); - } - - pub fn intoXYZd65(this: *const RGBA) XYZd65 { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.XYZd65); - } - - pub fn intoRec2020(this: *const RGBA) Rec2020 { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.Rec2020); - } - - pub fn intoHSL(this: *const RGBA) HSL { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const RGBA) HWB { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.HWB); - } - }; - pub const convert_LAB = struct { - pub fn intoXYZd65(this: *const LAB) XYZd65 { - const xyz: XYZd50 = this.into(.XYZd50); - return xyz.into(.XYZd65); - } - - pub fn intoOKLAB(this: *const LAB) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const LAB) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoSRGB(this: *const LAB) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoSRGBLinear(this: *const LAB) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoP3(this: *const LAB) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoA98(this: *const LAB) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const LAB) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoRec2020(this: *const LAB) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoHSL(this: *const LAB) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const LAB) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const LAB) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_SRGB = struct { - pub fn intoLAB(this: *const SRGB) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const SRGB) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoXYZd65(this: *const SRGB) XYZd65 { - const xyz: SRGBLinear = this.into(.SRGBLinear); - return xyz.into(.XYZd65); - } - - pub fn intoOKLAB(this: *const SRGB) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const SRGB) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoP3(this: *const SRGB) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoA98(this: *const SRGB) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const SRGB) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoRec2020(this: *const SRGB) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoXYZd50(this: *const SRGB) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - }; - pub const convert_HSL = struct { - pub fn intoLAB(this: *const HSL) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const HSL) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoP3(this: *const HSL) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const HSL) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const HSL) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const HSL) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoXYZd50(this: *const HSL) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoRec2020(this: *const HSL) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoOKLAB(this: *const HSL) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const HSL) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoXYZd65(this: *const HSL) XYZd65 { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.XYZd65); - } - - pub fn intoHWB(this: *const HSL) HWB { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const HSL) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_HWB = struct { - pub fn intoLAB(this: *const HWB) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const HWB) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoP3(this: *const HWB) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const HWB) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const HWB) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const HWB) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoXYZd50(this: *const HWB) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoRec2020(this: *const HWB) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoHSL(this: *const HWB) HSL { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.HSL); - } - - pub fn intoXYZd65(this: *const HWB) XYZd65 { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.XYZd65); - } - - pub fn intoOKLAB(this: *const HWB) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const HWB) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoRGBA(this: *const HWB) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_SRGBLinear = struct { - pub fn intoLAB(this: *const SRGBLinear) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const SRGBLinear) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoP3(this: *const SRGBLinear) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoOKLAB(this: *const SRGBLinear) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const SRGBLinear) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoA98(this: *const SRGBLinear) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const SRGBLinear) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoRec2020(this: *const SRGBLinear) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoXYZd50(this: *const SRGBLinear) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoHSL(this: *const SRGBLinear) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const SRGBLinear) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const SRGBLinear) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_P3 = struct { - pub fn intoLAB(this: *const P3) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const P3) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const P3) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoSRGBLinear(this: *const P3) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoOKLAB(this: *const P3) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const P3) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoA98(this: *const P3) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const P3) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoRec2020(this: *const P3) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoXYZd50(this: *const P3) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoHSL(this: *const P3) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const P3) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const P3) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_A98 = struct { - pub fn intoLAB(this: *const A98) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const A98) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const A98) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoP3(this: *const A98) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const A98) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoOKLAB(this: *const A98) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const A98) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoProPhoto(this: *const A98) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoRec2020(this: *const A98) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoXYZd50(this: *const A98) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoHSL(this: *const A98) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const A98) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const A98) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_ProPhoto = struct { - pub fn intoXYZd65(this: *const ProPhoto) XYZd65 { - const xyz: XYZd50 = this.into(.XYZd50); - return xyz.into(.XYZd65); - } - - pub fn intoLAB(this: *const ProPhoto) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const ProPhoto) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const ProPhoto) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoP3(this: *const ProPhoto) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const ProPhoto) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const ProPhoto) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoOKLAB(this: *const ProPhoto) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const ProPhoto) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoRec2020(this: *const ProPhoto) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoHSL(this: *const ProPhoto) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const ProPhoto) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const ProPhoto) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_Rec2020 = struct { - pub fn intoLAB(this: *const Rec2020) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const Rec2020) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const Rec2020) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoP3(this: *const Rec2020) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const Rec2020) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const Rec2020) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const Rec2020) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoXYZd50(this: *const Rec2020) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoOKLAB(this: *const Rec2020) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const Rec2020) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoHSL(this: *const Rec2020) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const Rec2020) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const Rec2020) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_XYZd50 = struct { - pub fn intoLCH(this: *const XYZd50) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const XYZd50) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoP3(this: *const XYZd50) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const XYZd50) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const XYZd50) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoOKLAB(this: *const XYZd50) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const XYZd50) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoRec2020(this: *const XYZd50) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoHSL(this: *const XYZd50) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const XYZd50) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const XYZd50) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_XYZd65 = struct { - pub fn intoLAB(this: *const XYZd65) LAB { - const xyz: XYZd50 = this.into(.XYZd50); - return xyz.into(.LAB); - } - - pub fn intoProPhoto(this: *const XYZd65) ProPhoto { - const xyz: XYZd50 = this.into(.XYZd50); - return xyz.into(.ProPhoto); - } - - pub fn intoOKLCH(this: *const XYZd65) OKLCH { - const xyz: OKLAB = this.into(.OKLAB); - return xyz.into(.OKLCH); - } - - pub fn intoLCH(this: *const XYZd65) LCH { - const xyz: LAB = this.into(.LAB); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const XYZd65) SRGB { - const xyz: SRGBLinear = this.into(.SRGBLinear); - return xyz.into(.SRGB); - } - - pub fn intoHSL(this: *const XYZd65) HSL { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const XYZd65) HWB { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const XYZd65) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_LCH = struct { - pub fn intoXYZd65(this: *const LCH) XYZd65 { - const xyz: LAB = this.into(.LAB); - return xyz.into(.XYZd65); - } - - pub fn intoOKLAB(this: *const LCH) OKLAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLAB); - } - - pub fn intoOKLCH(this: *const LCH) OKLCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.OKLCH); - } - - pub fn intoSRGB(this: *const LCH) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoSRGBLinear(this: *const LCH) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoP3(this: *const LCH) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoA98(this: *const LCH) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const LCH) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoRec2020(this: *const LCH) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoXYZd50(this: *const LCH) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoHSL(this: *const LCH) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const LCH) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const LCH) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_OKLAB = struct { - pub fn intoLAB(this: *const OKLAB) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const OKLAB) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const OKLAB) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoP3(this: *const OKLAB) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const OKLAB) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const OKLAB) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const OKLAB) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoXYZd50(this: *const OKLAB) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoRec2020(this: *const OKLAB) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoHSL(this: *const OKLAB) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const OKLAB) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const OKLAB) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; - pub const convert_OKLCH = struct { - pub fn intoXYZd65(this: *const OKLCH) XYZd65 { - const xyz: OKLAB = this.into(.OKLAB); - return xyz.into(.XYZd65); - } - - pub fn intoLAB(this: *const OKLCH) LAB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LAB); - } - - pub fn intoLCH(this: *const OKLCH) LCH { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.LCH); - } - - pub fn intoSRGB(this: *const OKLCH) SRGB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGB); - } - - pub fn intoP3(this: *const OKLCH) P3 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.P3); - } - - pub fn intoSRGBLinear(this: *const OKLCH) SRGBLinear { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.SRGBLinear); - } - - pub fn intoA98(this: *const OKLCH) A98 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.A98); - } - - pub fn intoProPhoto(this: *const OKLCH) ProPhoto { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.ProPhoto); - } - - pub fn intoXYZd50(this: *const OKLCH) XYZd50 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.XYZd50); - } - - pub fn intoRec2020(this: *const OKLCH) Rec2020 { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.Rec2020); - } - - pub fn intoHSL(this: *const OKLCH) HSL { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HSL); - } - - pub fn intoHWB(this: *const OKLCH) HWB { - const xyz: XYZd65 = this.into(.XYZd65); - return xyz.into(.HWB); - } - - pub fn intoRGBA(this: *const OKLCH) RGBA { - const xyz: SRGB = this.into(.SRGB); - return xyz.into(.RGBA); - } - }; -}; - -const color = @import("./color.zig"); -const A98 = color.A98; -const HSL = color.HSL; -const HWB = color.HWB; -const LAB = color.LAB; -const LCH = color.LCH; -const OKLAB = color.OKLAB; -const OKLCH = color.OKLCH; -const P3 = color.P3; -const ProPhoto = color.ProPhoto; -const RGBA = color.RGBA; -const Rec2020 = color.Rec2020; -const SRGB = color.SRGB; -const SRGBLinear = color.SRGBLinear; -const XYZd50 = color.XYZd50; -const XYZd65 = color.XYZd65; diff --git a/src/css/values/color_via.ts b/src/css/values/color_via.ts deleted file mode 100644 index fd1127c6f0d2..000000000000 --- a/src/css/values/color_via.ts +++ /dev/null @@ -1,231 +0,0 @@ -const RGBA = "RGBA"; -const LAB = "LAB"; -const SRGB = "SRGB"; -const HSL = "HSL"; -const HWB = "HWB"; -const SRGBLinear = "SRGBLinear"; -const P3 = "P3"; -const A98 = "A98"; -const ProPhoto = "ProPhoto"; -const Rec2020 = "Rec2020"; -const XYZd50 = "XYZd50"; -const XYZd65 = "XYZd65"; -const LCH = "LCH"; -const OKLAB = "OKLAB"; -const OKLCH = "OKLCH"; -const color_spaces = [ - RGBA, - LAB, - SRGB, - HSL, - HWB, - SRGBLinear, - P3, - A98, - ProPhoto, - Rec2020, - XYZd50, - XYZd65, - LCH, - OKLAB, - OKLCH, -]; - -type ColorSpaces = - | typeof RGBA - | typeof LAB - | typeof SRGB - | typeof HSL - | typeof HWB - | typeof SRGBLinear - | typeof P3 - | typeof A98 - | typeof ProPhoto - | typeof Rec2020 - | typeof XYZd50 - | typeof XYZd65 - | typeof LCH - | typeof OKLAB - | typeof OKLCH; - -type Foo = "a" | "b"; - -let code: Map = new Map(); - -initColorSpaces(); -addConversions(); -await generateCode(); - -function initColorSpaces() { - for (const space of color_spaces as ColorSpaces[]) { - code.set(space, []); - } -} - -async function generateCode() { - const output = `//!This file is generated by \`color_via.ts\`. Do not edit it directly! -const color = @import("./color.zig"); -const RGBA = color.RGBA; -const LAB = color.LAB; -const LCH = color.LCH; -const SRGB = color.SRGB; -const HSL = color.HSL; -const HWB = color.HWB; -const SRGBLinear = color.SRGBLinear; -const P3 = color.P3; -const A98 = color.A98; -const ProPhoto = color.ProPhoto; -const XYZd50 = color.XYZd50; -const XYZd65 = color.XYZd65; -const OKLAB = color.OKLAB; -const OKLCH = color.OKLCH; -const Rec2020 = color.Rec2020; - -pub const generated_color_conversions = struct { -${(() => { - let result = ""; - for (const [space, functions] of code) { - result += "\n"; - result += `pub const convert_${space} = struct {\n`; - result += functions.join("\n"); - result += "\n};"; - } - return result; -})()} -};`; - await Bun.$`echo ${output} > src/css/values/color_generated.zig; zig fmt src/css/values/color_generated.zig -`; -} - -function addConversions() { - // Once Rust specialization is stable, this could be simplified. - via("LAB", "XYZd50", "XYZd65"); - via("ProPhoto", "XYZd50", "XYZd65"); - via("OKLCH", "OKLAB", "XYZd65"); - - via("LAB", "XYZd65", "OKLAB"); - via("LAB", "XYZd65", "OKLCH"); - via("LAB", "XYZd65", "SRGB"); - via("LAB", "XYZd65", "SRGBLinear"); - via("LAB", "XYZd65", "P3"); - via("LAB", "XYZd65", "A98"); - via("LAB", "XYZd65", "ProPhoto"); - via("LAB", "XYZd65", "Rec2020"); - via("LAB", "XYZd65", "HSL"); - via("LAB", "XYZd65", "HWB"); - - via("LCH", "LAB", "XYZd65"); - via("LCH", "XYZd65", "OKLAB"); - via("LCH", "XYZd65", "OKLCH"); - via("LCH", "XYZd65", "SRGB"); - via("LCH", "XYZd65", "SRGBLinear"); - via("LCH", "XYZd65", "P3"); - via("LCH", "XYZd65", "A98"); - via("LCH", "XYZd65", "ProPhoto"); - via("LCH", "XYZd65", "Rec2020"); - via("LCH", "XYZd65", "XYZd50"); - via("LCH", "XYZd65", "HSL"); - via("LCH", "XYZd65", "HWB"); - - via("SRGB", "SRGBLinear", "XYZd65"); - via("SRGB", "XYZd65", "OKLAB"); - via("SRGB", "XYZd65", "OKLCH"); - via("SRGB", "XYZd65", "P3"); - via("SRGB", "XYZd65", "A98"); - via("SRGB", "XYZd65", "ProPhoto"); - via("SRGB", "XYZd65", "Rec2020"); - via("SRGB", "XYZd65", "XYZd50"); - - via("P3", "XYZd65", "SRGBLinear"); - via("P3", "XYZd65", "OKLAB"); - via("P3", "XYZd65", "OKLCH"); - via("P3", "XYZd65", "A98"); - via("P3", "XYZd65", "ProPhoto"); - via("P3", "XYZd65", "Rec2020"); - via("P3", "XYZd65", "XYZd50"); - via("P3", "XYZd65", "HSL"); - via("P3", "XYZd65", "HWB"); - - via("SRGBLinear", "XYZd65", "OKLAB"); - via("SRGBLinear", "XYZd65", "OKLCH"); - via("SRGBLinear", "XYZd65", "A98"); - via("SRGBLinear", "XYZd65", "ProPhoto"); - via("SRGBLinear", "XYZd65", "Rec2020"); - via("SRGBLinear", "XYZd65", "XYZd50"); - via("SRGBLinear", "XYZd65", "HSL"); - via("SRGBLinear", "XYZd65", "HWB"); - - via("A98", "XYZd65", "OKLAB"); - via("A98", "XYZd65", "OKLCH"); - via("A98", "XYZd65", "ProPhoto"); - via("A98", "XYZd65", "Rec2020"); - via("A98", "XYZd65", "XYZd50"); - via("A98", "XYZd65", "HSL"); - via("A98", "XYZd65", "HWB"); - - via("ProPhoto", "XYZd65", "OKLAB"); - via("ProPhoto", "XYZd65", "OKLCH"); - via("ProPhoto", "XYZd65", "Rec2020"); - via("ProPhoto", "XYZd65", "HSL"); - via("ProPhoto", "XYZd65", "HWB"); - - via("XYZd50", "XYZd65", "OKLAB"); - via("XYZd50", "XYZd65", "OKLCH"); - via("XYZd50", "XYZd65", "Rec2020"); - via("XYZd50", "XYZd65", "HSL"); - via("XYZd50", "XYZd65", "HWB"); - - via("Rec2020", "XYZd65", "OKLAB"); - via("Rec2020", "XYZd65", "OKLCH"); - via("Rec2020", "XYZd65", "HSL"); - via("Rec2020", "XYZd65", "HWB"); - - via("HSL", "XYZd65", "OKLAB"); - via("HSL", "XYZd65", "OKLCH"); - via("HSL", "SRGB", "XYZd65"); - via("HSL", "SRGB", "HWB"); - - via("HWB", "SRGB", "XYZd65"); - via("HWB", "XYZd65", "OKLAB"); - via("HWB", "XYZd65", "OKLCH"); - - // RGBA is an 8-bit version. Convert to SRGB, which is a - // more accurate floating point representation for all operations. - via("RGBA", "SRGB", "LAB"); - via("RGBA", "SRGB", "LCH"); - via("RGBA", "SRGB", "OKLAB"); - via("RGBA", "SRGB", "OKLCH"); - via("RGBA", "SRGB", "P3"); - via("RGBA", "SRGB", "SRGBLinear"); - via("RGBA", "SRGB", "A98"); - via("RGBA", "SRGB", "ProPhoto"); - via("RGBA", "SRGB", "XYZd50"); - via("RGBA", "SRGB", "XYZd65"); - via("RGBA", "SRGB", "Rec2020"); - via("RGBA", "SRGB", "HSL"); - via("RGBA", "SRGB", "HWB"); -} - -function via, V extends Exclude>( - from: T, - middle: U, - to: V, -) { - // Generate T, U, V function (where T, U, V are ColorSpaces) - let fromFunctions = code.get(from) || []; - fromFunctions.push(`pub fn into${to}(this: *const ${from}) ${to} { - const xyz: ${middle} = this.into${middle}(); - return xyz.into${to}(); -} -`); - code.set(from, fromFunctions); - - // Generate V, U, function - let toFunctions = code.get(to) || []; - toFunctions.push(`pub fn into${from}(this: *const ${to}) ${from} { - const xyz: ${middle} = this.into${middle}(); - return xyz.into${from}(); -} -`); - code.set(to, toFunctions); -} diff --git a/src/css/values/css_string.zig b/src/css/values/css_string.zig deleted file mode 100644 index 7bd88bb1f458..000000000000 --- a/src/css/values/css_string.zig +++ /dev/null @@ -1,16 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const Result = css.Result; -pub const Printer = css.Printer; -pub const PrintErr = css.PrintErr; - -/// A quoted CSS string. -pub const CSSString = []const u8; -pub const CSSStringFns = struct { - pub fn parse(input: *css.Parser) Result(CSSString) { - return input.expectString(); - } - - pub fn toCss(this: *const []const u8, dest: *Printer) PrintErr!void { - return css.serializer.serializeString(this.*, dest) catch return dest.addFmtError(); - } -}; diff --git a/src/css/values/easing.zig b/src/css/values/easing.zig deleted file mode 100644 index e87f282895c0..000000000000 --- a/src/css/values/easing.zig +++ /dev/null @@ -1,271 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const CSSInteger = css.css_values.number.CSSInteger; -const CSSIntegerFns = css.css_values.number.CSSIntegerFns; - -/// A CSS [easing function](https://www.w3.org/TR/css-easing-1/#easing-functions). -pub const EasingFunction = union(enum) { - /// A linear easing function. - linear, - /// Equivalent to `cubic-bezier(0.25, 0.1, 0.25, 1)`. - ease, - /// Equivalent to `cubic-bezier(0.42, 0, 1, 1)`. - ease_in, - /// Equivalent to `cubic-bezier(0, 0, 0.58, 1)`. - ease_out, - /// Equivalent to `cubic-bezier(0.42, 0, 0.58, 1)`. - ease_in_out, - /// A custom cubic Bézier easing function. - cubic_bezier: struct { - /// The x-position of the first point in the curve. - x1: CSSNumber, - /// The y-position of the first point in the curve. - y1: CSSNumber, - /// The x-position of the second point in the curve. - x2: CSSNumber, - /// The y-position of the second point in the curve. - y2: CSSNumber, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn __generateDeepClone() void {} - }, - /// A step easing function. - steps: struct { - /// The number of intervals in the function. - count: CSSInteger, - /// The step position. - position: StepPosition = StepPosition.default(), - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn __generateDeepClone() void {} - }, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - const Map = bun.ComptimeEnumMap(enum { - linear, - ease, - @"ease-in", - @"ease-out", - @"ease-in-out", - @"step-start", - @"step-end", - }); - - pub fn parse(input: *css.Parser) Result(EasingFunction) { - const location = input.currentSourceLocation(); - if (input.tryParse(struct { - fn parse(i: *css.Parser) Result([]const u8) { - return i.expectIdent(); - } - }.parse, .{}).asValue()) |ident| { - const keyword = if (Map.getASCIIICaseInsensitive(ident)) |e| switch (e) { - .linear => EasingFunction.linear, - .ease => EasingFunction.ease, - .@"ease-in" => EasingFunction.ease_in, - .@"ease-out" => EasingFunction.ease_out, - .@"ease-in-out" => EasingFunction.ease_in_out, - .@"step-start" => EasingFunction{ .steps = .{ .count = 1, .position = .start } }, - .@"step-end" => EasingFunction{ .steps = .{ .count = 1, .position = .end } }, - } else return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - - return .{ .result = keyword }; - } - - const function = switch (input.expectFunction()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const Closure = struct { loc: css.SourceLocation, function: []const u8 }; - return input.parseNestedBlock( - EasingFunction, - &Closure{ .loc = location, .function = function }, - struct { - fn parse( - closure: *const Closure, - i: *css.Parser, - ) Result(EasingFunction) { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "cubic-bezier")) { - const x1 = switch (CSSNumberFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const y1 = switch (CSSNumberFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const x2 = switch (CSSNumberFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - const y2 = switch (CSSNumberFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = EasingFunction{ .cubic_bezier = .{ .x1 = x1, .y1 = y1, .x2 = x2, .y2 = y2 } } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "steps")) { - const count = switch (CSSIntegerFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const position = i.tryParse(struct { - fn parse(p: *css.Parser) Result(StepPosition) { - if (p.expectComma().asErr()) |e| return .{ .err = e }; - return StepPosition.parse(p); - } - }.parse, .{}).unwrapOr(StepPosition.default()); - return .{ .result = EasingFunction{ .steps = .{ .count = count, .position = position } } }; - } else { - return .{ .err = closure.loc.newUnexpectedTokenError(.{ .ident = closure.function }) }; - } - } - }.parse, - ); - } - - pub fn toCss(this: *const EasingFunction, dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .linear => try dest.writeStr("linear"), - .ease => try dest.writeStr("ease"), - .ease_in => try dest.writeStr("ease-in"), - .ease_out => try dest.writeStr("ease-out"), - .ease_in_out => try dest.writeStr("ease-in-out"), - else => { - if (this.isEase()) { - return dest.writeStr("ease"); - } else if (this.* == .cubic_bezier and this.cubic_bezier.eql(&.{ - .x1 = 0.42, - .y1 = 0.0, - .x2 = 1.0, - .y2 = 1.0, - })) { - return dest.writeStr("ease-in"); - } else if (this.* == .cubic_bezier and this.cubic_bezier.eql(&.{ - .x1 = 0.0, - .y1 = 0.0, - .x2 = 0.58, - .y2 = 1.0, - })) { - return dest.writeStr("ease-out"); - } else if (this.* == .cubic_bezier and this.cubic_bezier.eql(&.{ - .x1 = 0.42, - .y1 = 0.0, - .x2 = 0.58, - .y2 = 1.0, - })) { - return dest.writeStr("ease-in-out"); - } - - switch (this.*) { - .cubic_bezier => |cb| { - try dest.writeStr("cubic-bezier("); - try css.generic.toCss(CSSNumber, &cb.x1, dest); - try dest.writeChar(','); - try css.generic.toCss(CSSNumber, &cb.y1, dest); - try dest.writeChar(','); - try css.generic.toCss(CSSNumber, &cb.x2, dest); - try dest.writeChar(','); - try css.generic.toCss(CSSNumber, &cb.y2, dest); - try dest.writeChar(')'); - }, - .steps => { - if (this.steps.count == 1 and this.steps.position == .start) { - return try dest.writeStr("step-start"); - } - if (this.steps.count == 1 and this.steps.position == .end) { - return try dest.writeStr("step-end"); - } - try dest.writeFmt("steps({d}", .{this.steps.count}); - try dest.delim(',', false); - try this.steps.position.toCss(dest); - return try dest.writeChar(')'); - }, - .linear, .ease, .ease_in, .ease_out, .ease_in_out => unreachable, - } - }, - }; - } - - /// Returns whether the given string is a valid easing function name. - pub fn isIdent(s: []const u8) bool { - return Map.getASCIIICaseInsensitive(s) != null; - } - - /// Returns whether the easing function is equivalent to the `ease` keyword. - pub fn isEase(this: *const EasingFunction) bool { - return this.* == .ease or - (this.* == .cubic_bezier and this.cubic_bezier.eql(&.{ - .x1 = 0.25, - .y1 = 0.1, - .x2 = 0.25, - .y2 = 1.0, - })); - } -}; - -/// A [step position](https://www.w3.org/TR/css-easing-1/#step-position), used within the `steps()` function. -pub const StepPosition = enum { - /// The first rise occurs at input progress value of 0. - start, - /// The last rise occurs at input progress value of 1. - end, - /// All rises occur within the range (0, 1). - @"jump-none", - /// The first rise occurs at input progress value of 0 and the last rise occurs at input progress value of 1. - @"jump-both", - - pub const toCss = css.DeriveToCss(@This()).toCss; - - const Map = bun.ComptimeEnumMap(enum { - start, - end, - @"jump-none", - @"jump-both", - @"jump-start", - @"jump-end", - }); - - pub fn parse(input: *css.Parser) Result(StepPosition) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const keyword = if (Map.getASCIIICaseInsensitive(ident)) |e| switch (e) { - .start => StepPosition.start, - .end => StepPosition.end, - .@"jump-start" => StepPosition.start, - .@"jump-end" => StepPosition.end, - .@"jump-none" => StepPosition.@"jump-none", - .@"jump-both" => StepPosition.@"jump-both", - } else return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - - return .{ .result = keyword }; - } - - pub fn default() StepPosition { - return .end; - } -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/values/gradient.zig b/src/css/values/gradient.zig deleted file mode 100644 index 1f7061253a1c..000000000000 --- a/src/css/values/gradient.zig +++ /dev/null @@ -1,1657 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const VendorPrefix = css.VendorPrefix; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CssColor = css.css_values.color.CssColor; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const Angle = css.css_values.angle.Angle; -const AnglePercentage = css.css_values.angle.AnglePercentage; -const HorizontalPositionKeyword = css.css_values.position.HorizontalPositionKeyword; -const VerticalPositionKeyword = css.css_values.position.VerticalPositionKeyword; -const Position = css.css_values.position.Position; -const Length = css.css_values.length.Length; -const LengthPercentage = css.css_values.length.LengthPercentage; -const NumberOrPercentage = css.css_values.percentage.NumberOrPercentage; - -/// A CSS [``](https://www.w3.org/TR/css-images-3/#gradients) value. -pub const Gradient = union(enum) { - /// A `linear-gradient()`, and its vendor prefix. - linear: LinearGradient, - /// A `repeating-linear-gradient()`, and its vendor prefix. - repeating_linear: LinearGradient, - /// A `radial-gradient()`, and its vendor prefix. - radial: RadialGradient, - /// A `repeating-radial-gradient`, and its vendor prefix. - repeating_radial: RadialGradient, - /// A `conic-gradient()`. - conic: ConicGradient, - /// A `repeating-conic-gradient()`. - repeating_conic: ConicGradient, - /// A legacy `-webkit-gradient()`. - @"webkit-gradient": WebKitGradient, - - pub fn parse(input: *css.Parser) Result(Gradient) { - const location = input.currentSourceLocation(); - const func = switch (input.expectFunction()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const Closure = struct { location: css.SourceLocation, func: []const u8 }; - return input.parseNestedBlock(Gradient, Closure{ .location = location, .func = func }, struct { - fn parse( - closure: Closure, - input_: *css.Parser, - ) Result(Gradient) { - const Map = comptime bun.ComptimeEnumMap(enum { - @"linear-gradient", - @"repeating-linear-gradient", - @"radial-gradient", - @"repeating-radial-gradient", - @"conic-gradient", - @"repeating-conic-gradient", - @"-webkit-linear-gradient", - @"-webkit-repeating-linear-gradient", - @"-webkit-radial-gradient", - @"-webkit-repeating-radial-gradient", - @"-moz-linear-gradient", - @"-moz-repeating-linear-gradient", - @"-moz-radial-gradient", - @"-moz-repeating-radial-gradient", - @"-o-linear-gradient", - @"-o-repeating-linear-gradient", - @"-o-radial-gradient", - @"-o-repeating-radial-gradient", - @"-webkit-gradient", - }); - if (Map.getAnyCase(closure.func)) |matched| - switch (matched) { - .@"linear-gradient" => { - return .{ .result = .{ .linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .none = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"repeating-linear-gradient" => { - return .{ .result = .{ .repeating_linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .none = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"radial-gradient" => { - return .{ .result = .{ .radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .none = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"repeating-radial-gradient" => { - return .{ .result = .{ .repeating_radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .none = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"conic-gradient" => { - return .{ .result = .{ .conic = switch (ConicGradient.parse(input_)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"repeating-conic-gradient" => { - return .{ .result = .{ .repeating_conic = switch (ConicGradient.parse(input_)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-webkit-linear-gradient" => { - return .{ .result = .{ .linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .webkit = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-webkit-repeating-linear-gradient" => { - return .{ .result = .{ .repeating_linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .webkit = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-webkit-radial-gradient" => { - return .{ .result = .{ .radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .webkit = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-webkit-repeating-radial-gradient" => { - return .{ .result = .{ .repeating_radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .webkit = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-moz-linear-gradient" => { - return .{ .result = .{ .linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .moz = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-moz-repeating-linear-gradient" => { - return .{ .result = .{ .repeating_linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .moz = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-moz-radial-gradient" => { - return .{ .result = .{ .radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .moz = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-moz-repeating-radial-gradient" => { - return .{ .result = .{ .repeating_radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .moz = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-o-linear-gradient" => { - return .{ .result = .{ .linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .o = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-o-repeating-linear-gradient" => { - return .{ .result = .{ .repeating_linear = switch (LinearGradient.parse(input_, css.VendorPrefix{ .o = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-o-radial-gradient" => { - return .{ .result = .{ .radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .o = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-o-repeating-radial-gradient" => { - return .{ .result = .{ .repeating_radial = switch (RadialGradient.parse(input_, css.VendorPrefix{ .o = true })) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - .@"-webkit-gradient" => { - return .{ .result = .{ .@"webkit-gradient" = switch (WebKitGradient.parse(input_)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } } }; - }, - } - else - return .{ .err = closure.location.newUnexpectedTokenError(.{ .ident = closure.func }) }; - } - }.parse); - } - - pub fn toCss(this: *const Gradient, dest: *Printer) PrintErr!void { - const f: []const u8, const prefix: ?css.VendorPrefix = switch (this.*) { - .linear => |g| .{ "linear-gradient(", g.vendor_prefix }, - .repeating_linear => |g| .{ "repeating-linear-gradient(", g.vendor_prefix }, - .radial => |g| .{ "radial-gradient(", g.vendor_prefix }, - .repeating_radial => |g| .{ "repeating-radial-gradient(", g.vendor_prefix }, - .conic => .{ "conic-gradient(", null }, - .repeating_conic => .{ "repeating-conic-gradient(", null }, - .@"webkit-gradient" => .{ "-webkit-gradient(", null }, - }; - - if (prefix) |p| { - try p.toCss(dest); - } - - try dest.writeStr(f); - - switch (this.*) { - .linear, .repeating_linear => |*linear| { - try linear.toCss(dest, linear.vendor_prefix != css.VendorPrefix{ .none = true }); - }, - .radial, .repeating_radial => |*radial| { - try radial.toCss(dest); - }, - .conic, .repeating_conic => |*conic| { - try conic.toCss(dest); - }, - .@"webkit-gradient" => |*g| { - try g.toCss(dest); - }, - } - - return dest.writeChar(')'); - } - - /// Attempts to convert the gradient to the legacy `-webkit-gradient()` syntax. - /// - /// Returns an error in case the conversion is not possible. - pub fn getLegacyWebkit(this: *const @This(), allocator: Allocator) ?Gradient { - return Gradient{ .@"webkit-gradient" = WebKitGradient.fromStandard(this, allocator) orelse return null }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const Gradient, other: *const Gradient) bool { - return css.implementEql(Gradient, this, other); - // if (this.* == .linear and other.* == .linear) { - // return this.linear.eql(&other.linear); - // } else if (this.* == .repeating_linear and other.* == .repeating_linear) { - // return this.repeating_linear.eql(&other.repeating_linear); - // } else if (this.* == .radial and other.* == .radial) { - // return this.radial.eql(&other.radial); - // } else if (this.* == .repeating_radial and other.* == .repeating_radial) { - // return this.repeating_radial.eql(&other.repeating_radial); - // } else if (this.* == .conic and other.* == .conic) { - // return this.conic.eql(&other.conic); - // } else if (this.* == .repeating_conic and other.* == .repeating_conic) { - // return this.repeating_conic.eql(&other.repeating_conic); - // } else if (this.* == .@"webkit-gradient" and other.* == .@"webkit-gradient") { - // return this.@"webkit-gradient".eql(&other.@"webkit-gradient"); - // } - // ret - } - - /// Returns the vendor prefix of the gradient. - pub fn getVendorPrefix(this: *const @This()) VendorPrefix { - return switch (this.*) { - .linear => |linear| linear.vendor_prefix, - .repeating_linear => |linear| linear.vendor_prefix, - .radial => |radial| radial.vendor_prefix, - .repeating_radial => |radial| radial.vendor_prefix, - .@"webkit-gradient" => VendorPrefix{ .webkit = true }, - else => VendorPrefix{ .none = true }, - }; - } - - /// Returns the vendor prefixes needed for the given browser targets. - pub fn getNecessaryPrefixes(this: *const @This(), targets: css.targets.Targets) css.VendorPrefix { - const getPrefixes = struct { - fn call(tgts: css.targets.Targets, feature: css.prefixes.Feature, prefix: VendorPrefix) VendorPrefix { - return tgts.prefixes(prefix, feature); - } - }.call; - - return switch (this.*) { - .linear => |linear| getPrefixes(targets, .linear_gradient, linear.vendor_prefix), - .repeating_linear => |linear| getPrefixes(targets, .repeating_linear_gradient, linear.vendor_prefix), - .radial => |radial| getPrefixes(targets, .radial_gradient, radial.vendor_prefix), - .repeating_radial => |radial| getPrefixes(targets, .repeating_radial_gradient, radial.vendor_prefix), - else => VendorPrefix{ .none = true }, - }; - } - - /// Returns a copy of the gradient with the given vendor prefix. - pub fn getPrefixed(this: *const @This(), allocator: Allocator, prefix: css.VendorPrefix) Gradient { - return switch (this.*) { - .linear => |*linear| .{ .linear = brk: { - var x = linear.deepClone(allocator); - x.vendor_prefix = prefix; - break :brk x; - } }, - .repeating_linear => |*linear| .{ .repeating_linear = brk: { - var x = linear.deepClone(allocator); - x.vendor_prefix = prefix; - break :brk x; - } }, - .radial => |*radial| .{ .radial = brk: { - var x = radial.deepClone(allocator); - x.vendor_prefix = prefix; - break :brk x; - } }, - .repeating_radial => |*radial| .{ .repeating_radial = brk: { - var x = radial.deepClone(allocator); - x.vendor_prefix = prefix; - break :brk x; - } }, - else => this.deepClone(allocator), - }; - } - - /// Returns a fallback gradient for the given color fallback type. - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: css.ColorFallbackKind) Gradient { - return switch (this.*) { - .linear => |g| .{ .linear = g.getFallback(allocator, kind) }, - .repeating_linear => |g| .{ .repeating_linear = g.getFallback(allocator, kind) }, - .radial => |g| .{ .radial = g.getFallback(allocator, kind) }, - .repeating_radial => |g| .{ .repeating_radial = g.getFallback(allocator, kind) }, - .conic => |g| .{ .conic = g.getFallback(allocator, kind) }, - .repeating_conic => |g| .{ .repeating_conic = g.getFallback(allocator, kind) }, - .@"webkit-gradient" => |g| .{ .@"webkit-gradient" = g.getFallback(allocator, kind) }, - }; - } - - /// Returns the color fallback types needed for the given browser targets. - pub fn getNecessaryFallbacks(this: *const @This(), targets: css.targets.Targets) css.ColorFallbackKind { - var fallbacks = css.ColorFallbackKind{}; - switch (this.*) { - .linear, .repeating_linear => |*linear| { - for (linear.items.items) |*item| { - bun.bits.insert(css.ColorFallbackKind, &fallbacks, item.getNecessaryFallbacks(targets)); - } - }, - .radial, .repeating_radial => |*radial| { - for (radial.items.items) |*item| { - bun.bits.insert(css.ColorFallbackKind, &fallbacks, item.getNecessaryFallbacks(targets)); - } - }, - .conic, .repeating_conic => |*conic| { - for (conic.items.items) |*item| { - bun.bits.insert(css.ColorFallbackKind, &fallbacks, item.getNecessaryFallbacks(targets)); - } - }, - .@"webkit-gradient" => {}, - } - return fallbacks; - } -}; - -/// A CSS [`linear-gradient()`](https://www.w3.org/TR/css-images-3/#linear-gradients) or `repeating-linear-gradient()`. -pub const LinearGradient = struct { - /// The vendor prefixes for the gradient. - vendor_prefix: VendorPrefix, - /// The direction of the gradient. - direction: LineDirection, - /// The color stops and transition hints for the gradient. - items: ArrayList(GradientItem(LengthPercentage)), - - pub fn parse(input: *css.Parser, vendor_prefix: VendorPrefix) Result(LinearGradient) { - const direction: LineDirection = if (input.tryParse(LineDirection.parse, .{vendor_prefix != VendorPrefix{ .none = true }}).asValue()) |dir| direction: { - if (input.expectComma().asErr()) |e| return .{ .err = e }; - break :direction dir; - } else LineDirection{ .vertical = .bottom }; - const items = switch (parseItems(LengthPercentage, input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = LinearGradient{ .direction = direction, .items = items, .vendor_prefix = vendor_prefix } }; - } - - pub fn toCss(this: *const LinearGradient, dest: *Printer, is_prefixed: bool) PrintErr!void { - const angle: f32 = switch (this.direction) { - .vertical => |v| switch (v) { - .bottom => 180.0, - .top => 0.0, - }, - .angle => |a| a.toDegrees(), - else => -1.0, - }; - - // We can omit `to bottom` or `180deg` because it is the default. - if (angle == 180.0) { - // todo_stuff.depth - try serializeItems(LengthPercentage, &this.items, dest); - } - // If we have `to top` or `0deg`, and all of the positions and hints are percentages, - // we can flip the gradient the other direction and omit the direction. - else if (angle == 0.0 and dest.minify and brk: { - for (this.items.items) |*item| { - if (item.* == .hint and item.hint != .percentage) break :brk false; - if (item.* == .color_stop and item.color_stop.position != null and item.color_stop.position.? != .percentage) break :brk false; - } - break :brk true; - }) { - var flipped_items = ArrayList(GradientItem(LengthPercentage)).initCapacity( - dest.allocator, - this.items.items.len, - ) catch |err| bun.handleOom(err); - defer flipped_items.deinit(dest.allocator); - - var i: usize = this.items.items.len; - while (i > 0) { - i -= 1; - const item = &this.items.items[i]; - switch (item.*) { - .hint => |*h| switch (h.*) { - .percentage => |p| bun.handleOom(flipped_items.append(dest.allocator, .{ .hint = .{ .percentage = .{ .v = 1.0 - p.v } } })), - else => unreachable, - }, - .color_stop => |*cs| flipped_items.append(dest.allocator, .{ - .color_stop = .{ - .color = cs.color, - .position = if (cs.position) |*p| switch (p.*) { - .percentage => |perc| .{ .percentage = .{ .v = 1.0 - perc.v } }, - else => unreachable, - } else null, - }, - }) catch |err| bun.handleOom(err), - } - } - - serializeItems(LengthPercentage, &flipped_items, dest) catch return dest.addFmtError(); - } else { - if (!this.direction.eql(&LineDirection{ .vertical = .bottom }) and - !this.direction.eql(&LineDirection{ .angle = Angle{ .deg = 180.0 } })) - { - try this.direction.toCss(dest, is_prefixed); - try dest.delim(',', false); - } - - serializeItems(LengthPercentage, &this.items, dest) catch return dest.addFmtError(); - } - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - for (this.items.items) |*item| { - if (!item.isCompatible(browsers)) return false; - } - return true; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const LinearGradient, other: *const LinearGradient) bool { - return css.implementEql(@This(), this, other); - } - - pub fn getFallback(this: *const @This(), allocator: std.mem.Allocator, kind: css.ColorFallbackKind) LinearGradient { - var fallback_items = bun.handleOom(ArrayList(GradientItem(LengthPercentage)).initCapacity(allocator, this.items.items.len)); - fallback_items.items.len = this.items.items.len; - for (fallback_items.items, this.items.items) |*out, *in| { - out.* = in.getFallback(allocator, kind); - } - - return LinearGradient{ - .direction = this.direction.deepClone(allocator), - .items = fallback_items, - .vendor_prefix = this.vendor_prefix, - }; - } -}; - -/// A CSS [`radial-gradient()`](https://www.w3.org/TR/css-images-3/#radial-gradients) or `repeating-radial-gradient()`. -pub const RadialGradient = struct { - /// The vendor prefixes for the gradient. - vendor_prefix: VendorPrefix, - /// The shape of the gradient. - shape: EndingShape, - /// The position of the gradient. - position: Position, - /// The color stops and transition hints for the gradient. - items: ArrayList(GradientItem(LengthPercentage)), - - pub fn parse(input: *css.Parser, vendor_prefix: VendorPrefix) Result(RadialGradient) { - // todo_stuff.depth - const shape = switch (input.tryParse(EndingShape.parse, .{})) { - .result => |vv| vv, - .err => null, - }; - const position = switch (input.tryParse(struct { - fn parse(input_: *css.Parser) Result(Position) { - if (input_.expectIdentMatching("at").asErr()) |e| return .{ .err = e }; - return Position.parse(input_); - } - }.parse, .{})) { - .result => |v| v, - .err => null, - }; - - if (shape != null or position != null) { - if (input.expectComma().asErr()) |e| return .{ .err = e }; - } - - const items = switch (parseItems(LengthPercentage, input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ - .result = RadialGradient{ - // todo_stuff.depth - .shape = shape orelse EndingShape.default(), - // todo_stuff.depth - .position = position orelse Position.center(), - .items = items, - .vendor_prefix = vendor_prefix, - }, - }; - } - - pub fn toCss(this: *const RadialGradient, dest: *Printer) PrintErr!void { - if (!std.meta.eql(this.shape, EndingShape.default())) { - try this.shape.toCss(dest); - if (this.position.isCenter()) { - try dest.delim(',', false); - } else { - try dest.writeChar(' '); - } - } - - if (!this.position.isCenter()) { - try dest.writeStr("at "); - try this.position.toCss(dest); - try dest.delim(',', false); - } - - try serializeItems(LengthPercentage, &this.items, dest); - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - for (this.items.items) |*item| { - if (!item.isCompatible(browsers)) return false; - } - return true; - } - - pub fn getFallback(this: *const RadialGradient, allocator: Allocator, kind: css.ColorFallbackKind) RadialGradient { - var items = bun.handleOom(ArrayList(GradientItem(LengthPercentage)).initCapacity(allocator, this.items.items.len)); - items.items.len = this.items.items.len; - for (items.items, this.items.items) |*out, *in| { - out.* = in.getFallback(allocator, kind); - } - - return RadialGradient{ - .shape = this.shape.deepClone(allocator), - .position = this.position.deepClone(allocator), - .items = items, - .vendor_prefix = this.vendor_prefix, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const RadialGradient, other: *const RadialGradient) bool { - return css.implementEql(@This(), this, other); - } -}; - -/// A CSS [`conic-gradient()`](https://www.w3.org/TR/css-images-4/#conic-gradients) or `repeating-conic-gradient()`. -pub const ConicGradient = struct { - /// The angle of the gradient. - angle: Angle, - /// The position of the gradient. - position: Position, - /// The color stops and transition hints for the gradient. - items: ArrayList(GradientItem(AnglePercentage)), - - pub fn parse(input: *css.Parser) Result(ConicGradient) { - const angle = input.tryParse(struct { - inline fn parse(i: *css.Parser) Result(Angle) { - if (i.expectIdentMatching("from").asErr()) |e| return .{ .err = e }; - // Spec allows unitless zero angles for gradients. - // https://w3c.github.io/csswg-drafts/css-images-4/#valdef-conic-gradient-angle - return Angle.parseWithUnitlessZero(i); - } - }.parse, .{}); - - const position = input.tryParse(struct { - inline fn parse(i: *css.Parser) Result(Position) { - if (i.expectIdentMatching("at").asErr()) |e| return .{ .err = e }; - return Position.parse(i); - } - }.parse, .{}); - - if (angle.isOk() or position.isOk()) { - if (input.expectComma().asErr()) |e| return .{ .err = e }; - } - - const items = switch (parseItems(AnglePercentage, input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = ConicGradient{ - .angle = angle.unwrapOr(Angle{ .deg = 0.0 }), - .position = position.unwrapOr(Position.center()), - .items = items, - } }; - } - - pub fn toCss(this: *const ConicGradient, dest: *Printer) PrintErr!void { - if (!this.angle.isZero()) { - try dest.writeStr("from "); - try this.angle.toCss(dest); - - if (this.position.isCenter()) { - try dest.delim(',', false); - } else { - try dest.writeChar(' '); - } - } - - if (!this.position.isCenter()) { - try dest.writeStr("at "); - try this.position.toCss(dest); - try dest.delim(',', false); - } - - return try serializeItems(AnglePercentage, &this.items, dest); - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - for (this.items.items) |*item| { - if (!item.isCompatible(browsers)) return false; - } - return true; - } - - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: css.ColorFallbackKind) ConicGradient { - var items = bun.handleOom(ArrayList(GradientItem(AnglePercentage)).initCapacity(allocator, this.items.items.len)); - items.items.len = this.items.items.len; - for (items.items, this.items.items) |*out, *in| { - out.* = in.getFallback(allocator, kind); - } - - return ConicGradient{ - .angle = this.angle.deepClone(allocator), - .position = this.position.deepClone(allocator), - .items = items, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const ConicGradient, other: *const ConicGradient) bool { - return css.implementEql(@This(), this, other); - } -}; - -/// A legacy `-webkit-gradient()`. -pub const WebKitGradient = union(enum) { - /// A linear `-webkit-gradient()`. - linear: struct { - /// The starting point of the gradient. - from: WebKitGradientPoint, - /// The ending point of the gradient. - to: WebKitGradientPoint, - /// The color stops in the gradient. - stops: ArrayList(WebKitColorStop), - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - /// A radial `-webkit-gradient()`. - radial: struct { - /// The starting point of the gradient. - from: WebKitGradientPoint, - /// The starting radius of the gradient. - r0: CSSNumber, - /// The ending point of the gradient. - to: WebKitGradientPoint, - /// The ending radius of the gradient. - r1: CSSNumber, - /// The color stops in the gradient. - stops: ArrayList(WebKitColorStop), - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - - pub fn parse(input: *css.Parser) Result(WebKitGradient) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "linear")) { - // todo_stuff.depth - const from = switch (WebKitGradientPoint.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const to = switch (WebKitGradientPoint.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const stops = switch (input.parseCommaSeparated(WebKitColorStop, WebKitColorStop.parse)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = WebKitGradient{ .linear = .{ - .from = from, - .to = to, - .stops = stops, - } } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "radial")) { - const from = switch (WebKitGradientPoint.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const r0 = switch (CSSNumberFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const to = switch (WebKitGradientPoint.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - const r1 = switch (CSSNumberFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectComma().asErr()) |e| return .{ .err = e }; - // todo_stuff.depth - const stops = switch (input.parseCommaSeparated(WebKitColorStop, WebKitColorStop.parse)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = WebKitGradient{ - .radial = .{ - .from = from, - .r0 = r0, - .to = to, - .r1 = r1, - .stops = stops, - }, - } }; - } else { - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - } - - pub fn toCss(this: *const WebKitGradient, dest: *Printer) PrintErr!void { - switch (this.*) { - .linear => |*linear| { - try dest.writeStr("linear"); - try dest.delim(',', false); - try linear.from.toCss(dest); - try dest.delim(',', false); - try linear.to.toCss(dest); - for (linear.stops.items) |*stop| { - try dest.delim(',', false); - try stop.toCss(dest); - } - }, - .radial => |*radial| { - try dest.writeStr("radial"); - try dest.delim(',', false); - try radial.from.toCss(dest); - try dest.delim(',', false); - try CSSNumberFns.toCss(&radial.r0, dest); - try dest.delim(',', false); - try radial.to.toCss(dest); - try dest.delim(',', false); - try CSSNumberFns.toCss(&radial.r1, dest); - for (radial.stops.items) |*stop| { - try dest.delim(',', false); - try stop.toCss(dest); - } - }, - } - } - - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: css.ColorFallbackKind) WebKitGradient { - var stops: ArrayList(WebKitColorStop) = .{}; - switch (this.*) { - .linear => |linear| { - stops = bun.handleOom(ArrayList(WebKitColorStop).initCapacity(allocator, linear.stops.items.len)); - stops.items.len = linear.stops.items.len; - for (stops.items, linear.stops.items) |*out, *in| { - out.* = in.getFallback(allocator, kind); - } - return WebKitGradient{ - .linear = .{ - .from = linear.from.deepClone(allocator), - .to = linear.to.deepClone(allocator), - .stops = stops, - }, - }; - }, - .radial => |radial| { - stops = bun.handleOom(ArrayList(WebKitColorStop).initCapacity(allocator, radial.stops.items.len)); - stops.items.len = radial.stops.items.len; - for (stops.items, radial.stops.items) |*out, *in| { - out.* = in.getFallback(allocator, kind); - } - return WebKitGradient{ - .radial = .{ - .from = radial.from.deepClone(allocator), - .r0 = radial.r0, - .to = radial.to.deepClone(allocator), - .r1 = radial.r1, - .stops = stops, - }, - }; - }, - } - } - - pub fn fromStandard(gradient: *const Gradient, allocator: Allocator) ?WebKitGradient { - switch (gradient.*) { - .linear => |*linear| { - // Convert from line direction to a from and to point, if possible. - const from: struct { f32, f32 }, const to: struct { f32, f32 } = switch (linear.direction) { - .horizontal => |horizontal| switch (horizontal) { - .left => .{ .{ 1.0, 0.0 }, .{ 0.0, 0.0 } }, - .right => .{ .{ 0.0, 0.0 }, .{ 1.0, 0.0 } }, - }, - .vertical => |vertical| switch (vertical) { - .top => .{ .{ 0.0, 1.0 }, .{ 0.0, 0.0 } }, - .bottom => .{ .{ 0.0, 0.0 }, .{ 0.0, 1.0 } }, - }, - .corner => |corner| switch (corner.horizontal) { - .left => switch (corner.vertical) { - .top => .{ .{ 1.0, 1.0 }, .{ 0.0, 0.0 } }, - .bottom => .{ .{ 1.0, 0.0 }, .{ 0.0, 1.0 } }, - }, - .right => switch (corner.vertical) { - .top => .{ .{ 0.0, 1.0 }, .{ 1.0, 0.0 } }, - .bottom => .{ .{ 0.0, 0.0 }, .{ 1.0, 1.0 } }, - }, - }, - .angle => |angle| brk: { - const degrees = angle.toDegrees(); - if (degrees == 0.0) { - break :brk .{ .{ 0.0, 1.0 }, .{ 0.0, 0.0 } }; - } else if (degrees == 90.0) { - break :brk .{ .{ 0.0, 0.0 }, .{ 1.0, 0.0 } }; - } else if (degrees == 180.0) { - break :brk .{ .{ 0.0, 0.0 }, .{ 0.0, 1.0 } }; - } else if (degrees == 270.0) { - break :brk .{ .{ 1.0, 0.0 }, .{ 0.0, 0.0 } }; - } else { - return null; - } - }, - }; - - return WebKitGradient{ - .linear = .{ - .from = .{ - .x = .{ .number = .{ .percentage = .{ .v = from[0] } } }, - .y = .{ .number = .{ .percentage = .{ .v = from[1] } } }, - }, - .to = .{ - .x = .{ .number = .{ .percentage = .{ .v = to[0] } } }, - .y = .{ .number = .{ .percentage = .{ .v = to[1] } } }, - }, - .stops = convertStopsToWebkit(allocator, &linear.items) orelse return null, - }, - }; - }, - .radial => |*radial| { - // Webkit radial gradients are always circles, not ellipses, and must be specified in pixels. - const radius = switch (radial.shape) { - .circle => |*circle| switch (circle.*) { - .radius => |r| if (r.toPx()) |px| px else return null, - else => return null, - }, - else => return null, - }; - - const x = WebKitGradientPointComponent(HorizontalPositionKeyword).fromPosition(&radial.position.x, allocator) orelse return null; - const y = WebKitGradientPointComponent(VerticalPositionKeyword).fromPosition(&radial.position.y, allocator) orelse return null; - const point = WebKitGradientPoint{ .x = x, .y = y }; - return WebKitGradient{ - .radial = .{ - .from = point.deepClone(allocator), - .r0 = 0.0, - .to = point, - .r1 = radius, - .stops = convertStopsToWebkit(allocator, &radial.items) orelse return null, - }, - }; - }, - else => return null, - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const WebKitGradient, other: *const WebKitGradient) bool { - return css.implementEql(@This(), this, other); - } -}; - -/// The direction of a CSS `linear-gradient()`. -/// -/// See [LinearGradient](LinearGradient). -pub const LineDirection = union(enum) { - /// An angle. - angle: Angle, - /// A horizontal position keyword, e.g. `left` or `right`. - horizontal: HorizontalPositionKeyword, - /// A vertical position keyword, e.g. `top` or `bottom`. - vertical: VerticalPositionKeyword, - /// A corner, e.g. `bottom left` or `top right`. - corner: struct { - /// A horizontal position keyword, e.g. `left` or `right`. - horizontal: HorizontalPositionKeyword, - /// A vertical position keyword, e.g. `top` or `bottom`. - vertical: VerticalPositionKeyword, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const LineDirection, other: *const LineDirection) bool { - return css.implementEql(@This(), this, other); - } - - pub fn parse(input: *css.Parser, is_prefixed: bool) Result(LineDirection) { - // Spec allows unitless zero angles for gradients. - // https://w3c.github.io/csswg-drafts/css-images-3/#linear-gradient-syntax - if (input.tryParse(Angle.parseWithUnitlessZero, .{}).asValue()) |angle| { - return .{ .result = LineDirection{ .angle = angle } }; - } - - if (!is_prefixed) { - if (input.expectIdentMatching("to").asErr()) |e| return .{ .err = e }; - } - - if (input.tryParse(HorizontalPositionKeyword.parse, .{}).asValue()) |x| { - if (input.tryParse(VerticalPositionKeyword.parse, .{}).asValue()) |y| { - return .{ .result = LineDirection{ .corner = .{ - .horizontal = x, - .vertical = y, - } } }; - } - return .{ .result = LineDirection{ .horizontal = x } }; - } - - const y = switch (VerticalPositionKeyword.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.tryParse(HorizontalPositionKeyword.parse, .{}).asValue()) |x| { - return .{ .result = LineDirection{ .corner = .{ - .horizontal = x, - .vertical = y, - } } }; - } - return .{ .result = LineDirection{ .vertical = y } }; - } - - pub fn toCss(this: *const LineDirection, dest: *Printer, is_prefixed: bool) PrintErr!void { - switch (this.*) { - .angle => |*angle| try angle.toCss(dest), - .horizontal => |*k| { - if (dest.minify) { - try dest.writeStr(switch (k.*) { - .left => "270deg", - .right => "90deg", - }); - } else { - if (!is_prefixed) { - try dest.writeStr("to "); - } - try k.toCss(dest); - } - }, - .vertical => |*k| { - if (dest.minify) { - try dest.writeStr(switch (k.*) { - .top => "0deg", - .bottom => "180deg", - }); - } else { - if (!is_prefixed) { - try dest.writeStr("to "); - } - try k.toCss(dest); - } - }, - .corner => |*c| { - if (!is_prefixed) { - try dest.writeStr("to "); - } - try c.vertical.toCss(dest); - try dest.writeChar(' '); - try c.horizontal.toCss(dest); - }, - } - } -}; - -/// Either a color stop or interpolation hint within a gradient. -/// -/// This type is generic, and items may be either a [LengthPercentage](super::length::LengthPercentage) -/// or [Angle](super::angle::Angle) depending on what type of gradient it is within. -pub fn GradientItem(comptime D: type) type { - return union(enum) { - /// A color stop. - color_stop: ColorStop(D), - /// A color interpolation hint. - hint: D, - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return switch (this.*) { - .color_stop => |*c| try c.toCss(dest), - .hint => |*h| try css.generic.toCss(D, h, dest), - }; - } - - pub fn eql(this: *const GradientItem(D), other: *const GradientItem(D)) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .color_stop => |*c| c.color.isCompatible(browsers), - .hint => css.compat.Feature.isCompatible(.gradient_interpolation_hints, browsers), - }; - } - - /// Returns a fallback gradient item for the given color fallback type. - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: css.ColorFallbackKind) GradientItem(D) { - return switch (this.*) { - .color_stop => |*stop| .{ - .color_stop = .{ - .color = stop.color.getFallback(allocator, kind), - .position = if (stop.position) |*p| p.deepClone(allocator) else null, - }, - }, - .hint => this.deepClone(allocator), - }; - } - - /// Returns the color fallback types needed for the given browser targets. - pub fn getNecessaryFallbacks(this: *const @This(), targets: css.targets.Targets) css.ColorFallbackKind { - return switch (this.*) { - .color_stop => |*stop| stop.color.getNecessaryFallbacks(targets), - .hint => css.ColorFallbackKind{}, - }; - } - }; -} - -/// A `radial-gradient()` [ending shape](https://www.w3.org/TR/css-images-3/#valdef-radial-gradient-ending-shape). -/// -/// See [RadialGradient](RadialGradient). -pub const EndingShape = union(enum) { - /// An ellipse. - ellipse: Ellipse, - /// A circle. - circle: Circle, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn default() EndingShape { - return .{ .ellipse = .{ .extent = .@"farthest-corner" } }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const EndingShape, other: *const EndingShape) bool { - return css.implementEql(@This(), this, other); - } -}; - -/// An x/y position within a legacy `-webkit-gradient()`. -pub const WebKitGradientPoint = struct { - /// The x-position. - x: WebKitGradientPointComponent(HorizontalPositionKeyword), - /// The y-position. - y: WebKitGradientPointComponent(VerticalPositionKeyword), - - pub fn parse(input: *css.Parser) Result(WebKitGradientPoint) { - const x = switch (WebKitGradientPointComponent(HorizontalPositionKeyword).parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const y = switch (WebKitGradientPointComponent(VerticalPositionKeyword).parse(input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .x = x, .y = y } }; - } - - pub fn toCss(this: *const WebKitGradientPoint, dest: *Printer) PrintErr!void { - try this.x.toCss(dest); - try dest.writeChar(' '); - return try this.y.toCss(dest); - } - - pub fn eql(this: *const WebKitGradientPoint, other: *const WebKitGradientPoint) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A keyword or number within a [WebKitGradientPoint](WebKitGradientPoint). -pub fn WebKitGradientPointComponent(comptime S: type) type { - return union(enum) { - /// The `center` keyword. - center, - /// A number or percentage. - number: NumberOrPercentage, - /// A side keyword. - side: S, - - const This = @This(); - - pub fn parse(input: *css.Parser) Result(This) { - if (input.tryParse(css.Parser.expectIdentMatching, .{"center"}).isOk()) { - return .{ .result = .center }; - } - - if (input.tryParse(NumberOrPercentage.parse, .{}).asValue()) |number| { - return .{ .result = .{ .number = number } }; - } - - const keyword = switch (css.generic.parse(S, input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .side = keyword } }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - switch (this.*) { - .center => { - if (dest.minify) { - try dest.writeStr("50%"); - } else { - try dest.writeStr("center"); - } - }, - .number => |*lp| { - if (lp.* == .percentage and lp.percentage.v == 0.0) { - try dest.writeChar('0'); - } else { - try lp.toCss(dest); - } - }, - .side => |*s| { - if (dest.minify) { - const lp: LengthPercentage = s.intoLengthPercentage(); - try lp.toCss(dest); - } else { - try s.toCss(dest); - } - }, - } - } - - /// Attempts to convert a standard position to a webkit gradient point. - pub fn fromPosition(this: *const css.css_values.position.PositionComponent(S), allocator: Allocator) ?WebKitGradientPointComponent(S) { - return switch (this.*) { - .center => .center, - .length => |len| .{ - .number = switch (len) { - .percentage => |p| .{ .percentage = p }, - // Webkit gradient points can only be specified in pixels. - .dimension => |*d| if (d.toPx()) |px| .{ .number = px } else return null, - else => return null, - }, - }, - .side => |s| if (s.offset != null) - return null - else - .{ - .side = s.side.deepClone(allocator), - }, - }; - } - - pub fn eql(this: *const This, other: *const This) bool { - return css.implementEql(@This(), this, other); - } - }; -} - -/// A color stop within a legacy `-webkit-gradient()`. -pub const WebKitColorStop = struct { - /// The color of the color stop. - color: CssColor, - /// The position of the color stop. - position: CSSNumber, - - pub fn parse(input: *css.Parser) Result(WebKitColorStop) { - const location = input.currentSourceLocation(); - const function = switch (input.expectFunction()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const Closure = struct { loc: css.SourceLocation, function: []const u8 }; - return input.parseNestedBlock( - WebKitColorStop, - Closure{ .loc = location, .function = function }, - struct { - fn parse( - closure: Closure, - i: *css.Parser, - ) Result(WebKitColorStop) { - // todo_stuff.match_ignore_ascii_case - const position: f32 = if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "color-stop")) position: { - const p: NumberOrPercentage = switch (@call(.auto, @field(NumberOrPercentage, "parse"), .{i})) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (i.expectComma().asErr()) |e| return .{ .err = e }; - break :position p.intoF32(); - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "from")) position: { - break :position 0.0; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(closure.function, "to")) position: { - break :position 1.0; - } else { - return .{ .err = closure.loc.newUnexpectedTokenError(.{ .ident = closure.function }) }; - }; - const color = switch (CssColor.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = WebKitColorStop{ .color = color, .position = position } }; - } - }.parse, - ); - } - - pub fn toCss(this: *const WebKitColorStop, dest: *Printer) PrintErr!void { - if (this.position == 0.0) { - try dest.writeStr("from("); - try this.color.toCss(dest); - } else if (this.position == 1.0) { - try dest.writeStr("to("); - try this.color.toCss(dest); - } else { - try dest.writeStr("color-stop("); - try css.generic.toCss(CSSNumber, &this.position, dest); - try dest.delim(',', false); - try this.color.toCss(dest); - } - try dest.writeChar(')'); - } - - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: css.ColorFallbackKind) WebKitColorStop { - return WebKitColorStop{ - .color = this.color.getFallback(allocator, kind), - .position = this.position, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const WebKitColorStop, other: *const WebKitColorStop) bool { - return css.implementEql(WebKitColorStop, this, other); - } -}; - -/// A [``](https://www.w3.org/TR/css-images-4/#color-stop-syntax) within a gradient. -/// -/// This type is generic, and may be either a [LengthPercentage](super::length::LengthPercentage) -/// or [Angle](super::angle::Angle) depending on what type of gradient it is within. -pub fn ColorStop(comptime D: type) type { - return struct { - /// The color of the color stop. - color: CssColor, - /// The position of the color stop. - position: ?D, - - const This = @This(); - - pub fn parse(input: *css.Parser) Result(ColorStop(D)) { - const color = switch (CssColor.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const position = switch (input.tryParse(css.generic.parseFor(D), .{})) { - .result => |v| v, - .err => null, - }; - return .{ .result = .{ .color = color, .position = position } }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - try this.color.toCss(dest); - if (this.position) |*position| { - try dest.writeChar(' '); - try css.generic.toCss(D, position, dest); - } - return; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const This, other: *const This) bool { - return css.implementEql(@This(), this, other); - } - }; -} - -/// An ellipse ending shape for a `radial-gradient()`. -/// -/// See [RadialGradient](RadialGradient). -pub const Ellipse = union(enum) { - /// An ellipse with a specified horizontal and vertical radius. - size: struct { - /// The x-radius of the ellipse. - x: LengthPercentage, - /// The y-radius of the ellipse. - y: LengthPercentage, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - /// A shape extent keyword. - extent: ShapeExtent, - - pub fn parse(input: *css.Parser) Result(Ellipse) { - if (input.tryParse(ShapeExtent.parse, .{}).asValue()) |extent| { - // The `ellipse` keyword is optional, but only if the `circle` keyword is not present. - // If it is, then we'll re-parse as a circle. - if (input.tryParse(css.Parser.expectIdentMatching, .{"circle"}).isOk()) { - return .{ .err = input.newErrorForNextToken() }; - } - _ = input.tryParse(css.Parser.expectIdentMatching, .{"ellipse"}); - return .{ .result = Ellipse{ .extent = extent } }; - } - - if (input.tryParse(LengthPercentage.parse, .{}).asValue()) |x| { - const y = switch (LengthPercentage.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - // The `ellipse` keyword is optional if there are two lengths. - _ = input.tryParse(css.Parser.expectIdentMatching, .{"ellipse"}); - return .{ .result = Ellipse{ .size = .{ .x = x, .y = y } } }; - } - - if (input.tryParse(css.Parser.expectIdentMatching, .{"ellipse"}).isOk()) { - if (input.tryParse(ShapeExtent.parse, .{}).asValue()) |extent| { - return .{ .result = Ellipse{ .extent = extent } }; - } - - if (input.tryParse(LengthPercentage.parse, .{}).asValue()) |x| { - const y = switch (LengthPercentage.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = Ellipse{ .size = .{ .x = x, .y = y } } }; - } - - // Assume `farthest-corner` if only the `ellipse` keyword is present. - return .{ .result = Ellipse{ .extent = .@"farthest-corner" } }; - } - - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn toCss(this: *const Ellipse, dest: *Printer) PrintErr!void { - // The `ellipse` keyword is optional, so we don't emit it. - return switch (this.*) { - .size => |*s| { - try s.x.toCss(dest); - try dest.writeChar(' '); - return try s.y.toCss(dest); - }, - .extent => |*e| try e.toCss(dest), - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const Ellipse, other: *const Ellipse) bool { - return css.implementEql(@This(), this, other); - } -}; - -pub const ShapeExtent = enum { - /// The closest side of the box to the gradient's center. - @"closest-side", - /// The farthest side of the box from the gradient's center. - @"farthest-side", - /// The closest corner of the box to the gradient's center. - @"closest-corner", - /// The farthest corner of the box from the gradient's center. - @"farthest-corner", - - pub fn eql(this: *const ShapeExtent, other: *const ShapeExtent) bool { - return this.* == other.*; - } - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } -}; - -/// A circle ending shape for a `radial-gradient()`. -/// -/// See [RadialGradient](RadialGradient). -pub const Circle = union(enum) { - /// A circle with a specified radius. - radius: Length, - /// A shape extent keyword. - extent: ShapeExtent, - - pub fn parse(input: *css.Parser) Result(Circle) { - if (input.tryParse(ShapeExtent.parse, .{}).asValue()) |extent| { - // The `circle` keyword is required. If it's not there, then it's an ellipse. - if (input.expectIdentMatching("circle").asErr()) |e| return .{ .err = e }; - return .{ .result = Circle{ .extent = extent } }; - } - - if (input.tryParse(Length.parse, .{}).asValue()) |length| { - // The `circle` keyword is optional if there is only a single length. - // We are assuming here that Ellipse.parse ran first. - _ = input.tryParse(css.Parser.expectIdentMatching, .{"circle"}); - return .{ .result = Circle{ .radius = length } }; - } - - if (input.tryParse(css.Parser.expectIdentMatching, .{"circle"}).isOk()) { - if (input.tryParse(ShapeExtent.parse, .{}).asValue()) |extent| { - return .{ .result = Circle{ .extent = extent } }; - } - - if (input.tryParse(Length.parse, .{}).asValue()) |length| { - return .{ .result = Circle{ .radius = length } }; - } - - // If only the `circle` keyword was given, default to `farthest-corner`. - return .{ .result = Circle{ .extent = .@"farthest-corner" } }; - } - - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn toCss(this: *const Circle, dest: *Printer) PrintErr!void { - return switch (this.*) { - .radius => |r| try r.toCss(dest), - .extent => |extent| { - try dest.writeStr("circle"); - if (extent != .@"farthest-corner") { - try dest.writeChar(' '); - try extent.toCss(dest); - } - }, - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const Circle, other: *const Circle) bool { - return css.implementEql(@This(), this, other); - } -}; - -pub fn parseItems(comptime D: type, input: *css.Parser) Result(ArrayList(GradientItem(D))) { - var items = ArrayList(GradientItem(D)){}; - var seen_stop = false; - - while (true) { - const Closure = struct { items: *ArrayList(GradientItem(D)), seen_stop: *bool }; - if (input.parseUntilBefore( - css.Delimiters{ .comma = true }, - void, - Closure{ .items = &items, .seen_stop = &seen_stop }, - struct { - fn parse(closure: Closure, i: *css.Parser) Result(void) { - if (closure.seen_stop.*) { - if (i.tryParse(comptime css.generic.parseFor(D), .{}).asValue()) |hint| { - closure.seen_stop.* = false; - bun.handleOom(closure.items.append(i.allocator(), .{ .hint = hint })); - return .success; - } - } - - const stop = switch (ColorStop(D).parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - if (i.tryParse(comptime css.generic.parseFor(D), .{}).asValue()) |position| { - const color = stop.color.deepClone(i.allocator()); - bun.handleOom(closure.items.append(i.allocator(), .{ .color_stop = stop })); - closure.items.append(i.allocator(), .{ .color_stop = .{ - .color = color, - .position = position, - } }) catch |err| bun.handleOom(err); - } else { - bun.handleOom(closure.items.append(i.allocator(), .{ .color_stop = stop })); - } - - closure.seen_stop.* = true; - return .success; - } - }.parse, - ).asErr()) |e| return .{ .err = e }; - - if (input.next().asValue()) |tok| { - if (tok.* == .comma) continue; - bun.unreachablePanic("expected a comma after parsing a gradient", .{}); - } else { - break; - } - } - - return .{ .result = items }; -} - -pub fn serializeItems( - comptime D: type, - items: *const ArrayList(GradientItem(D)), - dest: *Printer, -) PrintErr!void { - var first = true; - var last: ?*const GradientItem(D) = null; - for (items.items) |*item| { - // Skip useless hints - if (item.* == .hint and item.hint == .percentage and item.hint.percentage.v == 0.5) { - continue; - } - - // Use double position stop if the last stop is the same color and all targets support it. - if (last) |prev| { - if (!dest.targets.shouldCompile(.double_position_gradients, .{ .double_position_gradients = true })) { - if (prev.* == .color_stop and prev.color_stop.position != null and - item.* == .color_stop and item.color_stop.position != null and - prev.color_stop.color.eql(&item.color_stop.color)) - { - try dest.writeChar(' '); - try item.color_stop.position.?.toCss(dest); - last = null; - continue; - } - } - } - - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - try item.toCss(dest); - last = item; - } -} - -pub fn convertStopsToWebkit(allocator: Allocator, items: *const ArrayList(GradientItem(LengthPercentage))) ?ArrayList(WebKitColorStop) { - var stops: ArrayList(WebKitColorStop) = bun.handleOom(ArrayList(WebKitColorStop).initCapacity(allocator, items.items.len)); - for (items.items, 0..) |*item, i| { - switch (item.*) { - .color_stop => |*stop| { - // webkit stops must always be percentage based, not length based. - const position: f32 = if (stop.position) |pos| brk: { - break :brk switch (pos) { - .percentage => |percentage| percentage.v, - else => { - stops.deinit(allocator); - return null; - }, - }; - } else if (i == 0) brk: { - break :brk 0.0; - } else if (i == items.items.len - 1) brk: { - break :brk 1.0; - } else { - stops.deinit(allocator); - return null; - }; - - stops.append(allocator, .{ - .color = stop.color.deepClone(allocator), - .position = position, - }) catch return null; - }, - else => return null, - } - } - - return stops; -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/values/ident.zig b/src/css/values/ident.zig deleted file mode 100644 index d960105a1e8b..000000000000 --- a/src/css/values/ident.zig +++ /dev/null @@ -1,324 +0,0 @@ -pub const css = @import("../css_parser.zig"); -pub const Result = css.Result; -pub const Printer = css.Printer; -pub const PrintErr = css.PrintErr; - -pub const Specifier = css.css_properties.css_modules.Specifier; - -/// A CSS [``](https://www.w3.org/TR/css-values-4/#dashed-idents) reference. -/// -/// Dashed idents are used in cases where an identifier can be either author defined _or_ CSS-defined. -/// Author defined idents must start with two dash characters ("--") or parsing will fail. -/// -/// In CSS modules, when the `dashed_idents` option is enabled, the identifier may be followed by the -/// `from` keyword and an argument indicating where the referenced identifier is declared (e.g. a filename). -pub const DashedIdentReference = struct { - /// The referenced identifier. - ident: DashedIdent, - /// CSS modules extension: the filename where the variable is defined. - /// Only enabled when the CSS modules `dashed_idents` option is turned on. - from: ?Specifier, - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub fn parseWithOptions(input: *css.Parser, options: *const css.ParserOptions) Result(DashedIdentReference) { - const ident = switch (DashedIdentFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const from = if (options.css_modules != null and options.css_modules.?.dashed_idents) from: { - if (input.tryParse(css.Parser.expectIdentMatching, .{"from"}).isOk()) break :from switch (Specifier.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - break :from null; - } else null; - - return .{ .result = DashedIdentReference{ .ident = ident, .from = from } }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - if (dest.css_module) |*css_module| { - if (css_module.config.dashed_idents) { - if (try css_module.referenceDashed(dest, this.ident.v, &this.from, dest.loc.source_index)) |name| { - try dest.writeStr("--"); - css.serializer.serializeName(name, dest) catch return dest.addFmtError(); - return; - } - } - } - - return dest.writeDashedIdent(&this.ident, false); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -pub const DashedIdentFns = DashedIdent; -/// A CSS [``](https://www.w3.org/TR/css-values-4/#dashed-idents) declaration. -/// -/// Dashed idents are used in cases where an identifier can be either author defined _or_ CSS-defined. -/// Author defined idents must start with two dash characters ("--") or parsing will fail. -pub const DashedIdent = struct { - v: []const u8, - - pub fn HashMap(comptime V: type) type { - return std.ArrayHashMapUnmanaged( - DashedIdent, - V, - struct { - pub fn hash(_: @This(), s: DashedIdent) u32 { - return std.array_hash_map.hashString(s.v); - } - pub fn eql(_: @This(), a: DashedIdent, b: DashedIdent, _: usize) bool { - return bun.strings.eql(a, b); - } - }, - false, - ); - } - - pub fn parse(input: *css.Parser) Result(DashedIdent) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (!bun.strings.startsWith(ident, "--")) return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - - return .{ .result = .{ .v = ident } }; - } - - const This = @This(); - - pub fn toCss(this: *const DashedIdent, dest: *Printer) PrintErr!void { - return dest.writeDashedIdent(this, true); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// A CSS [``](https://www.w3.org/TR/css-values-4/#css-css-identifier). -pub const IdentFns = Ident; -pub const Ident = struct { - v: []const u8, - - pub fn parse(input: *css.Parser) Result(Ident) { - const ident = switch (input.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .v = ident } }; - } - - pub fn toCss(this: *const Ident, dest: *Printer) PrintErr!void { - return css.serializer.serializeIdentifier(this.v, dest) catch return dest.addFmtError(); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// Encodes an `Ident` or the bundler's `Ref` into 16 bytes. -/// -/// It uses the top bit of the pointer to denote whether it's an ident or a ref -/// -/// If it's an `Ident`, then `__ref_bit == false` and `__len` is the length of the slice. -/// -/// If it's `Ref`, then `__ref_bit == true` and `__len` is the bit pattern of the `Ref`. -/// -/// In debug mode, if it is a `Ref` we will also set the `__ptrbits` to point to the original -/// []const u8 so we can debug the string. This should be fine since we use arena -pub const IdentOrRef = packed struct(u128) { - __ptrbits: u63 = 0, - __ref_bit: bool = false, - __len: u64 = 0, - - const Tag = enum { - ident, - ref, - }; - - const DebugIdent = if (bun.Environment.isDebug) struct { []const u8, Allocator } else void; - - pub fn debugIdent(this: @This()) []const u8 { - if (comptime !bun.Environment.isDebug) { - @compileError("debugIdent is only available in debug mode"); - } - - if (this.__ref_bit) { - const ptr: *const []const u8 = @ptrFromInt(@as(usize, @intCast(this.__ptrbits))); - return ptr.*; - } - - return this.asIdent().?.v; - } - - pub fn format(this: @This(), writer: *std.Io.Writer) !void { - if (this.__ref_bit) { - const ref = this.asRef().?; - return writer.print("Ref({f})", .{ref}); - } - return writer.print("Ident({s})", .{this.asIdent().?.v}); - } - - pub fn fromIdent(ident: Ident) @This() { - return @This(){ - .__ptrbits = @intCast(@intFromPtr(ident.v.ptr)), - .__len = ident.v.len, - .__ref_bit = false, - }; - } - - pub fn fromRef(ref: bun.bundle_v2.Ref, debug_ident: DebugIdent) @This() { - var this = @This(){ - .__len = @bitCast(ref), - .__ref_bit = true, - }; - - if (comptime bun.Environment.isDebug) { - const heap_ptr: *[]const u8 = bun.handleOom(debug_ident[1].create([]const u8)); - heap_ptr.* = debug_ident[0]; - this.__ptrbits = @intCast(@intFromPtr(heap_ptr)); - } - - return this; - } - - pub inline fn isIdent(this: @This()) bool { - return !this.__ref_bit; - } - - pub inline fn isRef(this: @This()) bool { - return this.__ref_bit; - } - - pub inline fn asIdent(this: @This()) ?Ident { - if (!this.__ref_bit) { - const ptr: [*]const u8 = @ptrFromInt(@as(usize, @intCast(this.__ptrbits))); - return Ident{ .v = ptr[0..this.__len] }; - } - return null; - } - - pub inline fn asRef(this: @This()) ?bun.bundle_v2.Ref { - if (this.__ref_bit) { - const out: bun.bundle_v2.Ref = @bitCast(this.__len); - return out; - } - return null; - } - - pub fn asStr(this: @This(), map: *const bun.ast.Symbol.Map, local_names: ?*const css.LocalsResultsMap) ?[]const u8 { - if (this.isIdent()) return this.asIdent().?.v; - const ref = this.asRef().?; - const final_ref = map.follow(ref); - return local_names.?.get(final_ref); - } - - pub fn asOriginalString(this: @This(), symbols: *const Symbol.List) []const u8 { - if (this.isIdent()) return this.asIdent().?.v; - const ref = this.asRef().?; - return symbols.at(ref.inner_index).original_name; - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - if (this.isIdent()) { - hasher.update(this.asIdent().?.v); - } else { - const slice: [*]const u64 = @ptrCast(this); - const slice_u8: [*]align(8) const u8 = @ptrCast(@alignCast(slice)); - hasher.update(slice_u8[0..2]); - } - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - if (this.isIdent() and other.isIdent()) { - return bun.strings.eql(this.asIdent().?.v, other.asIdent().?.v); - } else if (this.isRef() and other.isRef()) { - const a = this.asRef().?; - const b = other.asRef().?; - return a.eql(b); - } - return false; - } - - pub fn deepClone(this: *const @This(), _: std.mem.Allocator) @This() { - return this.*; - } -}; - -pub const CustomIdentFns = CustomIdent; -pub const CustomIdent = struct { - v: []const u8, - - pub fn parse(input: *css.Parser) Result(CustomIdent) { - const location = input.currentSourceLocation(); - const ident = switch (input.expectIdent()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - // css.todo_stuff.match_ignore_ascii_case - const valid = !(bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "initial") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "inherit") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "unset") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "default") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "revert") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(ident, "revert-layer")); - - if (!valid) return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - return .{ .result = .{ .v = ident } }; - } - - const This = @This(); - - pub fn toCss(this: *const CustomIdent, dest: *Printer) PrintErr!void { - return @This().toCssWithOptions(this, dest, true); - } - - /// Write the custom ident to CSS. - pub fn toCssWithOptions( - this: *const CustomIdent, - dest: *Printer, - enabled_css_modules: bool, - ) PrintErr!void { - const css_module_custom_idents_enabled = enabled_css_modules and - if (dest.css_module) |*css_module| - css_module.config.custom_idents - else - false; - return dest.writeIdent(this.v, css_module_custom_idents_enabled); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } -}; - -/// A list of CSS [``](https://www.w3.org/TR/css-values-4/#custom-idents) values. -pub const CustomIdentList = css.SmallList(CustomIdent, 1); - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; -const Symbol = bun.ast.Symbol; diff --git a/src/css/values/image.zig b/src/css/values/image.zig deleted file mode 100644 index 924134b11560..000000000000 --- a/src/css/values/image.zig +++ /dev/null @@ -1,408 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Url = css.css_values.url.Url; -const Gradient = css.css_values.gradient.Gradient; -const Resolution = css.css_values.resolution.Resolution; -const VendorPrefix = css.VendorPrefix; -const UrlDependency = css.dependencies.UrlDependency; - -/// A CSS [``](https://www.w3.org/TR/css-images-3/#image-values) value. -pub const Image = union(enum) { - /// The `none` keyword. - none, - /// A `url()`. - url: Url, - /// A gradient. - gradient: *Gradient, - /// An `image-set()`. - image_set: ImageSet, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn deinit(_: *@This(), _: std.mem.Allocator) void { - // TODO: implement this - // Right now not implementing this. - // It is not a bug to implement this since all memory allocated in CSS parser is allocated into arena. - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .gradient => |g| switch (g.*) { - .linear => |linear| css.Feature.isCompatible(.linear_gradient, browsers) and linear.isCompatible(browsers), - .repeating_linear => |repeating_linear| css.Feature.isCompatible(.repeating_linear_gradient, browsers) and repeating_linear.isCompatible(browsers), - .radial => |radial| css.Feature.isCompatible(.radial_gradient, browsers) and radial.isCompatible(browsers), - .repeating_radial => |repeating_radial| css.Feature.isCompatible(.repeating_radial_gradient, browsers) and repeating_radial.isCompatible(browsers), - .conic => |conic| css.Feature.isCompatible(.conic_gradient, browsers) and conic.isCompatible(browsers), - .repeating_conic => |repeating_conic| css.Feature.isCompatible(.repeating_conic_gradient, browsers) and repeating_conic.isCompatible(browsers), - .@"webkit-gradient" => css.prefixes.Feature.isWebkitGradient(browsers), - }, - .image_set => |image_set| image_set.isCompatible(browsers), - .url, .none => true, - }; - } - - pub fn getPrefixed(this: *const @This(), allocator: Allocator, prefix: css.VendorPrefix) Image { - return switch (this.*) { - .gradient => |grad| .{ .gradient = bun.create(allocator, Gradient, grad.getPrefixed(allocator, prefix)) }, - .image_set => |image_set| .{ .image_set = image_set.getPrefixed(allocator, prefix) }, - else => this.deepClone(allocator), - }; - } - - pub fn getNecessaryPrefixes(this: *const @This(), targets: css.targets.Targets) css.VendorPrefix { - return switch (this.*) { - .gradient => |grad| grad.getNecessaryPrefixes(targets), - .image_set => |*image_set| image_set.getNecessaryPrefixes(targets), - else => css.VendorPrefix{ .none = true }, - }; - } - - pub fn hasVendorPrefix(this: *const @This()) bool { - const prefix = this.getVendorPrefix(); - return !prefix.isEmpty() and prefix != VendorPrefix{ .none = true }; - } - - /// Returns the vendor prefix used in the image value. - pub fn getVendorPrefix(this: *const @This()) VendorPrefix { - return switch (this.*) { - .gradient => |a| a.getVendorPrefix(), - .image_set => |a| a.getVendorPrefix(), - else => .{}, - }; - } - - /// Needed to satisfy ImageFallback interface - pub fn getImage(this: *const @This()) *const Image { - return this; - } - - /// Needed to satisfy ImageFallback interface - pub fn withImage(_: *const @This(), _: Allocator, image: Image) @This() { - return image; - } - - pub fn default() Image { - return .none; - } - - pub inline fn eql(this: *const Image, other: *const Image) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - /// Returns a legacy `-webkit-gradient()` value for the image. - /// - /// May return an error in case the gradient cannot be converted. - pub fn getLegacyWebkit(this: *const @This(), allocator: Allocator) ?Image { - return switch (this.*) { - .gradient => |gradient| Image{ .gradient = bun.create(allocator, Gradient, gradient.getLegacyWebkit(allocator) orelse return null) }, - else => this.deepClone(allocator), - }; - } - - pub fn getFallbacks(this: *@This(), allocator: Allocator, targets: css.targets.Targets) css.SmallList(Image, 6) { - const ColorFallbackKind = css.ColorFallbackKind; - // Determine which prefixes and color fallbacks are needed. - const prefixes = this.getNecessaryPrefixes(targets); - const fallbacks = this.getNecessaryFallbacks(targets); - var res = css.SmallList(Image, 6){}; - - // Get RGB fallbacks if needed. - const rgb = if (fallbacks.rgb) - this.getFallback(allocator, ColorFallbackKind.RGB) - else - null; - - // Prefixed properties only support RGB. - const prefix_image = if (rgb) |r| &r else this; - - // Legacy -webkit-gradient() - if (prefixes.webkit and - if (targets.browsers) |browsers| css.prefixes.Feature.isWebkitGradient(browsers) else false and - prefix_image.* == .gradient) - { - if (prefix_image.getLegacyWebkit(allocator)) |legacy| { - res.append(allocator, legacy); - } - } - - // Standard syntax, with prefixes. - if (prefixes.webkit) { - res.append(allocator, prefix_image.getPrefixed(allocator, css.VendorPrefix.WEBKIT)); - } - - if (prefixes.moz) { - res.append(allocator, prefix_image.getPrefixed(allocator, css.VendorPrefix.MOZ)); - } - - if (prefixes.o) { - res.append(allocator, prefix_image.getPrefixed(allocator, css.VendorPrefix.O)); - } - - if (prefixes.none) { - // Unprefixed, rgb fallback. - if (rgb) |r| { - res.append(allocator, r); - } - - // P3 fallback. - if (fallbacks.p3) { - res.append(allocator, this.getFallback(allocator, ColorFallbackKind.P3)); - } - - // Convert original to lab if needed (e.g. if oklab is not supported but lab is). - if (fallbacks.lab) { - this.* = this.getFallback(allocator, ColorFallbackKind.LAB); - } - } else if (res.pop()) |last| { - // Prefixed property with no unprefixed version. - // Replace self with the last prefixed version so that it doesn't - // get duplicated when the caller pushes the original value. - this.* = last; - } - - return res; - } - - pub fn getFallback(this: *const @This(), allocator: Allocator, kind: css.ColorFallbackKind) Image { - return switch (this.*) { - .gradient => |grad| .{ .gradient = bun.create(allocator, Gradient, grad.getFallback(allocator, kind)) }, - else => this.deepClone(allocator), - }; - } - - pub fn getNecessaryFallbacks(this: *const @This(), targets: css.targets.Targets) css.ColorFallbackKind { - return switch (this.*) { - .gradient => |grad| grad.getNecessaryFallbacks(targets), - else => css.ColorFallbackKind{}, - }; - } - - // pub fn parse(input: *css.Parser) Result(Image) { - // _ = input; // autofix - // @panic(css.todo_stuff.depth); - // } - - // pub fn toCss(this: *const Image, dest: *css.Printer) css.PrintErr!void { - // _ = this; // autofix - // _ = dest; // autofix - // @panic(css.todo_stuff.depth); - // } -}; - -/// A CSS [`image-set()`](https://drafts.csswg.org/css-images-4/#image-set-notation) value. -/// -/// `image-set()` allows the user agent to choose between multiple versions of an image to -/// display the most appropriate resolution or file type that it supports. -pub const ImageSet = struct { - /// The image options to choose from. - options: ArrayList(ImageSetOption), - - /// The vendor prefix for the `image-set()` function. - vendor_prefix: VendorPrefix, - - pub fn parse(input: *css.Parser) Result(ImageSet) { - const location = input.currentSourceLocation(); - const f = switch (input.expectFunction()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const vendor_prefix = vendor_prefix: { - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("image-set", f)) { - break :vendor_prefix VendorPrefix{ .none = true }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength("-webkit-image-set", f)) { - break :vendor_prefix VendorPrefix{ .webkit = true }; - } else return .{ .err = location.newUnexpectedTokenError(.{ .ident = f }) }; - }; - - const Fn = struct { - pub fn parseNestedBlockFn(_: void, i: *css.Parser) Result(ArrayList(ImageSetOption)) { - return i.parseCommaSeparated(ImageSetOption, ImageSetOption.parse); - } - }; - - const options = switch (input.parseNestedBlock(ArrayList(ImageSetOption), {}, Fn.parseNestedBlockFn)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = ImageSet{ - .options = options, - .vendor_prefix = vendor_prefix, - } }; - } - - pub fn toCss(this: *const ImageSet, dest: *css.Printer) PrintErr!void { - try this.vendor_prefix.toCss(dest); - try dest.writeStr("image-set("); - var first = true; - for (this.options.items) |*option| { - if (first) { - first = false; - } else { - try dest.delim(',', false); - } - try option.toCss(dest, this.vendor_prefix != VendorPrefix{ .none = true }); - } - return dest.writeChar(')'); - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return css.Feature.isCompatible(.image_set, browsers) and - for (this.options.items) |opt| { - if (!opt.image.isCompatible(browsers)) break false; - } else true; - } - - /// Returns the `image-set()` value with the given vendor prefix. - pub fn getPrefixed(this: *const @This(), allocator: Allocator, prefix: css.VendorPrefix) ImageSet { - return ImageSet{ - .options = css.deepClone(ImageSetOption, allocator, &this.options), - .vendor_prefix = prefix, - }; - } - - pub fn eql(this: *const ImageSet, other: *const ImageSet) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn getVendorPrefix(this: *const @This()) VendorPrefix { - return this.vendor_prefix; - } - - /// Returns the vendor prefixes needed for the given browser targets. - pub fn getNecessaryPrefixes(this: *const @This(), targets: css.targets.Targets) css.VendorPrefix { - return targets.prefixes(this.vendor_prefix, css.prefixes.Feature.image_set); - } -}; - -/// An image option within the `image-set()` function. See [ImageSet](ImageSet). -pub const ImageSetOption = struct { - /// The image for this option. - image: Image, - /// The resolution of the image. - resolution: Resolution, - /// The mime type of the image. - file_type: ?[]const u8, - - pub fn parse(input: *css.Parser) Result(ImageSetOption) { - const start_position = input.input.tokenizer.getPosition(); - const loc = input.currentSourceLocation(); - const image = if (input.tryParse(css.Parser.expectUrlOrString, .{}).asValue()) |url| brk: { - const record_idx = switch (input.addImportRecord( - url, - start_position, - .url, - )) { - .result => |idx| idx, - .err => |e| return .{ .err = e }, - }; - break :brk Image{ .url = Url{ - .import_record_idx = record_idx, - .loc = css.dependencies.Location.fromSourceLocation(loc), - } }; - } else switch (@call(.auto, @field(Image, "parse"), .{input})) { // For some reason, `Image.parse` makes zls crash, using this syntax until that's fixed - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - const resolution: Resolution, const file_type: ?[]const u8 = if (input.tryParse(Resolution.parse, .{}).asValue()) |res| brk: { - const file_type = input.tryParse(parseFileType, .{}).asValue(); - break :brk .{ res, file_type }; - } else brk: { - const file_type = input.tryParse(parseFileType, .{}).asValue(); - const resolution = input.tryParse(Resolution.parse, .{}).unwrapOr(Resolution{ .dppx = 1.0 }); - break :brk .{ resolution, file_type }; - }; - - return .{ .result = ImageSetOption{ - .image = image, - .resolution = resolution, - .file_type = if (file_type) |x| x else null, - } }; - } - - pub fn toCss( - this: *const ImageSetOption, - dest: *css.Printer, - is_prefixed: bool, - ) PrintErr!void { - if (this.image == .url and !is_prefixed) { - const _dep: ?UrlDependency = if (dest.dependencies != null) - UrlDependency.new(dest.allocator, &this.image.url, dest.filename(), try dest.getImportRecords()) - else - null; - - if (_dep) |dep| { - css.serializer.serializeString(dep.placeholder, dest) catch return dest.addFmtError(); - if (dest.dependencies) |*dependencies| { - dependencies.append( - dest.allocator, - .{ .url = dep }, - ) catch |err| bun.handleOom(err); - } - } else { - css.serializer.serializeString(try dest.getImportRecordUrl(this.image.url.import_record_idx), dest) catch return dest.addFmtError(); - } - } else { - try this.image.toCss(dest); - } - - // TODO: Throwing an error when `self.resolution = Resolution::Dppx(0.0)` - // TODO: -webkit-image-set() does not support ` | | - // | | ` and `type()`. - try dest.writeChar(' '); - - // Safari only supports the x resolution unit in image-set(). - // In other places, x was added as an alias later. - // Temporarily ignore the targets while printing here. - const targets = targets: { - const targets = dest.targets; - dest.targets = .{}; - break :targets targets; - }; - try this.resolution.toCss(dest); - dest.targets = targets; - - if (this.file_type) |file_type| { - try dest.writeStr(" type("); - css.serializer.serializeString(file_type, dest) catch return dest.addFmtError(); - try dest.writeChar(')'); - } - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(lhs: *const ImageSetOption, rhs: *const ImageSetOption) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -fn parseFileType(input: *css.Parser) Result([]const u8) { - if (input.expectFunctionMatching("type").asErr()) |e| return .{ .err = e }; - const Fn = struct { - pub fn parseNestedBlockFn(_: void, i: *css.Parser) Result([]const u8) { - return i.expectString(); - } - }; - return input.parseNestedBlock([]const u8, {}, Fn.parseNestedBlockFn); -} - -const bun = @import("bun"); - -const std = @import("std"); -const ArrayList = std.ArrayListUnmanaged; -const Allocator = std.mem.Allocator; diff --git a/src/css/values/length.zig b/src/css/values/length.zig deleted file mode 100644 index 1274199bf39c..000000000000 --- a/src/css/values/length.zig +++ /dev/null @@ -1,797 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumber = css.css_values.number.CSSNumber; -const Calc = css.css_values.calc.Calc; -const MathFunction = css.css_values.calc.MathFunction; -const DimensionPercentage = css.css_values.percentage.DimensionPercentage; - -/// Either a [``](https://www.w3.org/TR/css-values-4/#lengths) or a [``](https://www.w3.org/TR/css-values-4/#numbers). -pub const LengthOrNumber = union(enum) { - /// A number. - number: CSSNumber, - /// A length. - length: Length, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn deinit(this: *const LengthOrNumber, allocator: std.mem.Allocator) void { - switch (this.*) { - .number => {}, - .length => |*l| l.deinit(allocator), - } - } - - pub fn default() LengthOrNumber { - return .{ .number = 0.0 }; - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .length => |*l| l.isCompatible(browsers), - .number => true, - }; - } -}; - -pub const LengthPercentage = DimensionPercentage(LengthValue); -/// Either a [``](https://www.w3.org/TR/css-values-4/#typedef-length-percentage), or the `auto` keyword. -pub const LengthPercentageOrAuto = union(enum) { - /// The `auto` keyword. - auto, - /// A [``](https://www.w3.org/TR/css-values-4/#typedef-length-percentage). - length: LengthPercentage, - - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .length => this.length.isCompatible(browsers), - else => true, - }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } - - pub inline fn deepClone(this: *const @This(), allocator: Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -const PX_PER_IN: f32 = 96.0; -const PX_PER_CM: f32 = PX_PER_IN / 2.54; -const PX_PER_MM: f32 = PX_PER_CM / 10.0; -const PX_PER_Q: f32 = PX_PER_CM / 40.0; -const PX_PER_PT: f32 = PX_PER_IN / 72.0; -const PX_PER_PC: f32 = PX_PER_IN / 6.0; - -pub const LengthValue = union(enum) { - // https://www.w3.org/TR/css-values-4/#absolute-lengths - /// A length in pixels. - px: CSSNumber, - /// A length in inches. 1in = 96px. - in: CSSNumber, - /// A length in centimeters. 1cm = 96px / 2.54. - cm: CSSNumber, - /// A length in millimeters. 1mm = 1/10th of 1cm. - mm: CSSNumber, - /// A length in quarter-millimeters. 1Q = 1/40th of 1cm. - q: CSSNumber, - /// A length in points. 1pt = 1/72nd of 1in. - pt: CSSNumber, - /// A length in picas. 1pc = 1/6th of 1in. - pc: CSSNumber, - - // https://www.w3.org/TR/css-values-4/#font-relative-lengths - /// A length in the `em` unit. An `em` is equal to the computed value of the - /// font-size property of the element on which it is used. - em: CSSNumber, - /// A length in the `rem` unit. A `rem` is equal to the computed value of the - /// `em` unit on the root element. - rem: CSSNumber, - /// A length in `ex` unit. An `ex` is equal to the x-height of the font. - ex: CSSNumber, - /// A length in the `rex` unit. A `rex` is equal to the value of the `ex` unit on the root element. - rex: CSSNumber, - /// A length in the `ch` unit. A `ch` is equal to the width of the zero ("0") character in the current font. - ch: CSSNumber, - /// A length in the `rch` unit. An `rch` is equal to the value of the `ch` unit on the root element. - rch: CSSNumber, - /// A length in the `cap` unit. A `cap` is equal to the cap-height of the font. - cap: CSSNumber, - /// A length in the `rcap` unit. An `rcap` is equal to the value of the `cap` unit on the root element. - rcap: CSSNumber, - /// A length in the `ic` unit. An `ic` is equal to the width of the “水” (CJK water ideograph) character in the current font. - ic: CSSNumber, - /// A length in the `ric` unit. An `ric` is equal to the value of the `ic` unit on the root element. - ric: CSSNumber, - /// A length in the `lh` unit. An `lh` is equal to the computed value of the `line-height` property. - lh: CSSNumber, - /// A length in the `rlh` unit. An `rlh` is equal to the value of the `lh` unit on the root element. - rlh: CSSNumber, - - // https://www.w3.org/TR/css-values-4/#viewport-relative-units - /// A length in the `vw` unit. A `vw` is equal to 1% of the [viewport width](https://www.w3.org/TR/css-values-4/#ua-default-viewport-size). - vw: CSSNumber, - /// A length in the `lvw` unit. An `lvw` is equal to 1% of the [large viewport width](https://www.w3.org/TR/css-values-4/#large-viewport-size). - lvw: CSSNumber, - /// A length in the `svw` unit. An `svw` is equal to 1% of the [small viewport width](https://www.w3.org/TR/css-values-4/#small-viewport-size). - svw: CSSNumber, - /// A length in the `dvw` unit. An `dvw` is equal to 1% of the [dynamic viewport width](https://www.w3.org/TR/css-values-4/#dynamic-viewport-size). - dvw: CSSNumber, - /// A length in the `cqw` unit. An `cqw` is equal to 1% of the [query container](https://drafts.csswg.org/css-contain-3/#query-container) width. - cqw: CSSNumber, - - /// A length in the `vh` unit. A `vh` is equal to 1% of the [viewport height](https://www.w3.org/TR/css-values-4/#ua-default-viewport-size). - vh: CSSNumber, - /// A length in the `lvh` unit. An `lvh` is equal to 1% of the [large viewport height](https://www.w3.org/TR/css-values-4/#large-viewport-size). - lvh: CSSNumber, - /// A length in the `svh` unit. An `svh` is equal to 1% of the [small viewport height](https://www.w3.org/TR/css-values-4/#small-viewport-size). - svh: CSSNumber, - /// A length in the `dvh` unit. An `dvh` is equal to 1% of the [dynamic viewport height](https://www.w3.org/TR/css-values-4/#dynamic-viewport-size). - dvh: CSSNumber, - /// A length in the `cqh` unit. An `cqh` is equal to 1% of the [query container](https://drafts.csswg.org/css-contain-3/#query-container) height. - cqh: CSSNumber, - - /// A length in the `vi` unit. A `vi` is equal to 1% of the [viewport size](https://www.w3.org/TR/css-values-4/#ua-default-viewport-size) - /// in the box's [inline axis](https://www.w3.org/TR/css-writing-modes-4/#inline-axis). - vi: CSSNumber, - /// A length in the `svi` unit. A `svi` is equal to 1% of the [small viewport size](https://www.w3.org/TR/css-values-4/#small-viewport-size) - /// in the box's [inline axis](https://www.w3.org/TR/css-writing-modes-4/#inline-axis). - svi: CSSNumber, - /// A length in the `lvi` unit. A `lvi` is equal to 1% of the [large viewport size](https://www.w3.org/TR/css-values-4/#large-viewport-size) - /// in the box's [inline axis](https://www.w3.org/TR/css-writing-modes-4/#inline-axis). - lvi: CSSNumber, - /// A length in the `dvi` unit. A `dvi` is equal to 1% of the [dynamic viewport size](https://www.w3.org/TR/css-values-4/#dynamic-viewport-size) - /// in the box's [inline axis](https://www.w3.org/TR/css-writing-modes-4/#inline-axis). - dvi: CSSNumber, - /// A length in the `cqi` unit. An `cqi` is equal to 1% of the [query container](https://drafts.csswg.org/css-contain-3/#query-container) inline size. - cqi: CSSNumber, - - /// A length in the `vb` unit. A `vb` is equal to 1% of the [viewport size](https://www.w3.org/TR/css-values-4/#ua-default-viewport-size) - /// in the box's [block axis](https://www.w3.org/TR/css-writing-modes-4/#block-axis). - vb: CSSNumber, - /// A length in the `svb` unit. A `svb` is equal to 1% of the [small viewport size](https://www.w3.org/TR/css-values-4/#small-viewport-size) - /// in the box's [block axis](https://www.w3.org/TR/css-writing-modes-4/#block-axis). - svb: CSSNumber, - /// A length in the `lvb` unit. A `lvb` is equal to 1% of the [large viewport size](https://www.w3.org/TR/css-values-4/#large-viewport-size) - /// in the box's [block axis](https://www.w3.org/TR/css-writing-modes-4/#block-axis). - lvb: CSSNumber, - /// A length in the `dvb` unit. A `dvb` is equal to 1% of the [dynamic viewport size](https://www.w3.org/TR/css-values-4/#dynamic-viewport-size) - /// in the box's [block axis](https://www.w3.org/TR/css-writing-modes-4/#block-axis). - dvb: CSSNumber, - /// A length in the `cqb` unit. An `cqb` is equal to 1% of the [query container](https://drafts.csswg.org/css-contain-3/#query-container) block size. - cqb: CSSNumber, - - /// A length in the `vmin` unit. A `vmin` is equal to the smaller of `vw` and `vh`. - vmin: CSSNumber, - /// A length in the `svmin` unit. An `svmin` is equal to the smaller of `svw` and `svh`. - svmin: CSSNumber, - /// A length in the `lvmin` unit. An `lvmin` is equal to the smaller of `lvw` and `lvh`. - lvmin: CSSNumber, - /// A length in the `dvmin` unit. An `dvmin` is equal to the smaller of `dvw` and `dvh`. - dvmin: CSSNumber, - /// A length in the `cqmin` unit. An `cqmin` is equal to the smaller of `cqi` and `cqb`. - cqmin: CSSNumber, - - /// A length in the `vmax` unit. A `vmax` is equal to the larger of `vw` and `vh`. - vmax: CSSNumber, - /// A length in the `svmax` unit. An `svmax` is equal to the larger of `svw` and `svh`. - svmax: CSSNumber, - /// A length in the `lvmax` unit. An `lvmax` is equal to the larger of `lvw` and `lvh`. - lvmax: CSSNumber, - /// A length in the `dvmax` unit. An `dvmax` is equal to the larger of `dvw` and `dvh`. - dvmax: CSSNumber, - /// A length in the `cqmax` unit. An `cqmin` is equal to the larger of `cqi` and `cqb`. - cqmax: CSSNumber, - - const FeatureMap = .{ - .px = null, - .in = null, - .cm = null, - .mm = null, - .q = css.Feature.q_unit, - .pt = null, - .pc = null, - .em = null, - .rem = css.Feature.rem_unit, - .ex = css.Feature.ex_unit, - .rex = null, - .ch = css.Feature.ch_unit, - .rch = null, - .cap = css.Feature.cap_unit, - .rcap = null, - .ic = css.Feature.ic_unit, - .ric = null, - .lh = css.Feature.lh_unit, - .rlh = css.Feature.rlh_unit, - .vw = css.Feature.vw_unit, - .lvw = css.Feature.viewport_percentage_units_large, - .svw = css.Feature.viewport_percentage_units_small, - .dvw = css.Feature.viewport_percentage_units_dynamic, - .cqw = css.Feature.container_query_length_units, - .vh = css.Feature.vh_unit, - .lvh = css.Feature.viewport_percentage_units_large, - .svh = css.Feature.viewport_percentage_units_small, - .dvh = css.Feature.viewport_percentage_units_dynamic, - .cqh = css.Feature.container_query_length_units, - .vi = css.Feature.vi_unit, - .svi = css.Feature.viewport_percentage_units_small, - .lvi = css.Feature.viewport_percentage_units_large, - .dvi = css.Feature.viewport_percentage_units_dynamic, - .cqi = css.Feature.container_query_length_units, - .vb = css.Feature.vb_unit, - .svb = css.Feature.viewport_percentage_units_small, - .lvb = css.Feature.viewport_percentage_units_large, - .dvb = css.Feature.viewport_percentage_units_dynamic, - .cqb = css.Feature.container_query_length_units, - .vmin = css.Feature.vmin_unit, - .svmin = css.Feature.viewport_percentage_units_small, - .lvmin = css.Feature.viewport_percentage_units_large, - .dvmin = css.Feature.viewport_percentage_units_dynamic, - .cqmin = css.Feature.container_query_length_units, - .vmax = css.Feature.vmax_unit, - .svmax = css.Feature.viewport_percentage_units_small, - .lvmax = css.Feature.viewport_percentage_units_large, - .dvmax = css.Feature.viewport_percentage_units_dynamic, - .cqmax = css.Feature.container_query_length_units, - }; - - comptime { - const struct_fields = std.meta.fields(LengthValue); - const feature_fields = std.meta.fields(@TypeOf(FeatureMap)); - if (struct_fields.len != feature_fields.len) { - @compileError("LengthValue and FeatureMap must have the same number of fields"); - } - for (struct_fields) |field| { - _ = @field(FeatureMap, field.name); - } - } - - pub fn parse(input: *css.Parser) Result(@This()) { - const location = input.currentSourceLocation(); - const token = switch (input.next()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - switch (token.*) { - .dimension => |*dim| { - // todo_stuff.match_ignore_ascii_case - inline for (std.meta.fields(@This())) |field| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(field.name, dim.unit)) { - return .{ .result = @unionInit(LengthValue, field.name, dim.num.value) }; - } - } - }, - .number => |*num| return .{ .result = .{ .px = num.value } }, - else => {}, - } - return .{ .err = location.newUnexpectedTokenError(token.*) }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - const value, const unit = this.toUnitValue(); - - // The unit can be omitted if the value is zero, except inside calc() - // expressions, where unitless numbers won't be parsed as dimensions. - if (!dest.in_calc and value == 0.0) { - return dest.writeChar('0'); - } - - return css.serializer.serializeDimension(value, unit, dest); - } - - pub fn isZero(this: *const LengthValue) bool { - inline for (bun.meta.EnumFields(@This())) |field| { - if (@intFromEnum(this.*) == field.value) { - return @field(this, field.name) == 0.0; - } - } - unreachable; - } - - pub fn deepClone(this: *const @This(), _: std.mem.Allocator) @This() { - return this.*; - } - - pub fn zero() LengthValue { - return .{ .px = 0.0 }; - } - - /// Attempts to convert the value to pixels. - /// Returns `None` if the conversion is not possible. - pub fn toPx(this: *const @This()) ?CSSNumber { - return switch (this.*) { - .px => |v| v, - .in => |v| v * PX_PER_IN, - .cm => |v| v * PX_PER_CM, - .mm => |v| v * PX_PER_MM, - .q => |v| v * PX_PER_Q, - .pt => |v| v * PX_PER_PT, - .pc => |v| v * PX_PER_PC, - else => null, - }; - } - - pub inline fn eql(this: *const @This(), other: *const @This()) bool { - inline for (bun.meta.EnumFields(@This())) |field| { - if (field.value == @intFromEnum(this.*) and field.value == @intFromEnum(other.*)) { - return @field(this, field.name) == @field(other, field.name); - } - } - return false; - } - - pub fn isSignNegative(this: *const @This()) bool { - const s = this.trySign() orelse return false; - return css.signfns.isSignNegative(s); - } - - pub fn isSignPositive(this: *const @This()) bool { - const s = this.trySign() orelse return false; - return css.signfns.isSignPositive(s); - } - - pub fn trySign(this: *const @This()) ?f32 { - return sign(this); - } - - pub fn sign(this: *const @This()) f32 { - const enum_fields = @typeInfo(@typeInfo(@This()).@"union".tag_type.?).@"enum".fields; - inline for (std.meta.fields(@This()), 0..) |field, i| { - if (enum_fields[i].value == @intFromEnum(this.*)) { - return css.signfns.signF32(@field(this, field.name)); - } - } - unreachable; - } - - pub fn tryFromToken(token: *const css.Token) css.Maybe(@This(), void) { - switch (token.*) { - .dimension => |*dim| { - inline for (std.meta.fields(@This())) |field| { - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(field.name, dim.unit)) { - return .{ .result = @unionInit(LengthValue, field.name, dim.num.value) }; - } - } - }, - else => {}, - } - return .{ .err = {} }; - } - - pub fn toUnitValue(this: *const @This()) struct { CSSNumber, []const u8 } { - const enum_fields = @typeInfo(@typeInfo(@This()).@"union".tag_type.?).@"enum".fields; - inline for (std.meta.fields(@This()), 0..) |field, i| { - if (enum_fields[i].value == @intFromEnum(this.*)) { - return .{ @field(this, field.name), field.name }; - } - } - unreachable; - } - - pub fn map(this: *const @This(), comptime map_fn: *const fn (f32) f32) LengthValue { - inline for (comptime bun.meta.EnumFields(@This())) |field| { - if (field.value == @intFromEnum(this.*)) { - return @unionInit(LengthValue, field.name, map_fn(@field(this, field.name))); - } - } - unreachable; - } - - pub fn mulF32(this: @This(), _: Allocator, other: f32) LengthValue { - const fields = comptime bun.meta.EnumFields(@This()); - inline for (fields) |field| { - if (field.value == @intFromEnum(this)) { - return @unionInit(LengthValue, field.name, @field(this, field.name) * other); - } - } - unreachable; - } - - pub fn tryFromAngle(_: css.css_values.angle.Angle) ?@This() { - return null; - } - - pub fn partialCmp(this: *const LengthValue, other: *const LengthValue) ?std.math.Order { - if (@intFromEnum(this.*) == @intFromEnum(other.*)) { - inline for (bun.meta.EnumFields(LengthValue)) |field| { - if (field.value == @intFromEnum(this.*)) { - const a = @field(this, field.name); - const b = @field(other, field.name); - return css.generic.partialCmpF32(&a, &b); - } - } - unreachable; - } - - const a = this.toPx(); - const b = other.toPx(); - if (a != null and b != null) { - return css.generic.partialCmpF32(&a.?, &b.?); - } - return null; - } - - pub fn tryOp( - this: *const LengthValue, - other: *const LengthValue, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, - ) ?LengthValue { - if (@intFromEnum(this.*) == @intFromEnum(other.*)) { - inline for (bun.meta.EnumFields(LengthValue)) |field| { - if (field.value == @intFromEnum(this.*)) { - const a = @field(this, field.name); - const b = @field(other, field.name); - return @unionInit(LengthValue, field.name, op_fn(ctx, a, b)); - } - } - unreachable; - } - - const a = this.toPx(); - const b = this.toPx(); - if (a != null and b != null) { - return .{ .px = op_fn(ctx, a.?, b.?) }; - } - return null; - } - - pub fn tryOpTo( - this: *const LengthValue, - other: *const LengthValue, - comptime R: type, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R, - ) ?R { - if (@intFromEnum(this.*) == @intFromEnum(other.*)) { - inline for (bun.meta.EnumFields(LengthValue)) |field| { - if (field.value == @intFromEnum(this.*)) { - const a = @field(this, field.name); - const b = @field(other, field.name); - return op_fn(ctx, a, b); - } - } - unreachable; - } - - const a = this.toPx(); - const b = this.toPx(); - if (a != null and b != null) { - return op_fn(ctx, a.?, b.?); - } - return null; - } - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn tryAdd(this: *const LengthValue, _: std.mem.Allocator, rhs: *const LengthValue) ?LengthValue { - if (@intFromEnum(this.*) == @intFromEnum(rhs.*)) { - inline for (bun.meta.EnumFields(LengthValue)) |field| { - if (field.value == @intFromEnum(this.*)) { - return @unionInit(LengthValue, field.name, @field(this, field.name) + @field(rhs, field.name)); - } - } - unreachable; - } - if (this.toPx()) |a| { - if (rhs.toPx()) |b| { - return .{ .px = a + b }; - } - } - return null; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - inline for (bun.meta.EnumFields(LengthValue)) |field| { - if (field.value == @intFromEnum(this.*)) { - if (comptime @TypeOf(@field(FeatureMap, field.name)) == css.compat.Feature) { - const feature = @field(FeatureMap, field.name); - return css.compat.Feature.isCompatible(feature, browsers); - } - return true; - } - } - unreachable; - } -}; - -/// A CSS [``](https://www.w3.org/TR/css-values-4/#lengths) value, with support for `calc()`. -pub const Length = union(enum) { - /// An explicitly specified length value. - value: LengthValue, - /// A computed length value using `calc()`. - calc: *Calc(Length), - - pub fn zero() Length { - return .{ .value = LengthValue.zero() }; - } - - pub fn deepClone(this: *const Length, allocator: Allocator) Length { - return switch (this.*) { - .value => |v| .{ .value = v }, - .calc => |calc| .{ .calc = bun.create(allocator, Calc(Length), Calc(Length).deepClone(calc, allocator)) }, - }; - } - - pub fn deinit(this: *const Length, allocator: Allocator) void { - return switch (this.*) { - .calc => |calc| calc.deinit(allocator), - .value => {}, - }; - } - - pub fn parse(input: *css.Parser) Result(Length) { - if (input.tryParse(Calc(Length).parse, .{}).asValue()) |calc_value| { - // PERF: I don't like this redundant allocation - if (calc_value == .value) { - const ret = calc_value.value.*; - input.allocator().destroy(calc_value.value); - return .{ .result = ret }; - } - return .{ .result = .{ - .calc = bun.create( - input.allocator(), - Calc(Length), - calc_value, - ), - } }; - } - - const len = switch (LengthValue.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = .{ .value = len } }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return switch (this.*) { - .value => |a| a.toCss(dest), - .calc => |c| c.toCss(dest), - }; - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - - pub fn px(p: CSSNumber) Length { - return .{ .value = .{ .px = p } }; - } - - pub fn toPx(this: *const Length) ?CSSNumber { - return switch (this.*) { - .value => |a| a.toPx(), - else => null, - }; - } - - pub fn mulF32(this: Length, allocator: Allocator, other: f32) Length { - return switch (this) { - .value => Length{ .value = this.value.mulF32(allocator, other) }, - .calc => Length{ - .calc = bun.create( - allocator, - Calc(Length), - this.calc.mulF32(allocator, other), - ), - }, - }; - } - - pub fn add(this: Length, allocator: Allocator, other: Length) Length { - // Unwrap calc(...) functions so we can add inside. - // Then wrap the result in a calc(...) again if necessary. - const a = unwrapCalc(allocator, this); - const b = unwrapCalc(allocator, other); - const res: Length = Length.addInternal(a, allocator, b); - if (res == .calc) { - if (res.calc.* == .value) return res.calc.value.*; - if (res.calc.* == .function and res.calc.function.* != .calc) return Length{ .calc = bun.create(allocator, Calc(Length), Calc(Length){ .function = res.calc.function }) }; - return Length{ .calc = bun.create(allocator, Calc(Length), Calc(Length){ - .function = bun.create(allocator, MathFunction(Length), MathFunction(Length){ .calc = res.calc.* }), - }) }; - } - return res; - } - - pub fn addInternal(this: Length, allocator: Allocator, other: Length) Length { - if (this.tryAdd(allocator, &other)) |r| return r; - return this.add__(allocator, other); - } - - pub fn intoCalc(this: Length, allocator: Allocator) Calc(Length) { - return switch (this) { - .calc => |c| c.*, - else => |v| Calc(Length){ .value = bun.create(allocator, Length, v) }, - }; - } - - fn add__(this: Length, allocator: Allocator, other: Length) Length { - var a = this; - var b = other; - - if (a.isZero()) return b; - - if (b.isZero()) return a; - - if (a.isSignNegative() and b.isSignPositive()) { - std.mem.swap(Length, &a, &b); - } - - if (a == .calc and a.calc.* == .value and b != .calc) { - return a.calc.value.add__(allocator, b); - } else if (b == .calc and b.calc.* == .value and a != .calc) { - return a.add__(allocator, b.calc.value.*); - } else { - return Length{ .calc = bun.create(allocator, Calc(Length), Calc(Length){ - .sum = .{ - .left = bun.create(allocator, Calc(Length), a.intoCalc(allocator)), - .right = bun.create(allocator, Calc(Length), b.intoCalc(allocator)), - }, - }) }; - } - } - - fn tryAdd(this: *const Length, allocator: Allocator, other: *const Length) ?Length { - if (this.* == .value and other.* == .value) { - if (this.value.tryAdd(allocator, &other.value)) |res| { - return Length{ .value = res }; - } - return null; - } - - if (this.* == .calc) { - switch (this.calc.*) { - .value => |v| return v.tryAdd(allocator, other), - .sum => |s| { - const a = Length{ .calc = s.left }; - if (a.tryAdd(allocator, other)) |res| { - return res.add__(allocator, Length{ .calc = s.right }); - } - - const b = Length{ .calc = s.right }; - if (b.tryAdd(allocator, other)) |res| { - return (Length{ .calc = s.left }).add__(allocator, res); - } - - return null; - }, - else => return null, - } - } - - if (other.* == .calc) { - switch (other.calc.*) { - .value => |v| return v.tryAdd(allocator, this), - .sum => |s| { - const a = Length{ .calc = s.left }; - if (this.tryAdd(allocator, &a)) |res| { - return res.add__(allocator, Length{ .calc = s.right }); - } - - const b = Length{ .calc = s.right }; - if (this.tryAdd(allocator, &b)) |res| { - return (Length{ .calc = s.left }).add__(allocator, res); - } - - return null; - }, - else => return null, - } - } - - return null; - } - - fn unwrapCalc(allocator: Allocator, length: Length) Length { - return switch (length) { - .calc => |c| switch (c.*) { - .function => |f| switch (f.*) { - .calc => |c2| .{ .calc = bun.create(allocator, Calc(Length), c2) }, - else => |c2| .{ .calc = bun.create( - allocator, - Calc(Length), - Calc(Length){ .function = bun.create(allocator, css.css_values.calc.MathFunction(Length), c2) }, - ) }, - }, - else => .{ .calc = c }, - }, - else => length, - }; - } - - pub fn trySign(this: *const Length) ?f32 { - return switch (this.*) { - .value => |v| v.sign(), - .calc => |v| v.trySign(), - }; - } - - pub fn isSignNegative(this: *const @This()) bool { - const s = this.trySign() orelse return false; - return css.signfns.isSignNegative(s); - } - - pub fn isSignPositive(this: *const @This()) bool { - const s = this.trySign() orelse return false; - return css.signfns.isSignPositive(s); - } - - pub fn partialCmp(this: *const Length, other: *const Length) ?std.math.Order { - if (this.* == .value and other.* == .value) return css.generic.partialCmp(LengthValue, &this.value, &other.value); - return null; - } - - pub fn tryFromAngle(_: css.css_values.angle.Angle) ?@This() { - return null; - } - - pub fn tryMap(this: *const Length, comptime map_fn: *const fn (f32) f32) ?Length { - return switch (this.*) { - .value => |v| .{ .value = v.map(map_fn) }, - else => null, - }; - } - - pub fn tryOp( - this: *const Length, - other: *const Length, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, - ) ?Length { - if (this.* == .value and other.* == .value) { - if (this.value.tryOp(&other.value, ctx, op_fn)) |val| return .{ .value = val }; - return null; - } - return null; - } - - pub fn tryOpTo( - this: *const Length, - other: *const Length, - comptime R: type, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R, - ) ?R { - if (this.* == .value and other.* == .value) { - return this.value.tryOpTo(&other.value, R, ctx, op_fn); - } - return null; - } - - pub fn isZero(this: *const Length) bool { - return switch (this.*) { - .value => |v| v.isZero(), - else => false, - }; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .value => |*v| v.isCompatible(browsers), - .calc => |c| c.isCompatible(browsers), - }; - } -}; - -const bun = @import("bun"); -const std = @import("std"); -const Allocator = std.mem.Allocator; diff --git a/src/css/values/number.zig b/src/css/values/number.zig deleted file mode 100644 index 36a25bf099cc..000000000000 --- a/src/css/values/number.zig +++ /dev/null @@ -1,62 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const Calc = css.css_values.calc.Calc; - -pub const CSSNumber = f32; -pub const CSSNumberFns = struct { - pub fn parse(input: *css.Parser) Result(CSSNumber) { - if (input.tryParse(Calc(f32).parse, .{}).asValue()) |calc_value| { - switch (calc_value) { - .value => |v| return .{ .result = v.* }, - .number => |n| return .{ .result = n }, - // Numbers are always compatible, so they will always compute to a value. - else => return .{ .err = input.newCustomError(css.ParserError.invalid_value) }, - } - } - - return input.expectNumber(); - } - - pub fn toCss(this: *const CSSNumber, dest: *Printer) PrintErr!void { - const number: f32 = this.*; - if (number != 0.0 and @abs(number) < 1.0) { - var dtoa_buf: [129]u8 = undefined; - const str, _ = try css.dtoa_short(&dtoa_buf, number, 6); - if (number < 0.0) { - try dest.writeChar('-'); - try dest.writeStr(bun.strings.trimLeadingPattern2(str, '-', '0')); - } else { - try dest.writeStr(bun.strings.trimLeadingChar(str, '0')); - } - } else { - return css.to_css.float32(number, dest) catch { - return dest.addFmtError(); - }; - } - } - - pub fn tryFromAngle(_: css.css_values.angle.Angle) ?CSSNumber { - return null; - } - - pub fn sign(this: *const CSSNumber) f32 { - if (this.* == 0.0) return if (css.signfns.isSignPositive(this.*)) 0.0 else 0.0; - return css.signfns.signum(this.*); - } -}; - -/// A CSS [``](https://www.w3.org/TR/css-values-4/#integers) value. -pub const CSSInteger = i32; -pub const CSSIntegerFns = struct { - pub fn parse(input: *css.Parser) Result(CSSInteger) { - // TODO: calc?? - return input.expectInteger(); - } - pub inline fn toCss(this: *const CSSInteger, dest: *Printer) PrintErr!void { - try css.to_css.integer(i32, this.*, dest); - } -}; - -const bun = @import("bun"); diff --git a/src/css/values/percentage.zig b/src/css/values/percentage.zig deleted file mode 100644 index eccdac478732..000000000000 --- a/src/css/values/percentage.zig +++ /dev/null @@ -1,473 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumber = css.css_values.number.CSSNumber; -const Calc = css.css_values.calc.Calc; - -pub const Percentage = struct { - v: CSSNumber, - - pub fn parse(input: *css.Parser) Result(Percentage) { - if (input.tryParse(Calc(Percentage).parse, .{}).asValue()) |calc_value| { - if (calc_value == .value) return .{ .result = calc_value.value.* }; - // Handle calc() expressions that can't be reduced to a simple value (e.g., containing NaN, variables, etc.) - // Return an error since we can't determine the percentage value at parse time - return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - } - - const percent = switch (input.expectPercentage()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - return .{ .result = Percentage{ .v = percent } }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - const x = this.v * 100.0; - const int_value: ?i32 = if ((x - @trunc(x)) == 0.0) - bun.intFromFloat(i32, this.v) - else - null; - - const percent = css.Token{ .percentage = .{ - .has_sign = this.v < 0.0, - .unit_value = this.v, - .int_value = int_value, - } }; - - if (this.v != 0.0 and @abs(this.v) < 0.01) { - var buf: [32]u8 = undefined; - var writer = std.Io.Writer.fixed(&buf); - percent.toCssGeneric(&writer) catch return dest.addFmtError(); - if (this.v < 0.0) { - try dest.writeChar('-'); - try dest.writeStr(bun.strings.trimLeadingPattern2(writer.buffered(), '-', '0')); - } else { - try dest.writeStr(bun.strings.trimLeadingChar(writer.buffered(), '0')); - } - } else { - try percent.toCss(dest); - } - } - - pub inline fn eql(this: *const Percentage, other: *const Percentage) bool { - return this.v == other.v; - } - - pub fn addInternal(this: Percentage, allocator: std.mem.Allocator, other: Percentage) Percentage { - return this.add(allocator, other); - } - - pub fn add(lhs: Percentage, _: std.mem.Allocator, rhs: Percentage) Percentage { - return Percentage{ .v = lhs.v + rhs.v }; - } - - pub fn intoCalc(this: Percentage, allocator: std.mem.Allocator) Calc(Percentage) { - return Calc(Percentage){ .value = bun.create(allocator, Percentage, this) }; - } - - pub fn mulF32(this: Percentage, _: std.mem.Allocator, other: f32) Percentage { - return Percentage{ .v = this.v * other }; - } - - pub fn isZero(this: *const Percentage) bool { - return this.v == 0.0; - } - - pub fn sign(this: *const Percentage) f32 { - return css.signfns.signF32(this.v); - } - - pub fn trySign(this: *const Percentage) ?f32 { - return this.sign(); - } - - pub fn partialCmp(this: *const Percentage, other: *const Percentage) ?std.math.Order { - return css.generic.partialCmp(f32, &this.v, &other.v); - } - - pub fn tryFromAngle(_: css.css_values.angle.Angle) ?Percentage { - return null; - } - - pub fn tryMap(_: *const Percentage, comptime _: *const fn (f32) f32) ?Percentage { - // Percentages cannot be mapped because we don't know what they will resolve to. - // For example, they might be positive or negative depending on what they are a - // percentage of, which we don't know. - return null; - } - - pub fn op( - this: *const Percentage, - other: *const Percentage, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, - ) Percentage { - return Percentage{ .v = op_fn(ctx, this.v, other.v) }; - } - - pub fn opTo( - this: *const Percentage, - other: *const Percentage, - comptime R: type, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) R, - ) R { - return op_fn(ctx, this.v, other.v); - } - - pub fn tryOp( - this: *const Percentage, - other: *const Percentage, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, - ) ?Percentage { - return Percentage{ .v = op_fn(ctx, this.v, other.v) }; - } -}; - -fn needsDeepclone(comptime D: type) bool { - return switch (D) { - css.css_values.angle.Angle => false, - css.css_values.length.LengthValue => false, - else => @compileError("Can't tell if " ++ @typeName(D) ++ " needs deepclone, please add it to this switch statement."), - }; -} - -pub fn DimensionPercentage(comptime D: type) type { - const needs_deepclone = needsDeepclone(D); - return union(enum) { - dimension: D, - percentage: Percentage, - calc: *Calc(DimensionPercentage(D)), - - const This = @This(); - - pub fn parse(input: *css.Parser) Result(@This()) { - if (input.tryParse(Calc(This).parse, .{}).asValue()) |calc_value| { - if (calc_value == .value) return .{ .result = calc_value.value.* }; - return .{ .result = .{ - .calc = bun.create(input.allocator(), Calc(DimensionPercentage(D)), calc_value), - } }; - } - - if (input.tryParse(D.parse, .{}).asValue()) |length| { - return .{ .result = .{ .dimension = length } }; - } - - if (input.tryParse(Percentage.parse, .{}).asValue()) |percentage| { - return .{ .result = .{ .percentage = percentage } }; - } - - return .{ .err = input.newErrorForNextToken() }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - return switch (this.*) { - .dimension => |*length| length.toCss(dest), - .percentage => |*per| per.toCss(dest), - .calc => |calc| calc.toCss(dest), - }; - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return switch (this.*) { - .dimension => |*d| d.isCompatible(browsers), - .calc => |c| c.isCompatible(browsers), - .percentage => true, - }; - } - - pub fn eql(this: *const This, other: *const This) bool { - return css.implementEql(@This(), this, other); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) This { - return switch (this.*) { - .dimension => |d| if (comptime needs_deepclone) .{ .dimension = d.deepClone(allocator) } else this.*, - .percentage => return this.*, - .calc => |calc| .{ .calc = bun.create(allocator, Calc(DimensionPercentage(D)), calc.deepClone(allocator)) }, - }; - } - - pub fn deinit(this: *const @This(), allocator: std.mem.Allocator) void { - return switch (this.*) { - .dimension => |d| if (comptime @hasDecl(D, "deinit")) d.deinit(allocator), - .percentage => {}, - .calc => |calc| calc.deinit(allocator), - }; - } - - pub fn zero() This { - return This{ .dimension = switch (D) { - f32 => 0.0, - else => D.zero(), - } }; - } - - pub fn isZero(this: *const This) bool { - return switch (this.*) { - .dimension => |*d| switch (D) { - f32 => d == 0.0, - else => d.isZero(), - }, - .percentage => |*p| p.isZero(), - else => false, - }; - } - - fn mulValueF32(lhs: D, allocator: std.mem.Allocator, rhs: f32) D { - return switch (D) { - f32 => lhs * rhs, - else => lhs.mulF32(allocator, rhs), - }; - } - - pub fn mulF32(this: This, allocator: std.mem.Allocator, other: f32) This { - return switch (this) { - .dimension => |d| .{ .dimension = mulValueF32(d, allocator, other) }, - .percentage => |p| .{ .percentage = p.mulF32(allocator, other) }, - .calc => |c| .{ .calc = bun.create(allocator, Calc(DimensionPercentage(D)), c.mulF32(allocator, other)) }, - }; - } - - pub fn add(this: This, allocator: std.mem.Allocator, other: This) This { - // Unwrap calc(...) functions so we can add inside. - // Then wrap the result in a calc(...) again if necessary. - const a = unwrapCalc(this, allocator); - const b = unwrapCalc(other, allocator); - const res = a.addInternal(allocator, b); - return switch (res) { - .calc => |c| switch (c.*) { - .value => |l| l.*, - .function => |f| if (f.* != .calc) .{ - .calc = bun.create(allocator, Calc(DimensionPercentage(D)), .{ - .function = f, - }), - } else .{ - .calc = bun.create(allocator, Calc(DimensionPercentage(D)), .{ - .function = bun.create( - allocator, - css.css_values.calc.MathFunction(DimensionPercentage(D)), - .{ .calc = c.* }, - ), - }), - }, - else => .{ - .calc = bun.create(allocator, Calc(DimensionPercentage(D)), .{ - .function = bun.create( - allocator, - css.css_values.calc.MathFunction(DimensionPercentage(D)), - .{ .calc = c.* }, - ), - }), - }, - }, - else => res, - }; - } - - pub fn addInternal(this: This, allocator: std.mem.Allocator, other: This) This { - if (this.addRecursive(allocator, &other)) |res| return res; - return this.addImpl(allocator, other); - } - - fn addRecursive(this: *const This, allocator: std.mem.Allocator, other: *const This) ?This { - if (this.* == .dimension and other.* == .dimension) { - if (this.dimension.tryAdd(allocator, &other.dimension)) |res| { - return .{ .dimension = res }; - } - } else if (this.* == .percentage and other.* == .percentage) { - return .{ .percentage = .{ .v = this.percentage.v + other.percentage.v } }; - } else if (this.* == .calc) { - switch (this.calc.*) { - .value => |v| return v.addRecursive(allocator, other), - .sum => |sum| { - const left_calc = This{ .calc = sum.left }; - if (left_calc.addRecursive(allocator, other)) |res| { - return res.addImpl(allocator, This{ .calc = sum.right }); - } - - const right_calc = This{ .calc = sum.right }; - if (right_calc.addRecursive(allocator, other)) |res| { - return (This{ .calc = sum.left }).addImpl(allocator, res); - } - }, - else => {}, - } - } else if (other.* == .calc) { - switch (other.calc.*) { - .value => |v| return this.addRecursive(allocator, v), - .sum => |sum| { - const left_calc = This{ .calc = sum.left }; - if (this.addRecursive(allocator, &left_calc)) |res| { - return res.addImpl(allocator, This{ .calc = sum.right }); - } - - const right_calc = This{ .calc = sum.right }; - if (this.addRecursive(allocator, &right_calc)) |res| { - return (This{ .calc = sum.left }).addImpl(allocator, res); - } - }, - else => {}, - } - } - - return null; - } - - fn addImpl(this: This, allocator: std.mem.Allocator, other: This) This { - var a = this; - var b = other; - - if (a.isZero()) return b; - if (b.isZero()) return a; - - if (a.isSignNegative() and b.isSignPositive()) { - std.mem.swap(This, &a, &b); - } - - if (a == .calc and a.calc.* == .value and b != .calc) { - return a.calc.value.addImpl(allocator, b); - } else if (b == .calc and b.calc.* == .value and a != .calc) { - return a.addImpl(allocator, b.calc.value.*); - } else { - return .{ - .calc = bun.create( - allocator, - Calc(DimensionPercentage(D)), - .{ .sum = .{ - .left = bun.create(allocator, Calc(DimensionPercentage(D)), a.intoCalc(allocator)), - .right = bun.create(allocator, Calc(DimensionPercentage(D)), b.intoCalc(allocator)), - } }, - ), - }; - } - } - - inline fn isSignPositive(this: This) bool { - const sign = this.trySign() orelse return false; - return css.signfns.isSignPositive(sign); - } - - inline fn isSignNegative(this: This) bool { - const sign = this.trySign() orelse return false; - return css.signfns.isSignNegative(sign); - } - - fn unwrapCalc(this: This, allocator: std.mem.Allocator) This { - return switch (this) { - .calc => |calc| switch (calc.*) { - .function => |f| switch (f.*) { - .calc => |c2| .{ .calc = bun.create(allocator, Calc(DimensionPercentage(D)), c2) }, - else => .{ .calc = bun.create( - allocator, - Calc(DimensionPercentage(D)), - .{ - .function = bun.create( - allocator, - css.css_values.calc.MathFunction(DimensionPercentage(D)), - f.*, - ), - }, - ) }, - }, - else => .{ .calc = calc }, - }, - else => this, - }; - } - - pub fn partialCmp(this: *const This, other: *const This) ?std.math.Order { - if (this.* == .dimension and other.* == .dimension) { - return this.dimension.partialCmp(&other.dimension); - } else if (this.* == .percentage and other.* == .percentage) { - return this.percentage.partialCmp(&other.percentage); - } else { - return null; - } - } - - pub fn trySign(this: *const This) ?f32 { - return switch (this.*) { - .dimension => |*d| css.generic.trySign(@TypeOf(d.*), d), - .percentage => |p| p.trySign(), - .calc => |c| c.trySign(), - }; - } - - pub fn tryFromAngle(angle: css.css_values.angle.Angle) ?This { - return DimensionPercentage(D){ - .dimension = D.tryFromAngle(angle) orelse return null, - }; - } - - pub fn tryMap(this: *const This, comptime mapfn: *const fn (f32) f32) ?This { - return switch (this.*) { - .dimension => |vv| if (css.generic.tryMap(D, &vv, mapfn)) |v| .{ .dimension = v } else null, - else => null, - }; - } - - pub fn tryOp( - this: *const This, - other: *const This, - ctx: anytype, - comptime op_fn: *const fn (@TypeOf(ctx), a: f32, b: f32) f32, - ) ?This { - if (this.* == .dimension and other.* == .dimension) return .{ .dimension = css.generic.tryOp(D, &this.dimension, &other.dimension, ctx, op_fn) orelse return null }; - if (this.* == .percentage and other.* == .percentage) return .{ .percentage = Percentage{ .v = op_fn(ctx, this.percentage.v, other.percentage.v) } }; - return null; - } - - pub fn intoCalc(this: This, allocator: std.mem.Allocator) Calc(DimensionPercentage(D)) { - return switch (this) { - .calc => |calc| calc.*, - else => .{ .value = bun.create(allocator, This, this) }, - }; - } - }; -} - -/// Either a `` or ``. -pub const NumberOrPercentage = union(enum) { - /// A number. - number: CSSNumber, - /// A percentage. - percentage: Percentage, - - // TODO: implement this - pub const parse = css.DeriveParse(@This()).parse; - pub const toCss = css.DeriveToCss(@This()).toCss; - - // pub fn parse(input: *css.Parser) Result(NumberOrPercentage) { - // _ = input; // autofix - // @panic(css.todo_stuff.depth); - // } - - // pub fn toCss(this: *const NumberOrPercentage, dest: *css.Printer) css.PrintErr!void { - // _ = this; // autofix - // _ = dest; // autofix - // @panic(css.todo_stuff.depth); - // } - - pub fn deepClone(this: *const NumberOrPercentage, allocator: std.mem.Allocator) NumberOrPercentage { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const NumberOrPercentage, other: *const NumberOrPercentage) bool { - return css.implementEql(@This(), this, other); - } - - pub fn intoF32(this: *const @This()) f32 { - return switch (this.*) { - .number => this.number, - .percentage => this.percentage.v, - }; - } -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/values/position.zig b/src/css/values/position.zig deleted file mode 100644 index 97acd8b6ffd0..000000000000 --- a/src/css/values/position.zig +++ /dev/null @@ -1,429 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const LengthPercentage = css.css_values.length.LengthPercentage; -const Percentage = css.css_values.percentage.Percentage; - -/// A CSS `` value, -/// as used in the `background-position` property, gradients, masks, etc. -pub const Position = struct { - /// The x-position. - x: HorizontalPosition, - /// The y-position. - y: VerticalPosition, - - pub fn parse(input: *css.Parser) Result(Position) { - // Try parsing a horizontal position first - if (input.tryParse(HorizontalPosition.parse, .{}).asValue()) |horizontal_pos| { - switch (horizontal_pos) { - .center => { - // Try parsing a vertical position next - if (input.tryParse(VerticalPosition.parse, .{}).asValue()) |y| { - return .{ .result = Position{ - .x = .center, - .y = y, - } }; - } - - // If it didn't work, assume the first actually represents a y position, - // and the next is an x position. e.g. `center left` rather than `left center`. - const x = input.tryParse(HorizontalPosition.parse, .{}).unwrapOr(HorizontalPosition.center); - const y = VerticalPosition.center; - return .{ .result = Position{ .x = x, .y = y } }; - }, - .length => |*x| { - // If we got a length as the first component, then the second must - // be a keyword or length (not a side offset). - if (input.tryParse(VerticalPositionKeyword.parse, .{}).asValue()) |y_keyword| { - const y = VerticalPosition{ .side = .{ - .side = y_keyword, - .offset = null, - } }; - return .{ .result = Position{ .x = .{ .length = x.* }, .y = y } }; - } - if (input.tryParse(LengthPercentage.parse, .{}).asValue()) |y_lp| { - const y = VerticalPosition{ .length = y_lp }; - return .{ .result = Position{ .x = .{ .length = x.* }, .y = y } }; - } - const y = VerticalPosition.center; - _ = input.tryParse(css.Parser.expectIdentMatching, .{"center"}); - return .{ .result = Position{ .x = .{ .length = x.* }, .y = y } }; - }, - .side => |*side| { - const x_keyword = side.side; - const lp = side.offset; - - // If we got a horizontal side keyword (and optional offset), expect another for the vertical side. - // e.g. `left center` or `left 20px center` - if (input.tryParse(css.Parser.expectIdentMatching, .{"center"}).isOk()) { - const x = HorizontalPosition{ .side = .{ - .side = x_keyword, - .offset = lp, - } }; - const y = VerticalPosition.center; - return .{ .result = Position{ .x = x, .y = y } }; - } - - // e.g. `left top`, `left top 20px`, `left 20px top`, or `left 20px top 20px` - if (input.tryParse(VerticalPositionKeyword.parse, .{}).asValue()) |y_keyword| { - const y_lp = switch (input.tryParse(LengthPercentage.parse, .{})) { - .result => |vv| vv, - .err => null, - }; - const x = HorizontalPosition{ .side = .{ - .side = x_keyword, - .offset = lp, - } }; - const y = VerticalPosition{ .side = .{ - .side = y_keyword, - .offset = y_lp, - } }; - return .{ .result = Position{ .x = x, .y = y } }; - } - - // If we didn't get a vertical side keyword (e.g. `left 20px`), then apply the offset to the vertical side. - const x = HorizontalPosition{ .side = .{ - .side = x_keyword, - .offset = null, - } }; - const y = if (lp) |lp_val| - VerticalPosition{ .length = lp_val } - else - VerticalPosition.center; - return .{ .result = Position{ .x = x, .y = y } }; - }, - } - } - - // If the horizontal position didn't parse, then it must be out of order. Try vertical position keyword. - const y_keyword = switch (VerticalPositionKeyword.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const lp_and_x_pos = input.tryParse(struct { - fn parse(i: *css.Parser) Result(struct { ?LengthPercentage, HorizontalPosition }) { - const y_lp = i.tryParse(LengthPercentage.parse, .{}).asValue(); - if (i.tryParse(HorizontalPositionKeyword.parse, .{}).asValue()) |x_keyword| { - const x_lp = i.tryParse(LengthPercentage.parse, .{}).asValue(); - const x_pos = HorizontalPosition{ .side = .{ - .side = x_keyword, - .offset = x_lp, - } }; - return .{ .result = .{ y_lp, x_pos } }; - } - if (i.expectIdentMatching("center").asErr()) |e| return .{ .err = e }; - const x_pos = HorizontalPosition.center; - return .{ .result = .{ y_lp, x_pos } }; - } - }.parse, .{}); - - if (lp_and_x_pos.asValue()) |tuple| { - const y_lp = tuple[0]; - const x = tuple[1]; - const y = VerticalPosition{ .side = .{ - .side = y_keyword, - .offset = y_lp, - } }; - return .{ .result = Position{ .x = x, .y = y } }; - } - - const x = HorizontalPosition.center; - const y = VerticalPosition{ .side = .{ - .side = y_keyword, - .offset = null, - } }; - return .{ .result = Position{ .x = x, .y = y } }; - } - - pub fn toCss(this: *const Position, dest: *css.Printer) css.PrintErr!void { - if (this.x == .side and this.y == .length and this.x.side.side != .left) { - try this.x.toCss(dest); - try dest.writeStr(" top "); - try this.y.length.toCss(dest); - } else if (this.x == .side and this.x.side.side != .left and this.y.isCenter()) { - // If there is a side keyword with an offset, "center" must be a keyword not a percentage. - try this.x.toCss(dest); - try dest.writeStr(" center"); - } else if (this.x == .length and this.y == .side and this.y.side.side != .top) { - try dest.writeStr("left "); - try this.x.length.toCss(dest); - try dest.writeStr(" "); - try this.y.toCss(dest); - } else if (this.x.isCenter() and this.y.isCenter()) { - // `center center` => 50% - try this.x.toCss(dest); - } else if (this.x == .length and this.y.isCenter()) { - // `center` is assumed if omitted. - try this.x.length.toCss(dest); - } else if (this.x == .side and this.x.side.offset == null and this.y.isCenter()) { - const p: LengthPercentage = this.x.side.side.intoLengthPercentage(); - try p.toCss(dest); - } else if (this.y == .side and this.y.side.offset == null and this.x.isCenter()) { - try this.y.toCss(dest); - } else if (this.x == .side and this.x.side.offset == null and this.y == .side and this.y.side.offset == null) { - const x: LengthPercentage = this.x.side.side.intoLengthPercentage(); - const y: LengthPercentage = this.y.side.side.intoLengthPercentage(); - try x.toCss(dest); - try dest.writeStr(" "); - try y.toCss(dest); - } else { - const zero = LengthPercentage.zero(); - const fifty = LengthPercentage{ .percentage = .{ .v = 0.5 } }; - const x_len: ?*const LengthPercentage = x_len: { - switch (this.x) { - .side => |side| { - if (side.side == .left) { - if (side.offset) |*offset| { - if (offset.isZero()) { - break :x_len &zero; - } else { - break :x_len offset; - } - } else { - break :x_len &zero; - } - } - }, - .length => |len| { - if (len.isZero()) { - break :x_len &zero; - } - }, - .center => break :x_len &fifty, - } - break :x_len null; - }; - - const y_len: ?*const LengthPercentage = y_len: { - switch (this.y) { - .side => |side| { - if (side.side == .top) { - if (side.offset) |*offset| { - if (offset.isZero()) { - break :y_len &zero; - } else { - break :y_len offset; - } - } else { - break :y_len &zero; - } - } - }, - .length => |len| { - if (len.isZero()) { - break :y_len &zero; - } - }, - .center => break :y_len &fifty, - } - break :y_len null; - }; - - if (x_len != null and y_len != null) { - try x_len.?.toCss(dest); - try dest.writeStr(" "); - try y_len.?.toCss(dest); - } else { - try this.x.toCss(dest); - try dest.writeStr(" "); - try this.y.toCss(dest); - } - } - } - - pub fn default() @This() { - return .{ - .x = HorizontalPosition{ .length = LengthPercentage{ .percentage = .{ .v = 0.0 } } }, - .y = VerticalPosition{ .length = LengthPercentage{ .percentage = .{ .v = 0.0 } } }, - }; - } - - /// Returns whether both the x and y positions are centered. - pub fn isCenter(this: *const @This()) bool { - return this.x.isCenter() and this.y.isCenter(); - } - - pub fn center() Position { - return .{ .x = .center, .y = .center }; - } - - pub fn eql(this: *const Position, other: *const Position) bool { - return this.x.eql(&other.x) and this.y.eql(&other.y); - } - - pub fn isZero(this: *const Position) bool { - return this.x.isZero() and this.y.isZero(); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -pub fn PositionComponent(comptime S: type) type { - return union(enum) { - /// The `center` keyword. - center, - /// A length or percentage from the top-left corner of the box. - length: LengthPercentage, - /// A side keyword with an optional offset. - side: struct { - /// A side keyword. - side: S, - /// Offset from the side. - offset: ?LengthPercentage, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const @This(), other: *const @This()) bool { - return css.implementEql(@This(), this, other); - } - }, - - const This = @This(); - - pub fn isZero(this: *const This) bool { - if (this.* == .length and this.length.isZero()) return true; - return false; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const This, other: *const This) bool { - return css.implementEql(@This(), this, other); - } - - pub fn parse(input: *css.Parser) Result(This) { - if (input.tryParse( - struct { - fn parse(i: *css.Parser) Result(void) { - return i.expectIdentMatching("center"); - } - }.parse, - .{}, - ).isOk()) { - return .{ .result = .center }; - } - - if (input.tryParse(LengthPercentage.parse, .{}).asValue()) |lp| { - return .{ .result = .{ .length = lp } }; - } - - const side = switch (S.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const offset = input.tryParse(LengthPercentage.parse, .{}).asValue(); - return .{ .result = .{ .side = .{ .side = side, .offset = offset } } }; - } - - pub fn toCss(this: *const @This(), dest: *css.Printer) css.PrintErr!void { - switch (this.*) { - .center => { - if (dest.minify) { - try dest.writeStr("50%"); - } else { - try dest.writeStr("center"); - } - }, - .length => |*lp| try lp.toCss(dest), - .side => |*s| { - try s.side.toCss(dest); - if (s.offset) |lp| { - try dest.writeStr(" "); - try lp.toCss(dest); - } - }, - } - } - - pub fn isCenter(this: *const This) bool { - switch (this.*) { - .center => return true, - .length => |*l| { - if (l.* == .percentage) return l.percentage.v == 0.5; - }, - else => {}, - } - return false; - } - }; -} - -pub const HorizontalPositionKeyword = enum { - /// The `left` keyword. - left, - /// The `right` keyword. - right, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) HorizontalPositionKeyword { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const HorizontalPositionKeyword, other: *const HorizontalPositionKeyword) bool { - return this.* == other.*; - } - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn intoLengthPercentage(this: *const @This()) LengthPercentage { - return switch (this.*) { - .left => LengthPercentage.zero(), - .right => .{ .percentage = .{ .v = 1.0 } }, - }; - } -}; - -pub const VerticalPositionKeyword = enum { - /// The `top` keyword. - top, - /// The `bottom` keyword. - bottom, - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn eql(this: *const VerticalPositionKeyword, other: *const VerticalPositionKeyword) bool { - return this.* == other.*; - } - - pub fn asStr(this: *const @This()) []const u8 { - return css.enum_property_util.asStr(@This(), this); - } - - pub fn parse(input: *css.Parser) Result(@This()) { - return css.enum_property_util.parse(@This(), input); - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - return css.enum_property_util.toCss(@This(), this, dest); - } - - pub fn intoLengthPercentage(this: *const @This()) LengthPercentage { - return switch (this.*) { - .top => LengthPercentage.zero(), - .bottom => LengthPercentage{ .percentage = Percentage{ .v = 1.0 } }, - }; - } -}; - -pub const HorizontalPosition = PositionComponent(HorizontalPositionKeyword); -pub const VerticalPosition = PositionComponent(VerticalPositionKeyword); - -const std = @import("std"); diff --git a/src/css/values/ratio.zig b/src/css/values/ratio.zig deleted file mode 100644 index b3a31f35ec78..000000000000 --- a/src/css/values/ratio.zig +++ /dev/null @@ -1,58 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; - -/// A CSS [``](https://www.w3.org/TR/css-values-4/#ratios) value, -/// representing the ratio of two numeric values. -pub const Ratio = struct { - numerator: CSSNumber, - denominator: CSSNumber, - - pub fn parse(input: *css.Parser) Result(Ratio) { - const first = switch (CSSNumberFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const second = if (input.tryParse(css.Parser.expectDelim, .{'/'}).isOk()) switch (CSSNumberFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } else 1.0; - - return .{ .result = Ratio{ .numerator = first, .denominator = second } }; - } - - /// Parses a ratio where both operands are required. - pub fn parseRequired(input: *css.Parser) Result(Ratio) { - const first = switch (CSSNumberFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (input.expectDelim('/').asErr()) |e| return .{ .err = e }; - const second = switch (CSSNumberFns.parse(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - return .{ .result = Ratio{ .numerator = first, .denominator = second } }; - } - - pub fn toCss(this: *const @This(), dest: *Printer) PrintErr!void { - try CSSNumberFns.toCss(&this.numerator, dest); - if (this.denominator != 1.0) { - try dest.delim('/', true); - try CSSNumberFns.toCss(&this.denominator, dest); - } - } - - pub fn addF32(this: Ratio, _: std.mem.Allocator, other: f32) Ratio { - return .{ .numerator = this.numerator + other, .denominator = this.denominator }; - } - - pub fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return css.implementEql(@This(), lhs, rhs); - } -}; - -const std = @import("std"); diff --git a/src/css/values/rect.zig b/src/css/values/rect.zig deleted file mode 100644 index be0f27e9e291..000000000000 --- a/src/css/values/rect.zig +++ /dev/null @@ -1,143 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const DimensionPercentage = css.css_values.percentage.DimensionPercentage; -const LengthPercentage = css.css_values.length.LengthPercentage; -const LengthOrNumber = css.css_values.length.LengthOrNumber; -const CssColor = css.css_values.color.CssColor; - -fn needsDeinit(comptime T: type) bool { - return switch (T) { - f32, i32, u32, []const u8 => false, - LengthPercentage => true, - LengthOrNumber => true, - css.css_values.percentage.NumberOrPercentage => false, - css.css_properties.border_image.BorderImageSideWidth => true, - *const css.css_values.percentage.DimensionPercentage(css.css_values.length.LengthValue) => true, - CssColor => true, - css.css_properties.border.LineStyle => false, - css.css_properties.border.BorderSideWidth => true, - css.css_values.length.LengthPercentageOrAuto => true, - else => @compileError("Don't know if " ++ @typeName(T) ++ " needs deinit. Please add it to this switch statement."), - }; -} - -/// A generic value that represents a value for four sides of a box, -/// e.g. border-width, margin, padding, etc. -/// -/// When serialized, as few components as possible are written when -/// there are duplicate values. -pub fn Rect(comptime T: type) type { - const needs_deinit = needsDeinit(T); - return struct { - /// The top component. - top: T, - /// The right component. - right: T, - /// The bottom component. - bottom: T, - /// The left component. - left: T, - - const This = @This(); - - pub fn eql(this: *const This, other: *const This) bool { - return css.generic.eql(T, &this.top, &other.top) and css.generic.eql(T, &this.right, &other.right) and css.generic.eql(T, &this.bottom, &other.bottom) and css.generic.eql(T, &this.left, &other.left); - } - - pub fn deepClone(this: *const This, allocator: std.mem.Allocator) This { - if (comptime needs_deinit or T == *const css.css_values.percentage.DimensionPercentage(css.css_values.length.LengthValue)) { - return This{ - .top = this.top.deepClone(allocator), - .right = this.right.deepClone(allocator), - .bottom = this.bottom.deepClone(allocator), - .left = this.left.deepClone(allocator), - }; - } - return This{ - .top = this.top, - .right = this.right, - .bottom = this.bottom, - .left = this.left, - }; - } - - pub fn all(val: T) This { - return This{ - .top = val, - .right = val, - .bottom = val, - .left = val, - }; - } - - pub fn deinit(this: *const This, allocator: std.mem.Allocator) void { - if (comptime needs_deinit) { - this.top.deinit(allocator); - this.right.deinit(allocator); - this.bottom.deinit(allocator); - this.left.deinit(allocator); - } - } - - pub fn parse(input: *css.Parser) Result(This) { - return This.parseWith(input, valParse); - } - - pub fn parseWith(input: *css.Parser, comptime parse_fn: anytype) Result(This) { - const first = switch (parse_fn(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const second = switch (input.tryParse(parse_fn, .{})) { - .result => |v| v, - // - .err => return .{ .result = This{ .top = first, .right = first, .bottom = first, .left = first } }, - }; - const third = switch (input.tryParse(parse_fn, .{})) { - .result => |v| v, - // - .err => return .{ .result = This{ .top = first, .right = second, .bottom = first, .left = second } }, - }; - const fourth = switch (input.tryParse(parse_fn, .{})) { - .result => |v| v, - // - .err => return .{ .result = This{ .top = first, .right = second, .bottom = third, .left = second } }, - }; - // - return .{ .result = This{ .top = first, .right = second, .bottom = third, .left = fourth } }; - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - try css.generic.toCss(T, &this.top, dest); - const same_vertical = css.generic.eql(T, &this.top, &this.bottom); - const same_horizontal = css.generic.eql(T, &this.right, &this.left); - if (same_vertical and same_horizontal and css.generic.eql(T, &this.top, &this.right)) { - return; - } - try dest.writeStr(" "); - try css.generic.toCss(T, &this.right, dest); - if (same_vertical and same_horizontal) { - return; - } - try dest.writeStr(" "); - try css.generic.toCss(T, &this.bottom, dest); - if (same_horizontal) { - return; - } - try dest.writeStr(" "); - try css.generic.toCss(T, &this.left, dest); - } - - pub fn valParse(i: *css.Parser) Result(T) { - return css.generic.parse(T, i); - } - - pub fn isCompatible(this: *const @This(), browsers: css.targets.Browsers) bool { - return this.top.isCompatible(browsers) and this.right.isCompatible(browsers) and this.bottom.isCompatible(browsers) and this.left.isCompatible(browsers); - } - }; -} - -const std = @import("std"); diff --git a/src/css/values/resolution.zig b/src/css/values/resolution.zig deleted file mode 100644 index 68f19075cab8..000000000000 --- a/src/css/values/resolution.zig +++ /dev/null @@ -1,91 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumber = css.css_values.number.CSSNumber; - -/// A CSS `` value. -pub const Resolution = union(enum) { - /// A resolution in dots per inch. - dpi: CSSNumber, - /// A resolution in dots per centimeter. - dpcm: CSSNumber, - /// A resolution in dots per px. - dppx: CSSNumber, - - // ~toCssImpl - const This = @This(); - - pub fn hash(this: *const @This(), hasher: *std.hash.Wyhash) void { - return css.implementHash(@This(), this, hasher); - } - - pub fn eql(this: *const Resolution, other: *const Resolution) bool { - return css.implementEql(@This(), this, other); - } - - pub fn parse(input: *css.Parser) Result(Resolution) { - // TODO: calc? - const location = input.currentSourceLocation(); - const tok = switch (input.next()) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - if (tok.* == .dimension) { - const value = tok.dimension.num.value; - const unit = tok.dimension.unit; - // css.todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "dpi")) return .{ .result = .{ .dpi = value } }; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "dpcm")) return .{ .result = .{ .dpcm = value } }; - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "dppx") or bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "x")) return .{ .result = .{ .dppx = value } }; - return .{ .err = location.newUnexpectedTokenError(.{ .ident = unit }) }; - } - return .{ .err = location.newUnexpectedTokenError(tok.*) }; - } - - pub fn tryFromToken(token: *const css.Token) css.Maybe(Resolution, void) { - switch (token.*) { - .dimension => |dim| { - const value = dim.num.value; - const unit = dim.unit; - // todo_stuff.match_ignore_ascii_case - if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "dpi")) { - return .{ .result = .{ .dpi = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "dpcm")) { - return .{ .result = .{ .dpcm = value } }; - } else if (bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "dppx") or - bun.strings.eqlCaseInsensitiveASCIIICheckLength(unit, "x")) - { - return .{ .result = .{ .dppx = value } }; - } else { - return .{ .err = {} }; - } - }, - else => return .{ .err = {} }, - } - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - const value, const unit = switch (this.*) { - .dpi => |dpi| .{ dpi, "dpi" }, - .dpcm => |dpcm| .{ dpcm, "dpcm" }, - .dppx => |dppx| if (dest.targets.isCompatible(.x_resolution_unit)) - .{ dppx, "x" } - else - .{ dppx, "dppx" }, - }; - - return try css.serializer.serializeDimension(value, unit, dest); - } - - pub fn addF32(this: This, _: std.mem.Allocator, other: f32) Resolution { - return switch (this) { - .dpi => |dpi| .{ .dpi = dpi + other }, - .dpcm => |dpcm| .{ .dpcm = dpcm + other }, - .dppx => |dppx| .{ .dppx = dppx + other }, - }; - } -}; - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/values/size.zig b/src/css/values/size.zig deleted file mode 100644 index 8aa8a4fd638f..000000000000 --- a/src/css/values/size.zig +++ /dev/null @@ -1,76 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const LengthPercentage = css.css_values.length.LengthPercentage; - -/// A generic value that represents a value with two components, e.g. a border radius. -/// -/// When serialized, only a single component will be written if both are equal. -pub fn Size2D(comptime T: type) type { - return struct { - a: T, - b: T, - - fn parseVal(input: *css.Parser) Result(T) { - return switch (T) { - f32 => return CSSNumberFns.parse(input), - LengthPercentage => return LengthPercentage.parse(input), - else => T.parse(input), - }; - } - - pub fn parse(input: *css.Parser) Result(Size2D(T)) { - const first = switch (parseVal(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - const second = input.tryParse(parseVal, .{}).unwrapOr(first); - return .{ .result = Size2D(T){ - .a = first, - .b = second, - } }; - } - - pub fn toCss(this: *const Size2D(T), dest: *css.Printer) css.PrintErr!void { - try valToCss(&this.a, dest); - if (!valEql(&this.b, &this.a)) { - try dest.writeStr(" "); - try valToCss(&this.b, dest); - } - } - - pub fn valToCss(val: *const T, dest: *css.Printer) css.PrintErr!void { - return switch (T) { - f32 => CSSNumberFns.toCss(val, dest), - else => val.toCss(dest), - }; - } - - pub fn isCompatible(this: *const @This(), browsers: bun.css.targets.Browsers) bool { - return this.a.isCompatible(browsers) and this.b.isCompatible(browsers); - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub inline fn valEql(lhs: *const T, rhs: *const T) bool { - return switch (T) { - f32 => lhs.* == rhs.*, - else => lhs.eql(rhs), - }; - } - - pub inline fn eql(lhs: *const @This(), rhs: *const @This()) bool { - return switch (T) { - f32 => lhs.a == rhs.b, - else => lhs.a.eql(&rhs.b), - }; - } - }; -} - -const bun = @import("bun"); -const std = @import("std"); diff --git a/src/css/values/syntax.zig b/src/css/values/syntax.zig deleted file mode 100644 index 4bee62a9cdca..000000000000 --- a/src/css/values/syntax.zig +++ /dev/null @@ -1,524 +0,0 @@ -pub const css = @import("../css_parser.zig"); -const Result = css.Result; -const Printer = css.Printer; -const PrintErr = css.PrintErr; -const CSSNumber = css.css_values.number.CSSNumber; -const CSSNumberFns = css.css_values.number.CSSNumberFns; -const LengthPercentage = css.css_values.length.LengthPercentage; -const Length = css.css_values.length.Length; -const Percentage = css.css_values.percentage.Percentage; -const CssColor = css.css_values.color.CssColor; -const Image = css.css_values.image.Image; -const Url = css.css_values.url.Url; -const CSSInteger = css.css_values.number.CSSInteger; -const CSSIntegerFns = css.css_values.number.CSSIntegerFns; -const Angle = css.css_values.angle.Angle; -const Time = css.css_values.time.Time; -const Resolution = css.css_values.resolution.Resolution; -const CustomIdent = css.css_values.ident.CustomIdent; -const CustomIdentFns = css.css_values.ident.CustomIdentFns; -const Ident = css.css_values.ident.Ident; - -// https://drafts.csswg.org/css-syntax-3/#whitespace -const SPACE_CHARACTERS: []const u8 = &.{ 0x20, 0x09 }; - -/// A CSS [syntax string](https://drafts.css-houdini.org/css-properties-values-api/#syntax-strings) -/// used to define the grammar for a registered custom property. -pub const SyntaxString = union(enum) { - /// A list of syntax components. - components: ArrayList(SyntaxComponent), - /// The universal syntax definition. - universal, - - const This = @This(); - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } - - pub fn toCss(this: *const This, dest: *Printer) PrintErr!void { - try dest.writeChar('"'); - switch (this.*) { - .universal => try dest.writeChar('*'), - .components => |*components| { - var first = true; - for (components.items) |*component| { - if (first) { - first = false; - } else { - try dest.delim('|', true); - } - - try component.toCss(dest); - } - }, - } - - return dest.writeChar('"'); - } - - pub fn parse(input: *css.Parser) Result(SyntaxString) { - const string = switch (input.expectString()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - const result = SyntaxString.parseString(input.allocator(), string); - if (result.isErr()) return .{ .err = input.newCustomError(css.ParserError.invalid_value) }; - return .{ .result = result.result }; - } - - /// Parses a syntax string. - pub fn parseString(allocator: std.mem.Allocator, input: []const u8) css.Maybe(SyntaxString, void) { - // https://drafts.css-houdini.org/css-properties-values-api/#parsing-syntax - var trimmed_input = std.mem.trimLeft(u8, input, SPACE_CHARACTERS); - if (trimmed_input.len == 0) { - return .{ .err = {} }; - } - - if (bun.strings.eqlComptime(trimmed_input, "*")) { - return .{ .result = SyntaxString.universal }; - } - - var components = ArrayList(SyntaxComponent){}; - - // PERF(alloc): count first? - while (true) { - const component = switch (SyntaxComponent.parseString(&trimmed_input)) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - components.append( - allocator, - component, - ) catch |err| bun.handleOom(err); - - trimmed_input = std.mem.trimLeft(u8, trimmed_input, SPACE_CHARACTERS); - if (trimmed_input.len == 0) { - break; - } - - if (bun.strings.startsWithChar(trimmed_input, '|')) { - trimmed_input = trimmed_input[1..]; - continue; - } - - return .{ .err = {} }; - } - - return .{ .result = SyntaxString{ .components = components } }; - } - - /// Parses a value according to the syntax grammar. - pub fn parseValue(this: *const SyntaxString, input: *css.Parser) Result(ParsedComponent) { - switch (this.*) { - .universal => return .{ .result = ParsedComponent{ - .token_list = switch (css.css_properties.custom.TokenList.parse( - input, - &css.ParserOptions.default(input.allocator(), null), - 0, - )) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }, - } }, - .components => |components| { - // Loop through each component, and return the first one that parses successfully. - for (components.items) |component| { - const state = input.state(); - // PERF: deinit this on error - var parsed = ArrayList(ParsedComponent){}; - - while (true) { - const value_result = input.tryParse(struct { - fn parse( - i: *css.Parser, - comp: SyntaxComponent, - ) Result(ParsedComponent) { - const value = switch (comp.kind) { - .length => ParsedComponent{ .length = switch (Length.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .number => ParsedComponent{ .number = switch (CSSNumberFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .percentage => ParsedComponent{ .percentage = switch (Percentage.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .length_percentage => ParsedComponent{ .length_percentage = switch (LengthPercentage.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .color => ParsedComponent{ .color = switch (CssColor.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .image => ParsedComponent{ .image = switch (Image.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .url => ParsedComponent{ .url = switch (Url.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .integer => ParsedComponent{ .integer = switch (CSSIntegerFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .angle => ParsedComponent{ .angle = switch (Angle.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .time => ParsedComponent{ .time = switch (Time.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .resolution => ParsedComponent{ .resolution = switch (Resolution.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .transform_function => ParsedComponent{ .transform_function = switch (css.css_properties.transform.Transform.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .transform_list => ParsedComponent{ .transform_list = switch (css.css_properties.transform.TransformList.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .custom_ident => ParsedComponent{ .custom_ident = switch (CustomIdentFns.parse(i)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - } }, - .literal => |value| blk: { - const location = i.currentSourceLocation(); - const ident = switch (i.expectIdent()) { - .result => |v| v, - .err => |e| return .{ .err = e }, - }; - if (!bun.strings.eql(ident, value)) { - return .{ .err = location.newUnexpectedTokenError(.{ .ident = ident }) }; - } - break :blk ParsedComponent{ .literal = .{ .v = ident } }; - }, - }; - return .{ .result = value }; - } - }.parse, .{component}); - - if (value_result.asValue()) |value| { - switch (component.multiplier) { - .none => return .{ .result = value }, - .space => { - bun.handleOom(parsed.append(input.allocator(), value)); - if (input.isExhausted()) { - return .{ .result = ParsedComponent{ .repeated = .{ - .components = parsed, - .multiplier = component.multiplier, - } } }; - } - }, - .comma => { - bun.handleOom(parsed.append(input.allocator(), value)); - if (input.next().asValue()) |token| { - if (token.* == .comma) continue; - break; - } else { - return .{ .result = ParsedComponent{ .repeated = .{ - .components = parsed, - .multiplier = component.multiplier, - } } }; - } - }, - } - } else { - break; - } - } - - input.reset(&state); - } - - return .{ .err = input.newErrorForNextToken() }; - }, - } - } -}; - -/// A [syntax component](https://drafts.css-houdini.org/css-properties-values-api/#syntax-component) -/// within a [SyntaxString](SyntaxString). -/// -/// A syntax component consists of a component kind an a multiplier, which indicates how the component -/// may repeat during parsing. -pub const SyntaxComponent = struct { - kind: SyntaxComponentKind, - multiplier: Multiplier, - - pub fn parseString(input: *[]const u8) css.Maybe(SyntaxComponent, void) { - const kind = switch (SyntaxComponentKind.parseString(input)) { - .result => |vv| vv, - .err => |e| return .{ .err = e }, - }; - - // Pre-multiplied types cannot have multipliers. - if (kind == .transform_list) { - return .{ .result = SyntaxComponent{ - .kind = kind, - .multiplier = .none, - } }; - } - - var multiplier: Multiplier = .none; - if (bun.strings.startsWithChar(input.*, '+')) { - input.* = input.*[1..]; - multiplier = .space; - } else if (bun.strings.startsWithChar(input.*, '#')) { - input.* = input.*[1..]; - multiplier = .comma; - } - - return .{ .result = SyntaxComponent{ .kind = kind, .multiplier = multiplier } }; - } - - pub fn toCss(this: *const SyntaxComponent, dest: *Printer) PrintErr!void { - try this.kind.toCss(dest); - return switch (this.multiplier) { - .none => {}, - .comma => dest.writeChar('#'), - .space => dest.writeChar('+'), - }; - } - - pub fn deepClone(this: *const @This(), allocator: std.mem.Allocator) @This() { - return css.implementDeepClone(@This(), this, allocator); - } -}; - -/// A [syntax component component name](https://drafts.css-houdini.org/css-properties-values-api/#supported-names). -pub const SyntaxComponentKind = union(enum) { - /// A `` component. - length, - /// A `` component. - number, - /// A `` component. - percentage, - /// A `` component. - length_percentage, - /// A `` component. - color, - /// An `` component. - image, - /// A `` component. - url, - /// An `` component. - integer, - /// An `` component. - angle, - /// A `