@teacss/bun 0.3.0

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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2021-PRESENT Anthony Fu <https://github.com/antfu>
4
+ Copyright (c) 2026-PRESENT Billgo <hi@billgo.me>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # @teacss/bun
2
+
3
+ **Bun build plugin for TeaCSS.**
4
+
5
+ ## Purpose
6
+
7
+ The plugin emits `virtual:teacss.css`, resolves CSS-entry configuration, and
8
+ transforms TeaCSS CSS directives.
9
+
10
+ Use this package when an application or build tool runs through `Bun.build`,
11
+ including programmatic watch builds. It owns Bun's plugin and watcher
12
+ lifecycles; use `@teacss/cli` for standalone CSS output, or the matching
13
+ framework integration when another build system owns the module graph.
14
+
15
+ For an application using the stable facade import, install the adapter beside
16
+ `teacss`:
17
+
18
+ ```sh
19
+ bun add teacss
20
+ bun add -d @teacss/bun
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```ts
26
+ import { pluginTeacss } from "teacss/bun";
27
+
28
+ await Bun.build({
29
+ entrypoints: ["./src/index.ts"],
30
+ outdir: "./dist",
31
+ plugins: [pluginTeacss()],
32
+ });
33
+ ```
34
+
35
+ `pluginTeacss()` is the one-shot `Bun.build` integration. Bun 1.3 does not
36
+ expose watch-dependency registration or invalidation through its JavaScript
37
+ plugin API. For a programmatic watch build, use `watchTeacssBuild`; it watches
38
+ the Bun module graph together with the CSS entry, resolved config dependencies,
39
+ and positive `@source` roots:
40
+
41
+ ```ts
42
+ import { watchTeacssBuild } from "teacss/bun";
43
+
44
+ const session = await watchTeacssBuild(
45
+ {
46
+ entrypoints: ["./src/index.ts"],
47
+ outdir: "./dist",
48
+ },
49
+ {
50
+ configOrPath: "./index.css",
51
+ onError: (error) => console.error(error),
52
+ },
53
+ );
54
+
55
+ await session.dispose();
56
+ ```
57
+
58
+ The session exposes the latest successful `result`, background `error`, and
59
+ successful-build `version`. An initial build or config failure still returns an
60
+ active session: `result` is `undefined`, `version` is `0`, and `error` contains
61
+ the failure until a watched change succeeds. With `throw: false`, an
62
+ unsuccessful Bun result likewise calls only `onError` and does not replace the
63
+ last successful result, version, or module inputs.
64
+
65
+ A successful config reload replaces stale watch roots; a failed reload keeps
66
+ the last successful configuration active while watching the failed attempt's
67
+ dependencies for recovery. Callback failures are logged without changing build
68
+ state. Known watch roots are installed before each build, newly discovered
69
+ module roots receive a stabilizing rebuild, and failed native watchers are
70
+ replaced on the next attempt. Writes outside the tracked config, source, module,
71
+ and entry inputs do not force stabilization. Concurrent `dispose()` calls share
72
+ one completion and wait for all in-flight builds and callbacks. A callback may
73
+ also `await session.dispose()` to stop its own session; that reentrant call
74
+ cannot wait for the invoking callback itself, while disposal started outside a
75
+ callback still waits for the callback to finish.
76
+
77
+ `Bun.build` added JavaScript metafile support in Bun 1.3.6. On older supported
78
+ Bun versions, the helper omits that option and continues watching entry,
79
+ TeaCSS config, and `@source` roots, but it cannot discover additional
80
+ module-graph inputs outside those roots.
81
+
82
+ ```ts
83
+ import "virtual:teacss.css";
84
+ ```
85
+
86
+ ```css
87
+ @preset "standard";
88
+ @source "./src/**/*.{ts,tsx}";
89
+ @teacss;
90
+ ```
91
+
92
+ ## Status
93
+
94
+ Pre-1.0. Install `@teacss/bun` beside `teacss`, then use the stable
95
+ `teacss/bun` facade subpath in applications. Source transformers such as
96
+ `:css:` compile-class are not run here. Integration authors may import
97
+ `@teacss/bun` directly when they intentionally do not use the facade.
@@ -0,0 +1,51 @@
1
+ import { UserConfig, UserConfigDefaults } from "@teacss/core";
2
+ import { BuildConfig, BuildOutput, BunPlugin } from "bun";
3
+ //#region src/index.d.ts
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 `@preset` / `@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).
22
+ */
23
+ declare function pluginTeacss(configOrPath?: UserConfig<object> | string, defaults?: UserConfigDefaults): BunPlugin;
24
+ 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>;
33
+ }
34
+ 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>;
43
+ }
44
+ /**
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.
48
+ */
49
+ declare function watchTeacssBuild(buildConfig: BuildConfig, options?: WatchTeacssBuildOptions): Promise<TeacssBuildWatchSession>;
50
+ //#endregion
51
+ export { TeacssBuildWatchSession, WatchTeacssBuildOptions, pluginTeacss, watchTeacssBuild };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{AsyncLocalStorage as e}from"node:async_hooks";import{existsSync as t,statSync as n,watch as r}from"node:fs";import{readFile as i,stat as a}from"node:fs/promises";import{dirname as o,isAbsolute as s,normalize as c,relative as l,resolve as u,sep as d}from"node:path";import f from"node:process";import p from"@teacss/directives";import{applyTransformerPipeline as m,createContext as h,defaultFilesystemGlobs as g}from"@teacss/runtime";import{DEFAULT_SOURCE_IGNORE as _,generateSources as v,readSourceFile as y}from"@teacss/runtime/source-generation";import{glob as b,isDynamicPattern as x}from"tinyglobby";function S(e,t){let n=l(e,t);return n===``||n!==`..`&&!n.startsWith(`..${d}`)&&!s(n)}function C(e){let t=Array.from(new Set(Array.from(e,c))).sort((e,t)=>e.length-t.length||e.localeCompare(t)),n=[];for(let e of t)n.some(t=>S(t,e))||n.push(e);return n}function ee(e,t){let n=t;for(;x(n);){let e=o(n);if(e===n)break;n=e}return u(e,n)}var te=class{createWatcher;onChange;onError;#e=!1;#t=new Map;constructor(e,t,n){this.createWatcher=e,this.onChange=t,this.onError=n}get roots(){return[...this.#t.keys()]}covers(e){for(let t of this.#t.keys())if(S(t,e))return!0;return!1}reconcile(e){if(this.#e)return;let t=C(e),n=new Set(t),r=new Map;try{for(let e of t){if(this.#t.has(e))continue;let t;try{t=this.createWatcher(e,(t,n)=>{this.onChange(n==null?void 0:u(e,n.toString()))});let n=t;t.on(`error`,t=>{this.#t.get(e)===n&&(this.#t.delete(e),this.closeWatcher(n)),this.onError(t)}),r.set(e,t)}catch(e){throw t&&this.closeWatcher(t),e}}}catch(e){for(let e of r.values())this.closeWatcher(e);throw e}if(this.#e){for(let e of r.values())this.closeWatcher(e);return}let i=new Map;for(let e of t){let t=this.#t.get(e)??r.get(e);t&&i.set(e,t)}let a=this.#t;this.#t=i;for(let[e,t]of a)n.has(e)||this.closeWatcher(t)}dispose(){if(this.#e)return;this.#e=!0;let e=this.#t;this.#t=new Map;for(let t of e.values())this.closeWatcher(t)}closeWatcher(e){try{e.close()}catch(e){this.onError(e)}}};function ne(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}}const w=/^(?:virtual:)?teacss\.css$/,T=/\.css$/,E=`teacss`;function D(e,t={}){return{name:`teacss`,async setup(n){let r=h(e,{...t,transformers:[...t.transformers??[],p()]}),a=n.config.root??f.cwd();await r.updateRoot(a);let s=new Set,c=new Set,l=!0;function u(){let e=r.getConfigFileList()[0];return e?o(e):a}async function d(e){let t=e();s.add(t);try{return await t}finally{s.delete(t)}}n.onStart(async()=>{if(l){l=!1;return}await Promise.allSettled(s);for(let e of c)await r.extract(``,e);c.clear(),await r.reloadConfig()}),n.onResolve({filter:w},()=>({path:`teacss.css`,namespace:E})),n.onLoad({filter:/.*/,namespace:E},()=>d(async()=>{let e=await b((await r.getConfig()).content?.filesystem??g,{cwd:u(),absolute:!0,ignore:_}),t=e.map(y),{css:n}=await v(r.generator,e,t,{minify:!1});return{contents:n,loader:`css`}})),n.onLoad({filter:T},e=>d(async()=>{let t=await i(e.path,`utf8`);return c.add(e.path),{contents:(await m(r,t,e.path))?.code??t,loader:`css`}}))}}}function re(e){let r=e;for(n(r,{throwIfNoEntry:!1})?.isFile()&&(r=o(r));!t(r);){let e=o(r);if(e===r)break;r=e}return r}function ie(e){return`${e.mtimeMs}:${e.ctimeMs}:${e.size}:${e.ino}`}async function O(n,i={}){let c=u(n.root??f.cwd()),l=n.entrypoints.map(e=>s(e)?e:u(c,e)),{configOrPath:d,defaults:p={},debounce:m=50,onBuild:v,onError:y}=i,x=h(d,p),S=new Set,C=!1,w=!1,T,E,O=!1,k,A=!1,j=!1,M=0,N=!1,P=``,F=new Set,I,L,R=0,z=new Set,B=new e;function V(){let e=x.getConfigFileList()[0];return e?o(e):c}async function H(){return await b(x.generator.config.content?.filesystem??g,{cwd:V(),absolute:!0,ignore:_})}function ae(e){let t=e.content?.filesystem;if(!t)return e;let n=V();return{...e,content:{...e.content,filesystem:t.map(e=>e.startsWith(`!`)?`!${u(n,e.slice(1))}`:u(n,e))}}}function U(e,t,n){if(!t)return Promise.resolve();let r={active:!0},i;return i=B.run(r,()=>Promise.resolve().then(()=>t(n)).catch(t=>console.error(`[@teacss/bun] watch ${e} callback failed:`,t)).finally(()=>{r.active=!1,z.delete(i)})),z.add(i),i}async function oe(){for(;z.size>0;)await Promise.all(z)}function W(e){return w?Promise.resolve():(I=e,U(`error`,y,e))}function se(e,t=S){let n=new Set([...x.getConfigFileList(),...l,...t,...e]);if(typeof d!=`object`){let e=typeof d==`string`?u(c,d):c;n.add(e)}let r=V();for(let e of x.generator.config.content?.filesystem??g)e.startsWith(`!`)||n.add(ee(r,e));return n}function G(e,t=S){return new Set([...x.getConfigFileList(),...l,...t,...e])}async function K(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 ce(e,t=S){return(await K([G(e,t)]))[0]}let q=new te((e,t)=>r(e,{recursive:!0},t),e=>{if(e!==void 0&&F.has(e)&&M++,!A){j=!0;return}$()},e=>{W(e),A?$():j=!0});function J(e,t=S){return F=G(e,t),q.reconcile(Array.from(se(e,t),re))}function Y(e,t,n){return AggregateError([e,t],n)}function X(e,n){return new Set(Object.keys(e.metafile?.inputs??{}).map(e=>s(e)?e:u(c,e)).filter(e=>!n||t(e)))}async function Z(e,t=S){if(w)return;let n=e,r=[];try{r=await H()}catch(e){n=Y(n,e,`TeaCSS build and source discovery failed`)}if(!w){try{J(r,t)}catch(e){n=Y(n,e,`TeaCSS build and watcher reconciliation failed`)}await W(n)}}async function le(){if(w)return;let e=M;if(C?await x.reloadConfig():(C=!0,await x.updateRoot(c)),w)return;let t=await H();if(w||(J(t),w))return;let r=await ce(t);if(w)return;let i=N;if(N=!1,!i&&R>0&&I===void 0&&r===P)return;let a=ae(await x.getConfig());if(w)return;let o=[...(n.plugins??[]).filter(e=>e.name!==`teacss`),D(a)],s=await Bun.build(ne(n,o));if(w)return;if(!s.success){await Z(s,new Set([...S,...X(s,!1)]));return}let l=X(s,!0),u=await H();if(w)return;let d=[...l].some(e=>!q.covers(e));if(J(u,l),w)return;let[f,p]=await K([G(u),G(u,l)]);if(w)return;let m=d||f!==r||M!==e;L=s,I=void 0,R++,S=l,P=p,await U(`build`,v,s),m&&(N=!0,A?O=!0:j=!0)}async function Q(){try{await le()}catch(e){await Z(e)}}async function ue(){do O=!1,await Q();while(O&&!w)}function $(){w||(E&&clearTimeout(E),E=setTimeout(()=>{E=void 0,O=!0,k||=ue().finally(()=>{k=void 0,O&&!w&&$()})},m))}function de(){w=!0,E&&clearTimeout(E),E=void 0,q.dispose()}return await Q(),A=!0,j&&$(),{get error(){return I},get result(){return L},get version(){return R},dispose(){return B.getStore()?.active?(de(),Promise.resolve()):(T??=(async()=>{de(),await k,await oe()})(),T)}}}export{D as pluginTeacss,O as watchTeacssBuild};
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@teacss/bun",
3
+ "version": "0.3.0",
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",
7
+ "license": "MIT",
8
+ "author": "Billgo <hi@billgo.me>",
9
+ "sideEffects": false,
10
+ "type": "module",
11
+ "exports": {
12
+ ".": "./dist/index.js",
13
+ "./package.json": "./package.json"
14
+ },
15
+ "types": "./dist/index.d.ts",
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "scripts": {
21
+ "build": "bunx tsdown --config tsdown.config.mts",
22
+ "dev": "tsdown --watch"
23
+ },
24
+ "dependencies": {
25
+ "@teacss/core": "0.3.0",
26
+ "@teacss/directives": "0.3.0",
27
+ "@teacss/runtime": "0.3.0",
28
+ "tinyglobby": "^0.2.17"
29
+ },
30
+ "devDependencies": {
31
+ "@teacss/preset-standard": "0.3.0",
32
+ "bun-types": "^1.3.14"
33
+ },
34
+ "engines": {
35
+ "bun": ">=1.1.0",
36
+ "node": ">=22.12.0"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ }
41
+ }