@teacss/bun 0.9.3 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,65 +1,41 @@
1
1
  # @teacss/bun
2
2
 
3
- Bun Build integration for TeaCSS.
3
+ The `Bun.build` plugin for TeaCSS. It calls the Rust engine (`@teacss/engine`) in process and turns `virtual:teacss.css`, or a CSS entry's `@teacss;`, into the generated CSS. It needs Bun 1.4 or later.
4
+
5
+ ## Install
4
6
 
5
7
  ```sh
6
- bun add --dev teacss @teacss/bun
8
+ bun add --dev @teacss/bun
7
9
  ```
8
10
 
11
+ ## Use
12
+
9
13
  ```ts
10
- import { pluginTeacss } from "@teacss/bun";
14
+ // build.ts, run with `bun build.ts`
15
+ import { teacss } from "@teacss/bun";
11
16
 
12
- await Bun.build({
13
- entrypoints: ["./src/index.ts"],
14
- outdir: "./dist",
15
- plugins: [pluginTeacss()],
16
- });
17
+ await Bun.build({ entrypoints: ["./src/index.ts"], outdir: "./dist", plugins: [teacss()] });
17
18
  ```
18
19
 
19
- Import `virtual:teacss.css` from the application. `pluginTeacss()` is for a
20
- one-shot build because Bun's plugin API does not expose watch invalidation.
21
-
22
- For programmatic watch builds, use `watchTeacssBuild`:
23
-
24
- ```ts
25
- import { watchTeacssBuild } from "@teacss/bun";
26
-
27
- const session = await watchTeacssBuild(
28
- { entrypoints: ["./src/index.ts"], outdir: "./dist" },
29
- {
30
- configOrPath: "./index.css",
31
- onError: (error) => console.error(error),
32
- },
33
- );
20
+ Configuration lives in a CSS entry. Create `index.css` at the project root:
34
21
 
35
- await session.dispose();
22
+ ```css
23
+ @presets "standard,icons,official";
24
+ @source "./src/**/*.{js,jsx,ts,tsx,html}";
25
+ @teacss;
36
26
  ```
37
27
 
38
- The session exposes the latest successful `result`, current `error`, and
39
- successful-build `version`. Failed rebuilds preserve the last valid result and
40
- continue watching configuration, module, entry, and positive `@source` roots.
41
- `dispose()` waits for active work and is safe to call more than once.
28
+ Import the generated CSS once from the application entry, either as `virtual:teacss.css` or as the entry itself:
42
29
 
43
- Bun versions before 1.3.6 cannot expose extra module-graph inputs through a
44
- metafile, so watch coverage is limited to entries, TeaCSS configuration, and
45
- `@source` roots.
30
+ ```ts
31
+ // src/index.ts
32
+ import "virtual:teacss.css";
33
+ ```
46
34
 
47
- Pre-1.0. Source compile-class transformers are not run by this adapter.
35
+ With `outdir` set, the Standard preset's fonts are written to `teacss-fonts/` beside the CSS. `watch(options, onBuild)` reruns `Bun.build` when a project file changes.
48
36
 
49
- Watch sessions update source-scanned shortcuts and safelists through file and
50
- source-root creation, removal, and recreation, including external absolute
51
- sources. Changes during configuration loading or a build cause another build
52
- before the session settles.
37
+ ## Documentation
53
38
 
54
- Glob-matched CSS file symlinks observe their physical file targets through
55
- filtered shallow parent watches, including recovery after a failed member read.
56
- A bounded declaration check every 500 ms also recovers changes omitted by native
57
- callbacks; unchanged declarations do not reload configuration or rebuild.
58
- Nested source directory symlinks observe physical target changes, including empty
59
- targets and target deletion or recreation. Missing routes use shallow parent
60
- observation. Failed reads retain the last accepted configuration. An initial
61
- failed declaration read also keeps its source routes watched, so repairing the
62
- source can produce the first build without touching the entry. If native watch
63
- creation fails with `EACCES`, successful desired watches remain active, including
64
- shallow recovery sentinels. The original error is reported; repeated failure
65
- alone does not keep retrying.
39
+ - [Build integrations](https://github.com/teacss/teacss-rs/blob/master/skills/teacss/references/integrations.md) and [their options](https://github.com/teacss/teacss-rs/blob/master/skills/teacss/references/integrations.md#options)
40
+ - [The CSS entry](https://github.com/teacss/teacss-rs/blob/master/skills/teacss/references/setup.md#css-entry)
41
+ - [The TeaCSS skill](https://github.com/teacss/teacss-rs/blob/master/skills/teacss/SKILL.md) for syntax, presets and tooling
package/dist/index.d.ts CHANGED
@@ -1,50 +1,32 @@
1
- import { UserConfig, UserConfigDefaults } from "@teacss/core";
2
- import { BuildConfig, BuildOutput, BunPlugin } from "bun";
3
- //#region src/index.d.ts
1
+ import { type ShellOptions } from "@teacss/engine";
2
+ import type { BuildConfig, BuildOutput, BunPlugin } from "bun";
3
+ export type { ShellOptions } from "@teacss/engine";
4
4
  /**
5
- * Bun plugin for TeaCSS. Use it with `Bun.build` (or a `bunfig.toml` preload):
6
- *
7
- * ```ts
8
- * import { pluginTeacss } from "@teacss/bun";
9
- * await Bun.build({ entrypoints: ["./src/index.ts"], plugins: [pluginTeacss()] });
10
- * ```
11
- *
12
- * - `import "virtual:teacss.css"` (or `"teacss.css"`) resolves to the generated
13
- * utilities — scanned from the project's content (the CSS entry's `@source`,
14
- * else the default globs).
15
- * - every `.css` gets `@apply` / `@screen` / `theme()` / `icon()` inlined (the
16
- * directive transformer fast-bails when none are present).
17
- *
18
- * Configuration comes from the CSS entry (`index.css` with `@presets` / `@source`
19
- * / `@custom`) or an inline `UserConfig` — there is no `teacss.config.*` file.
20
- * Like `@teacss/rsbuild`, this path does not run source transformers (so the
21
- * `:css:` compile-class transform is not applied here).
5
+ * v10.2 §3.4. `import "virtual:teacss.css"` (or `"teacss.css"`) becomes the generated stylesheet; every other
6
+ * module goes through `project.transform`, and in a CSS file whose top level has `@teacss;` the generated
7
+ * stylesheet then takes that rule's place. `minify` defaults to false, as teacss-ts's Bun plugin emits the
8
+ * stylesheet unminified.
22
9
  */
23
- export declare function pluginTeacss(configOrPath?: UserConfig<object> | string, defaults?: UserConfigDefaults): BunPlugin;
24
- export interface WatchTeacssBuildOptions {
25
- /** CSS entry file, discovery root, or inline configuration. */
26
- configOrPath?: UserConfig<object> | string;
27
- /** Defaults merged below the resolved TeaCSS configuration. */
28
- defaults?: UserConfigDefaults;
29
- /** Filesystem event coalescing delay. @default 50 */
30
- debounce?: number;
31
- onBuild?: (result: BuildOutput) => void | Promise<void>;
32
- onError?: (error: unknown) => void | Promise<void>;
10
+ export declare function teacss(options?: ShellOptions): BunPlugin;
11
+ export interface WatchOptions {
12
+ /** The `Bun.build` configuration; a plugin of this package already in `plugins` is replaced. */
13
+ build: BuildConfig;
14
+ shell?: ShellOptions;
15
+ /** Milliseconds between the last file event and the rebuild. Default 200. */
16
+ debounce?: number;
17
+ /** Called with a failed build's error or a watcher error. Default `console.error`. */
18
+ onError?: (error: unknown) => void;
33
19
  }
34
- export interface TeacssBuildWatchSession {
35
- /** Latest background rebuild error, cleared by the next successful build. */
36
- readonly error: unknown | undefined;
37
- /** Latest successful build result, or undefined until the first success. */
38
- readonly result: BuildOutput | undefined;
39
- /** Number of successful builds. */
40
- readonly version: number;
41
- /** Stop this session without affecting other watch sessions. */
42
- dispose(): Promise<void>;
20
+ export interface WatchSession {
21
+ /** Successful builds so far, the first one included. */
22
+ readonly builds: number;
23
+ close(): void;
43
24
  }
44
25
  /**
45
- * Rebuild with Bun when either Bun's module graph or TeaCSS's graph-external
46
- * config and `@source` inputs change. Bun 1.3's plugin API has no dependency
47
- * registration or invalidation hook, so watch ownership lives in this helper.
26
+ * Builds once, then rebuilds whenever a file in a directory of `project.watchFiles()` (or the root) changes,
27
+ * or a file anywhere under a `@source` glob's directory (`project.sourceDirectories()`), outside `outdir`.
28
+ * Bun's plugin API has no dependency registration, so the watch owns the file list; it resolves after the
29
+ * first build has been reported.
48
30
  */
49
- export declare function watchTeacssBuild(buildConfig: BuildConfig, options?: WatchTeacssBuildOptions): Promise<TeacssBuildWatchSession>;
50
- //#endregion
31
+ export declare function watch(options: WatchOptions, onBuild: (result: BuildOutput) => void | Promise<void>): Promise<WatchSession>;
32
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1 +1,188 @@
1
- import{AsyncLocalStorage as e}from"node:async_hooks";import{existsSync as t,watch as n}from"node:fs";import{mkdir as r,readFile as i,stat as a,writeFile as o}from"node:fs/promises";import{dirname as s,isAbsolute as c,join as l,resolve as u}from"node:path";import d from"node:process";import{entryDiscoveryFiles as f}from"@teacss/config";import{SourceWatchRegistry as p,createSourceDeclarationCheck as m,planSourceWatches as h,probeSourceDeclarations as g,scanSourceFiles as _,sourceDeclarationStateOf as v,sourceDeclarationWatchTargets as y,sourceWatchTargets as b}from"@teacss/config/internal/source-scan";import x from"@teacss/directives";import{applyTransformerPipeline as S,createContext as C,defaultFilesystemGlobs as w}from"@teacss/runtime";import{bundledAssetName as T,rewriteBundledAssets as E}from"@teacss/runtime/internal/bundled-assets";import{enableNodeCompileCache as ee}from"@teacss/runtime/internal/compile-cache";import{DEFAULT_SOURCE_IGNORE as D,generateSources as O}from"@teacss/runtime/source-generation";function te(e,t,n=Bun.version){let r={...e};return delete r.metafile,Bun.semver.satisfies(n,`>=1.3.6`)&&(r.metafile=!0),{...r,plugins:t}}ee();const k=/^(?:virtual:)?teacss\.css$/,A=/\.css$/,j=`teacss`;function ne(e){return e===void 0?{globs:w,ignore:D}:{globs:e,ignore:[]}}function re(e,t={}){return{name:`teacss`,async setup(n){let a=C(e,{...t,transformers:[...t.transformers??[],x()]}),c=n.config.root??d.cwd();await a.updateRoot(c);let u=new Set,f=new Set,p=!0,m=new Map;async function h(e){return n.config.outdir?(await E(e,e=>(m.set(e.digest,e),`./teacss-fonts/${T(e)}`))).toString():e}n.config.outdir&&(n.onResolve({filter:/^\.\/teacss-fonts\/teacss-[a-f0-9]{64}\.woff2$/},e=>{let t=e.path.slice(15);if([...m.values()].some(e=>T(e)===t))return{path:e.path,external:!0}}),n.onEnd(async e=>{if(e.success)for(let t of e.outputs){if(!t.path.endsWith(`.css`))continue;let e=await t.text(),n=l(s(t.path),`teacss-fonts`);for(let t of m.values()){let i=T(t);e.includes(`teacss-fonts/${i}`)&&(await r(n,{recursive:!0}),await o(l(n,i),t.bytes))}}}));function g(){let e=a.getConfigFileList()[0];return e?s(e):c}async function v(e){let t=e();u.add(t);try{return await t}finally{u.delete(t)}}n.onStart(async()=>{if(p){p=!1;return}await Promise.allSettled(u),m.clear();for(let e of f)await a.extract(``,e);f.clear(),await a.reloadConfig()}),n.onResolve({filter:k},()=>({path:`teacss.css`,namespace:j})),n.onLoad({filter:/.*/,namespace:j},()=>v(async()=>{let{globs:e,ignore:t}=ne((await a.getConfig()).content?.filesystem),n=await _(e,{cwd:g(),ignore:t,expandDirectories:!0}),{css:r}=await O(a.generator,n,void 0,{minify:!1});return{contents:await h(r),loader:`css`}})),n.onLoad({filter:A},e=>v(async()=>{let t=await i(e.path,`utf8`);return f.add(e.path),{contents:await h((await S(a,t,e.path))?.code??t),loader:`css`}}))}}}function ie(e){return`${e.mtimeMs}:${e.ctimeMs}:${e.size}:${e.ino}`}async function M(r,i={}){let o=u(r.root??d.cwd()),l=r.entrypoints.map(e=>c(e)?e:u(o,e)),{configOrPath:x,defaults:S={},debounce:T=50,onBuild:E,onError:ee}=i,D=C(x,S),O=new Set,k=!1,A=!1,j,M,N=!1,P,F=!1,I=!1,L=0,R=!1,z=``,B=new Set,V,ae,H=0,U=new Set,oe=new e;function W(){let e=D.getConfigFileList()[0];return e?s(e):o}async function G(){let{globs:e,ignore:t}=ne(D.generator.config.content?.filesystem);return await _(e,{cwd:W(),ignore:t,expandDirectories:!0})}function se(e){let t=e.content?.filesystem;if(!t)return e;let n=W();return{...e,content:{...e.content,filesystem:t.map(e=>e.startsWith(`!`)?`!${u(n,e.slice(1))}`:u(n,e))}}}function K(e,t,n){if(!t)return Promise.resolve();let r={active:!0},i;return i=oe.run(r,()=>Promise.resolve().then(()=>t(n)).catch(t=>console.error(`[@teacss/bun] watch ${e} callback failed:`,t)).finally(()=>{r.active=!1,U.delete(i)})),U.add(i),i}async function ce(){for(;U.size>0;)await Promise.all(U)}function q(e){return A?Promise.resolve():(V=e,K(`error`,ee,e))}function le(e,t=O){let n=[...D.getConfigFileList(),...l,...t,...e].map(e=>({kind:`exact`,path:e}));if(typeof x!=`object`){let e=typeof x==`string`?u(o,x):o;if(e.endsWith(`.css`))n.push({kind:`exact`,path:e});else for(let t of f)n.push({kind:`exact`,path:u(e,t)})}return n.push(...b(D.generator.config.content?.filesystem??w,W(),!0)),n.push(...y(v(D))),n}function J(e,t=O){return new Set([...D.getConfigFileList(),...l,...t,...e])}async function Y(e){let t=new Set(e.flatMap(e=>[...e])),n=new Map(await Promise.all([...t].map(async e=>{try{return[e,`${e}:${ie(await a(e))}`]}catch(t){if(t.code===`ENOENT`)return[e,`${e}:missing`];throw t}})));return e.map(e=>[...e].sort().map(e=>n.get(e)).join(`|`))}async function ue(e,t=O){return(await Y([J(e,t)]))[0]}let de=new p((e,t,r)=>n(e,{recursive:r},t),e=>{if(e!==void 0&&B.has(e)&&L++,!F){I=!0;return}$()},e=>{q(e)});function X(e,t=O){de.reconcile(h(le(e,t))),B=J(e,t)}function fe(e,t,n){return AggregateError([e,t],n)}function pe(e,n){return new Set(Object.keys(e.metafile?.inputs??{}).map(e=>c(e)?e:u(o,e)).filter(e=>!n||t(e)))}let Z,Q;async function me(e,t=O){if(A)return;let n=e,r=[];try{r=await G()}catch(e){n=fe(n,e,`TeaCSS build and source discovery failed`)}if(!A){try{X(r,t);let e=v(D),n=await g(e,!0,Z);Q=n,(await g(e)).signature!==n.signature&&(R=!0,F?N=!0:I=!0)}catch(e){n=fe(n,e,`TeaCSS build and watcher reconciliation failed`)}await q(n)}}async function he(){if(A)return;Z=await g(v(D));let e=L,t=new Set(B),[n]=await Y([t]);if(k?await D.reloadConfig():(k=!0,await D.updateRoot(o)),A)return;let i=await G();if(A||(X(i),A))return;let a=v(D),s=await g(a,!0,Z);Q=s;let c=await g(a),l=s.signature!==c.signature,[u]=await Y([t]),d=n!==u||l,f=await ue(i);if(A)return;let p=R;if(R=!1,!p&&!d&&H>0&&V===void 0&&f===z)return;let m=se(await D.getConfig());if(A)return;let h=[...(r.plugins??[]).filter(e=>e.name!==`teacss`),re(m)],_=await Bun.build(te(r,h));if(A)return;if(!_.success){await me(_,new Set([...O,...pe(_,!1)]));return}let y=pe(_,!0),b=await G();if(A)return;let x=[...y].some(e=>!B.has(e));if(X(b,y),A)return;let[S,C]=await Y([J(b),J(b,y)]);if(A)return;let w=await g(a),T=d||s?.signature!==w?.signature||x||S!==f||L!==e;ae=_,V=void 0,H++,O=y,z=C,await K(`build`,E,_),T&&(R=!0,F?N=!0:I=!0)}async function ge(){try{await he()}catch(e){await me(e)}}async function _e(){do N=!1,await ge();while(N&&!A)}function $(){A||(M&&clearTimeout(M),M=setTimeout(()=>{M=void 0,N=!0,P||=_e().finally(()=>{P=void 0,N&&!A&&$()})},T))}function ve(){A=!0,ye.retire(),M&&clearTimeout(M),M=void 0,de.retire()}await ge(),F=!0;let ye=m(()=>v(D),async e=>{A||M||N||e.signature===Q?.signature||(P?N=!0:$())},q);return I&&$(),{get error(){return V},get result(){return ae},get version(){return H},dispose(){return oe.getStore()?.active?(ve(),Promise.resolve()):(j??=(async()=>{ve(),await ye.close(),await P,await ce()})(),j)}}}export{re as pluginTeacss,M as watchTeacssBuild};
1
+ import { existsSync, watch as watchDirectory } from "node:fs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { dirname, join, resolve, sep } from "node:path";
4
+ import { createProject, extractBundledFonts, replaceEntry } from "@teacss/engine";
5
+ const PLUGIN = "teacss";
6
+ const VIRTUAL_ENTRY = /^(?:virtual:)?teacss\.css$/;
7
+ const MODULE = /\.(?:[cm]?[jt]sx?|html)$/;
8
+ const CSS = /\.css$/;
9
+ const NODE_MODULES = `${sep}node_modules${sep}`;
10
+ // teacss-ts `rewriteBundledAssets` writes each bundled font as `teacss-fonts/teacss-<sha256>.woff2` beside the CSS.
11
+ const FONT_URL_PREFIX = "./teacss-fonts/teacss-";
12
+ const FONT_URL = /^\.\/teacss-fonts\/teacss-[a-f0-9]{64}\.woff2$/;
13
+ /**
14
+ * v10.2 §3.4: the tokens of every `@source` file read once and of `inline.content.inline`. `warned` holds the
15
+ * unmatched-token warnings already printed by earlier builds of the same plugin.
16
+ */
17
+ function generateCss(project, minify, warned) {
18
+ const union = project.engine.extractFilesUnion(project.info.sourceFiles);
19
+ for (const path of project.info.unreadableDirectories)
20
+ console.warn(`[@teacss/bun] cannot read ${path} (E_IO)`);
21
+ for (const { path, error } of union.failed)
22
+ console.warn(`[@teacss/bun] cannot read ${path} (${error})`);
23
+ const tokens = [...new Set([...union.tokens, ...project.inlineTokens()])];
24
+ const result = project.engine.generate({ kind: "tokens", tokens }, { minify, css: true });
25
+ project.reportUnmatched(result, {
26
+ tokens,
27
+ warn: (message) => {
28
+ if (warned.has(message))
29
+ return;
30
+ warned.add(message);
31
+ console.warn(`[@teacss/bun] ${message}`);
32
+ },
33
+ });
34
+ return result.css;
35
+ }
36
+ function externalizeFonts(css, fonts) {
37
+ const extracted = extractBundledFonts(css, (digest) => `${FONT_URL_PREFIX}${digest}.woff2`);
38
+ for (const font of extracted.fonts)
39
+ fonts.set(font.digest, font.bytes);
40
+ return extracted.css;
41
+ }
42
+ async function writeFonts(result, fonts) {
43
+ if (!result.success || fonts.size === 0)
44
+ return;
45
+ for (const output of result.outputs) {
46
+ if (!output.path.endsWith(".css"))
47
+ continue;
48
+ const css = await output.text();
49
+ const directory = join(dirname(output.path), "teacss-fonts");
50
+ for (const [digest, bytes] of fonts) {
51
+ const name = `teacss-${digest}.woff2`;
52
+ if (!css.includes(`teacss-fonts/${name}`))
53
+ continue;
54
+ await mkdir(directory, { recursive: true });
55
+ await writeFile(join(directory, name), bytes);
56
+ }
57
+ }
58
+ }
59
+ function projectRoot(options, config) {
60
+ return resolve(options.root ?? config.root ?? process.cwd());
61
+ }
62
+ /**
63
+ * v10.2 §3.4. `import "virtual:teacss.css"` (or `"teacss.css"`) becomes the generated stylesheet; every other
64
+ * module goes through `project.transform`, and in a CSS file whose top level has `@teacss;` the generated
65
+ * stylesheet then takes that rule's place. `minify` defaults to false, as teacss-ts's Bun plugin emits the
66
+ * stylesheet unminified.
67
+ */
68
+ export function teacss(options = {}) {
69
+ // `watch()` runs every build through this one plugin; each build gets a fresh project, so that no module or
70
+ // compile-class definition of a file deleted or renamed since lingers, and the warnings outlive it here.
71
+ const warned = new Set();
72
+ return {
73
+ name: PLUGIN,
74
+ setup(build) {
75
+ const project = createProject({ ...options, root: projectRoot(options, build.config) });
76
+ const fonts = new Map();
77
+ const externalize = build.config.outdir ? (css) => externalizeFonts(css, fonts) : (css) => css;
78
+ const generated = () => externalize(generateCss(project, options.minify ?? false, warned));
79
+ build.onResolve({ filter: VIRTUAL_ENTRY }, () => ({ path: "teacss.css", namespace: PLUGIN }));
80
+ // Bun bundles every `url()` of a stylesheet; the fonts exist only after `onEnd` writes them.
81
+ build.onResolve({ filter: FONT_URL }, (args) => (fonts.has(args.path.slice(FONT_URL_PREFIX.length, -".woff2".length)) ? { path: args.path, external: true } : undefined));
82
+ build.onLoad({ filter: /.*/, namespace: PLUGIN }, () => ({ contents: generated(), loader: "css" }));
83
+ build.onLoad({ filter: CSS }, async (args) => {
84
+ const { code } = project.transform(args.path, await readFile(args.path, "utf8"));
85
+ return { contents: replaceEntry(code, generated) ?? externalize(code), loader: "css" };
86
+ });
87
+ build.onLoad({ filter: MODULE }, async (args) => {
88
+ const code = await readFile(args.path, "utf8");
89
+ if (args.path.includes(NODE_MODULES) && !code.includes("@teacss-include"))
90
+ return;
91
+ const result = project.transform(args.path, code);
92
+ return result.changed ? { contents: result.code, loader: args.loader } : undefined;
93
+ });
94
+ build.onEnd(async (result) => {
95
+ project.dispose();
96
+ await writeFonts(result, fonts);
97
+ });
98
+ },
99
+ };
100
+ }
101
+ /**
102
+ * Builds once, then rebuilds whenever a file in a directory of `project.watchFiles()` (or the root) changes,
103
+ * or a file anywhere under a `@source` glob's directory (`project.sourceDirectories()`), outside `outdir`.
104
+ * Bun's plugin API has no dependency registration, so the watch owns the file list; it resolves after the
105
+ * first build has been reported.
106
+ */
107
+ export async function watch(options, onBuild) {
108
+ const { build, shell = {}, debounce = 200, onError = console.error } = options;
109
+ const root = projectRoot(shell, build);
110
+ const plugins = [...(build.plugins ?? []).filter((plugin) => plugin.name !== PLUGIN), teacss({ ...shell, root })];
111
+ const project = createProject({ ...shell, root });
112
+ const outdir = build.outdir === undefined ? undefined : resolve(build.outdir);
113
+ const watchers = new Map();
114
+ let timer;
115
+ let running = false;
116
+ let queued = false;
117
+ let closed = false;
118
+ let builds = 0;
119
+ function syncWatchers() {
120
+ project.reload();
121
+ const wanted = new Map([root, ...project.watchFiles().map((file) => dirname(file))].map((directory) => [directory, false]));
122
+ for (const { dir } of project.sourceDirectories())
123
+ if (existsSync(dir))
124
+ wanted.set(dir, true);
125
+ for (const [directory, { watcher, recursive }] of watchers) {
126
+ if (wanted.get(directory) === recursive)
127
+ continue;
128
+ watcher.close();
129
+ watchers.delete(directory);
130
+ }
131
+ for (const [directory, recursive] of wanted) {
132
+ if (watchers.has(directory))
133
+ continue;
134
+ const watcher = watchDirectory(directory, { recursive }, (_event, file) => {
135
+ if (file === null || !isOutput(resolve(directory, file)))
136
+ schedule();
137
+ });
138
+ watchers.set(directory, { watcher: watcher.on("error", onError), recursive });
139
+ }
140
+ }
141
+ function isOutput(file) {
142
+ return outdir !== undefined && (file === outdir || file.startsWith(`${outdir}${sep}`));
143
+ }
144
+ async function run() {
145
+ running = true;
146
+ do {
147
+ queued = false;
148
+ try {
149
+ syncWatchers();
150
+ const result = await Bun.build({ ...build, plugins });
151
+ if (!result.success)
152
+ throw new AggregateError(result.logs, "[@teacss/bun] build failed");
153
+ builds++;
154
+ await onBuild(result);
155
+ }
156
+ catch (error) {
157
+ onError(error);
158
+ }
159
+ } while (queued && !closed);
160
+ running = false;
161
+ }
162
+ function schedule() {
163
+ if (closed)
164
+ return;
165
+ clearTimeout(timer);
166
+ timer = setTimeout(() => {
167
+ if (running)
168
+ queued = true;
169
+ else
170
+ void run();
171
+ }, debounce);
172
+ }
173
+ await run();
174
+ return {
175
+ get builds() {
176
+ return builds;
177
+ },
178
+ close() {
179
+ closed = true;
180
+ clearTimeout(timer);
181
+ for (const { watcher } of watchers.values())
182
+ watcher.close();
183
+ watchers.clear();
184
+ project.dispose();
185
+ },
186
+ };
187
+ }
188
+ //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,44 +1,50 @@
1
1
  {
2
2
  "name": "@teacss/bun",
3
- "version": "0.9.3",
4
- "description": "Bun plugin for TeaCSS — generate utilities and inline @apply via Bun.build.",
5
- "homepage": "https://css.teasim.com",
6
- "funding": "https://github.com/sponsors/billgo",
3
+ "version": "0.10.2",
4
+ "description": "Bun.build plugin for TeaCSS: virtual:teacss.css and the entry's @teacss become the CSS the Rust engine generates",
7
5
  "license": "MIT",
8
- "author": "Billgo <hi@billgo.me>",
9
- "sideEffects": false,
10
6
  "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/teacss/teacss-rs.git",
10
+ "directory": "packages/bun"
11
+ },
12
+ "homepage": "https://github.com/teacss/teacss-rs/tree/master/packages/bun#readme",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
11
15
  "exports": {
12
- ".": "./dist/index.js",
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
13
20
  "./package.json": "./package.json"
14
21
  },
15
- "types": "./dist/index.d.ts",
16
22
  "files": [
17
- "dist",
18
- "README.md"
23
+ "dist/**/*.js",
24
+ "dist/**/*.d.ts",
25
+ "README.md",
26
+ "LICENSE"
19
27
  ],
20
- "scripts": {
21
- "build": "bunx tsdown --config tsdown.config.mts",
22
- "dev": "tsdown --watch"
28
+ "sideEffects": false,
29
+ "engines": {
30
+ "bun": ">=1.4.0",
31
+ "node": ">=26"
23
32
  },
24
33
  "dependencies": {
25
- "@teacss/config": "0.9.3",
26
- "@teacss/core": "0.9.3",
27
- "@teacss/directives": "0.9.3",
28
- "@teacss/engine": "0.9.3",
29
- "@teacss/runtime": "0.9.3",
30
- "tinyglobby": "^0.2.17"
34
+ "@teacss/engine": "0.10.2"
31
35
  },
32
36
  "devDependencies": {
33
- "@teacss/preset-standard": "0.9.3",
34
- "bun-types": "^1.4.1",
35
- "consola": "^3.4.2"
37
+ "@types/bun": "1.4.3",
38
+ "typescript": "^5.9.3"
36
39
  },
37
- "engines": {
38
- "bun": ">=1.1.0",
39
- "node": ">=22.12.0"
40
+ "scripts": {
41
+ "build:ts": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
42
+ "build": "npm run build:ts",
43
+ "test": "bun test",
44
+ "check:types": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit"
40
45
  },
41
46
  "publishConfig": {
42
- "access": "public"
47
+ "access": "public",
48
+ "registry": "https://registry.npmjs.org/"
43
49
  }
44
50
  }