diff --git a/packages/meta-css/src/api.ts b/packages/meta-css/src/api.ts index cb1c9b1cd2..651e87014d 100644 --- a/packages/meta-css/src/api.ts +++ b/packages/meta-css/src/api.ts @@ -148,6 +148,10 @@ export const ARG_NO_HEADER = { noHeader: flag({ desc: "Don't emit generated header comment" }), }; +export const ARG_SCOPE = { + scope: string({ desc: "Suffix for CSS class names" }), +}; + export const ARG_WATCH = { watch: flag({ alias: "w", diff --git a/packages/meta-css/src/convert.ts b/packages/meta-css/src/convert.ts index f976d8c70d..bc3bf88f12 100644 --- a/packages/meta-css/src/convert.ts +++ b/packages/meta-css/src/convert.ts @@ -11,7 +11,7 @@ import { QUOTED_FNS, at_media, css, - type Format, + type CSSOpts, } from "@thi.ng/hiccup-css"; import { type ILogger } from "@thi.ng/logger"; import { sync } from "@thi.ng/rstream"; @@ -28,6 +28,7 @@ import { ARG_NO_HEADER, ARG_OUTPUT, ARG_PRETTY, + ARG_SCOPE, ARG_SPECS, ARG_WATCH, type AppCtx, @@ -44,16 +45,17 @@ import { type State = "sel" | "class" | "nest"; export interface ConvertOpts extends CommonOpts { - out?: string; - specs: string; - include?: string[]; + bundle: boolean; eval?: string; force?: string[]; - bundle: boolean; - pretty: boolean; + include?: string[]; noDecls: boolean; noHeader: boolean; noWrite: boolean; + out?: string; + pretty: boolean; + scope?: string; + specs: string; watch: boolean; } @@ -71,12 +73,12 @@ interface ProcessCtx { } export interface ProcessOpts { + css: Partial; logger: ILogger; - format: Format; - specs: CompiledSpecs; - plainRules: IObjectOf>; mediaQueryIDs: Set; mediaQueryRules: IObjectOf>>; + plainRules: IObjectOf>; + specs: CompiledSpecs; } export const CONVERT: Command> = { @@ -84,12 +86,13 @@ export const CONVERT: Command> = { opts: { ...ARG_BUNDLE, ...ARG_EVAL, - ...ARG_NO_DECLS, ...ARG_FORCE_INCLUDE, ...ARG_INCLUDE, + ...ARG_NO_DECLS, ...ARG_NO_HEADER, ...ARG_OUTPUT, ...ARG_PRETTY, + ...ARG_SCOPE, ...ARG_SPECS, ...ARG_WATCH, noWrite: flag({ desc: "Don't write files, use stdout only" }), @@ -261,7 +264,7 @@ const watchBundleInputs = async ( export const processInputs = ( { logger, - opts: { include, noDecls, noHeader, pretty }, + opts: { include, noDecls, noHeader, pretty, scope }, }: Pick>, "logger" | "opts">, specs: CompiledSpecs, forceRules: ReturnType, @@ -271,7 +274,7 @@ export const processInputs = ( const procOpts: ProcessOpts = { logger, specs, - format: pretty ? PRETTY : COMPACT, + css: { format: pretty ? PRETTY : COMPACT, fns: QUOTED_FNS, scope }, mediaQueryIDs: new Set(Object.keys(specs.media)), mediaQueryRules: { ...forceRules.mediaQueryRules }, plainRules: { ...forceRules.plainRules }, @@ -281,9 +284,7 @@ export const processInputs = ( : []; if (!noHeader) bundle.push(generateHeader(specs)); if (!noDecls && specs.decls.length) { - bundle.push( - css(specs.decls, { format: procOpts.format, fns: QUOTED_FNS }) - ); + bundle.push(css(specs.decls, procOpts.css)); } inputs.forEach((input) => processSpec(input, procOpts)); processPlainRules(bundle, procOpts); @@ -293,27 +294,24 @@ export const processInputs = ( export const processMediaQueries = ( result: string[], - { logger, specs, format, mediaQueryRules }: ProcessOpts + { css: opts, logger, mediaQueryRules, specs }: ProcessOpts ) => { for (let queryID in mediaQueryRules) { const rules = buildDecls(mediaQueryRules[queryID], specs); logger.debug("mediaquery rules", queryID, rules); result.push( - css(at_media(mergeMediaQueries(specs.media, queryID), rules), { - format, - fns: QUOTED_FNS, - }) + css(at_media(mergeMediaQueries(specs.media, queryID), rules), opts) ); } }; export const processPlainRules = ( bundle: string[], - { logger, specs, format, plainRules }: ProcessOpts + { css: opts, logger, plainRules, specs }: ProcessOpts ) => { const rules = buildDecls(plainRules, specs); logger.debug("plain rules", rules); - bundle.push(css(rules, { format, fns: QUOTED_FNS })); + bundle.push(css(rules, opts)); }; export const processForceIncludes = ( diff --git a/packages/meta-css/src/develop.ts b/packages/meta-css/src/develop.ts index c3168cee38..8b1cdc9bf4 100644 --- a/packages/meta-css/src/develop.ts +++ b/packages/meta-css/src/develop.ts @@ -9,6 +9,7 @@ import { ARG_NO_HEADER, ARG_PREC, ARG_PRETTY, + ARG_SCOPE, ARG_WATCH, type AppCtx, type CommonOpts, @@ -36,6 +37,7 @@ export const DEVELOP: Command> = { ...ARG_NO_HEADER, ...ARG_PREC, ...ARG_PRETTY, + ...ARG_SCOPE, ...ARG_WATCH, outCss: string({ desc: "Output file for CSS bundle", @@ -69,6 +71,7 @@ export const DEVELOP: Command> = { ...opts, noWrite: false, out: opts.outCss, + scope: opts.scope, specs: opts.outSpecs, }, }; diff --git a/packages/meta-css/src/doc.ts b/packages/meta-css/src/doc.ts index 1275779816..e108e89b18 100644 --- a/packages/meta-css/src/doc.ts +++ b/packages/meta-css/src/doc.ts @@ -20,8 +20,8 @@ import { maybeWriteText } from "./utils.js"; interface DocOpts extends CommonOpts { out?: string; level: number; - title?: string; // noDecls: boolean; + title?: string; } export const DOC: Command> = { @@ -32,8 +32,7 @@ export const DOC: Command> = { level: int({ alias: "l", desc: "Initial heading level", default: 1 }), title: string({ alias: "t", - desc: "Main title, set to 'none' to disable", - default: "meta", + desc: "Custom main title, set to NONE to disable", }), }, inputs: 1, @@ -73,10 +72,8 @@ export const generateDocs = ( "", ]; - if (title !== "none") { - doc.unshift( - `${__hd(level)} ${title === "meta" ? specs.info.name : title}\n` - ); + if (title !== "NONE") { + doc.unshift(`${__hd(level)} ${title ?? specs.info.name}\n`); } return doc; }; diff --git a/packages/meta-css/src/export.ts b/packages/meta-css/src/export.ts index 803c067fe4..bd60707f4b 100644 --- a/packages/meta-css/src/export.ts +++ b/packages/meta-css/src/export.ts @@ -1,7 +1,14 @@ // thing:no-export import type { Command } from "@thi.ng/args"; import { readJSON, readText } from "@thi.ng/file-io"; -import { COMPACT, PRETTY, QUOTED_FNS, at_media, css } from "@thi.ng/hiccup-css"; +import { + COMPACT, + PRETTY, + QUOTED_FNS, + at_media, + css, + type CSSOpts, +} from "@thi.ng/hiccup-css"; import type { ILogger } from "@thi.ng/logger"; import { resolve } from "node:path"; import { @@ -12,6 +19,7 @@ import { ARG_ONLY_DECLS, ARG_OUTPUT, ARG_PRETTY, + ARG_SCOPE, type AppCtx, type CommonOpts, type CompiledSpecs, @@ -19,13 +27,14 @@ import { import { generateHeader, maybeWriteText, withoutInternals } from "./utils.js"; interface ExportOpts extends CommonOpts { - out?: string; - pretty: boolean; - noDecls: boolean; - onlyDecls: boolean; - noHeader: boolean; include?: string[]; media?: string[]; + noDecls: boolean; + noHeader: boolean; + onlyDecls: boolean; + out?: string; + pretty: boolean; + scope?: string; } export const EXPORT: Command> = { @@ -38,29 +47,39 @@ export const EXPORT: Command> = { ...ARG_PRETTY, ...ARG_NO_HEADER, ...ARG_MEDIA_QUERIES, + ...ARG_SCOPE, }, inputs: 1, fn: async (ctx) => { const { logger, - opts: { include, media, noDecls, noHeader, onlyDecls, pretty, out }, + opts: { + include, + media, + noDecls, + noHeader, + onlyDecls, + out, + pretty, + scope, + }, inputs, } = ctx; + const cssOpts: Partial = { + format: pretty ? PRETTY : COMPACT, + fns: QUOTED_FNS, + scope, + }; const specs = readJSON(resolve(inputs[0]), logger); const bundle: string[] = include ? include.map((x) => readText(resolve(x), logger).trim()) : []; if (!noHeader) bundle.push(generateHeader(specs)); if (!noDecls && specs.decls.length) { - bundle.push( - css(specs.decls, { - format: pretty ? PRETTY : COMPACT, - fns: QUOTED_FNS, - }) - ); + bundle.push(css(specs.decls, cssOpts)); } if (!onlyDecls) { - bundle.push(serializeSpecs(specs, media, pretty, logger)); + bundle.push(serializeSpecs(specs, media, cssOpts, logger)); } maybeWriteText(out, bundle, logger); }, @@ -69,7 +88,7 @@ export const EXPORT: Command> = { export const serializeSpecs = ( specs: CompiledSpecs, media: string[] | undefined, - pretty: boolean, + opts: Partial, logger: ILogger ) => { const rules: any[] = __suffixed("", specs); @@ -86,7 +105,7 @@ export const serializeSpecs = ( } } } - return css(rules, { format: pretty ? PRETTY : COMPACT, fns: QUOTED_FNS }); + return css(rules, opts); }; /** @internal */