packages/meta-css/src/utils.ts
// thing:no-export
import type { Maybe } from "@thi.ng/api";
import { isString } from "@thi.ng/checks";
import { readText, writeText } from "@thi.ng/file-io";
import type { ILogger } from "@thi.ng/logger";
import { Stream, reactive, sync } from "@thi.ng/rstream";
import { Z4 } from "@thi.ng/strings";
import { assocObj, map } from "@thi.ng/transducers";
import { watch } from "node:fs";
import { resolve } from "node:path";
import type { CompiledSpec, CompiledSpecs } from "./api.js";
export const maybeWriteText = (
out: Maybe<string>,
body: string | string[],
logger: ILogger
) => {
body = isString(body) ? body : body.join("\n");
out
? writeText(resolve(out), body, logger)
: process.stdout.write(body + "\n");
};
export const generateHeader = ({ info: { name, version } }: CompiledSpecs) =>
`/*! ${name} v${version} - generated by thi.ng/meta-css @ ${new Date().toISOString()} */`;
export const watchInputs = (paths: string[], logger: ILogger) => {
const close = () => {
logger.info("closing watchers...");
inputs.forEach((i) => i.watcher.close());
};
const inputs = paths.map((file, i) => {
file = resolve(file);
const input = reactive(readText(file, logger), {
id: `in${Z4(i)}`,
});
return {
input,
watcher: watch(file, {}, (event) => {
if (event === "change") {
try {
input.next(readText(file, logger));
} catch (e) {
logger.warn((<Error>e).message);
close();
}
} else {
logger.warn(`input removed:`, file);
close();
}
}),
};
});
// close watchers when ctrl-c is pressed
process.on("SIGINT", close);
return sync({
src: assocObj<Stream<string>>(
map(
({ input }) => <[string, Stream<string>]>[input.id, input],
inputs
)
),
});
};
/** @internal */
export const withoutInternals = (props: CompiledSpec) =>
Object.keys(props).reduce((acc, k) => {
if (!k.startsWith("__")) acc[k] = props[k];
return acc;
}, <CompiledSpec>{});