mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 03:18:53 +00:00
No longer needed after zig upgrade --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
460 lines
17 KiB
Zig
460 lines
17 KiB
Zig
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("<error writing declaration block: {s}>\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,
|
|
};
|
|
errdefer decl_parser.deinit();
|
|
|
|
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;
|
|
}
|
|
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;
|