@cssints/css-grammar 0.0.0-stage → 0.1.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 +21 -0
- package/README.md +178 -2
- package/THIRD_PARTY_NOTICES.md +33 -0
- package/dist/api-query.d.mts +6 -0
- package/dist/api-query.mjs +1 -0
- package/dist/api-typed.d.mts +18 -0
- package/dist/api-typed.mjs +1 -0
- package/dist/api.d.mts +13 -0
- package/dist/api.mjs +1 -0
- package/dist/browsers.d.mts +5 -0
- package/dist/browsers.mjs +15 -0
- package/dist/check.d.mts +17 -0
- package/dist/check.mjs +85 -0
- package/dist/css.d.mts +298 -0
- package/dist/css.mjs +1 -0
- package/dist/errors.d.mts +52 -0
- package/dist/errors.mjs +15 -0
- package/dist/functions.d.mts +355 -0
- package/dist/functions.mjs +178 -0
- package/dist/keywords.d.mts +2353 -0
- package/dist/keywords.mjs +1 -0
- package/dist/longhands.d.mts +3 -0
- package/dist/longhands.mjs +841 -0
- package/dist/mdn.d.mts +894 -0
- package/dist/mdn.mjs +895 -0
- package/dist/query.d.mts +34 -0
- package/dist/query.mjs +8 -0
- package/dist/rules.d.mts +6 -0
- package/dist/rules.mjs +218 -0
- package/dist/selector.d.mts +3 -0
- package/dist/selector.mjs +79 -0
- package/dist/support.d.mts +28 -0
- package/dist/support.mjs +148 -0
- package/dist/token.d.mts +146 -0
- package/dist/token.mjs +112 -0
- package/dist/twin-core.d.mts +48 -0
- package/dist/twin-core.mjs +789 -0
- package/dist/twin.d.mts +12 -0
- package/dist/twin.mjs +38 -0
- package/dist/values.d.mts +28 -0
- package/dist/values.mjs +44 -0
- package/package.json +33 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexei Accio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,179 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CSS-in-TS
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<img src="https://cssints.dev/logo.svg" alt="" width="96" height="96">
|
|
4
|
+
|
|
5
|
+
cssints is compile-time CSS-in-TypeScript. You write calls such as `css.flex().alignItems("center")`. A Vite plugin runs them at build time and replaces each one with atomic, content-hashed class names in `@layer`s. Nothing of the styling code ships to the browser except `cx` and the few lines behind `cv`, which join class names.
|
|
6
|
+
|
|
7
|
+
- Values are checked against the spec grammars (mdn-data) in the types and again at build time. A typo is an error in the editor and in the build.
|
|
8
|
+
- Conditions (`media`, `container`, `supports`, `hover`), variants (`cv`), design tokens and themes (`createTokens`, `createGlobalTheme`, `check.contrast`) are all build-time, and all typed.
|
|
9
|
+
- LightningCSS optimizes the output. Browser support (`@mdn/browser-compat-data` against your browserslist) is reported as warnings, except for what LightningCSS lowers for those targets.
|
|
10
|
+
|
|
11
|
+
Status: 0.1 is not published yet. Decisions and findings are in [docs/wayfinder.md](docs/wayfinder.md); the API reference is [docs/API.md](docs/API.md). Both are also a site with search and type hovers: [apps/docs](apps/docs) (`cd apps/docs && bun run dev`); deployed to Cloudflare with Alchemy: <https://cssints.dev>.
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Not on npm yet. In this repo `cssints` is a workspace package (`apps/demo` depends on `"cssints": "workspace:*"`). It needs Vite 8 (Vite+ works too) and, for the plugin, Node with type stripping (22.18 or later).
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// vite.config.ts
|
|
19
|
+
import cssints, { cssTarget, targets } from "cssints/vite";
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
plugins: [cssints()],
|
|
23
|
+
css: { transformer: "lightningcss", lightningcss: { targets } },
|
|
24
|
+
build: { cssMinify: "lightningcss", cssTarget },
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// the entry, once
|
|
30
|
+
import "virtual:cssints.css";
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`targets` and `cssTarget` come from the browserslist query of the support warnings: the `BROWSERSLIST` variable, else the standard config (`"browserslist"` in `package.json` or `.browserslistrc`, with the `BROWSERSLIST_ENV`, `NODE_ENV` or `production` section), else `defaults`. The exports are computed when `vite.config.ts` is imported, before Vite's root is known, so they look the config up from `process.cwd()` and upward; the support warnings look it up from Vite's `root` (2026-10-09, cssints-p3d2). They are the same when Vite runs from the app's directory; with `vite <dir>` from elsewhere, give `targets` and `cssTarget` the app's config yourself. Vite's CSS minify reads `cssTarget`, not `targets`: without it the minifier merges the declarations of a `firstThatWorks` into the last one. Add `"types": ["vite/client"]` to `tsconfig.json` for the `virtual:` import.
|
|
34
|
+
|
|
35
|
+
### Frameworks
|
|
36
|
+
|
|
37
|
+
Any framework that builds JSX through a Vite plugin works; the engine evaluates your modules itself, so it does not care what the plugin makes of JSX, nor in which order the plugins are listed. `apps/sky` is the Solid 2 app (`solid-js` and `@solidjs/web` 2.0.0-rc.13, `@solidjs/vite-plugin` 3.0.0-next.47):
|
|
38
|
+
|
|
39
|
+
```ts skip
|
|
40
|
+
// vite.config.ts
|
|
41
|
+
import solid from "@solidjs/vite-plugin";
|
|
42
|
+
import cssints, { cssTarget, targets } from "cssints/vite";
|
|
43
|
+
|
|
44
|
+
export default {
|
|
45
|
+
plugins: [cssints(), solid()],
|
|
46
|
+
css: { transformer: "lightningcss", lightningcss: { targets } },
|
|
47
|
+
build: { cssMinify: "lightningcss", cssTarget },
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`tsconfig.json` is Solid's: `"jsx": "preserve"`, `"jsxImportSource": "@solidjs/web"`, `"types": ["vite/client"]`. Solid's `class` takes a string, an object or an array, so `cx` is not needed: `class={[card, on() && p(4)]}` and `class={badge({ tone: tone() })}` work as in React. A site's arguments are still build-time values, so a signal goes in the condition or in a `cv` variant, not in `p(n())`. Under `vite dev` an edit of a component replaces it and resets its state below it (Solid's refresh); an edit of a style changes the class strings and the sheet with no reload.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { cx } from "cssints";
|
|
55
|
+
import { bg, color, cn, cv, flex, hover, media, p, style, token } from "cssints" with { type: "cssints" };
|
|
56
|
+
|
|
57
|
+
const md = media("(width >= 40rem)");
|
|
58
|
+
const accent = token.color("#2563eb", "accent");
|
|
59
|
+
|
|
60
|
+
const button = cv({
|
|
61
|
+
base: cn(p(2), color("white"), bg(accent), hover(bg("#1d4ed8"))),
|
|
62
|
+
variants: { wide: { true: md(p(4)) } },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
export const Row = ({ wide, on }: { wide?: boolean; on?: boolean }) => (
|
|
66
|
+
<div className={cx(flex().alignItems("center").gap(2), on && p(1))} style={style(token.set(accent, "#dc2626"))}>
|
|
67
|
+
<button className={button({ wide })}>Save</button>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`with { type: "cssints" }` marks what runs at build time. The plugin replaces each call with a class string, so the browser gets `cx("_1s47490 _1ob5z5m _g2iyum", on && "_lqk467")` and `button` is a call of the runtime with `{ base: "_1t8gqy5 ...", ... }`, so it never sees `flex()`. `virtual:cssints.css` is one sheet with every rule once, sorted by layer, then condition, then shorthand before longhand, then class name:
|
|
73
|
+
|
|
74
|
+
```css
|
|
75
|
+
@layer _.k, _.a, _.b, _.c, _.d, _.e;
|
|
76
|
+
@property --accent{syntax:"<color>";inherits:true;initial-value:#2563eb}
|
|
77
|
+
@layer _.a {
|
|
78
|
+
._1t8gqy5{padding:0.5rem}
|
|
79
|
+
._lqk467{padding:0.25rem}
|
|
80
|
+
._g2iyum{gap:0.5rem}
|
|
81
|
+
._17xzvrh{background-color:var(--accent)}
|
|
82
|
+
._1binn6n{color:white}
|
|
83
|
+
._1ob5z5m{align-items:center}
|
|
84
|
+
._1s47490{display:flex}
|
|
85
|
+
}
|
|
86
|
+
@layer _.b {
|
|
87
|
+
._1tsjws2:hover{background-color:#1d4ed8}
|
|
88
|
+
@media (width >= 40rem) {
|
|
89
|
+
._tdcza3{padding:1rem}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### In a terminal
|
|
95
|
+
|
|
96
|
+
`import * as css from "cssints/tui" with { type: "cssints" }` gives the members a terminal has (cells, colours, borders, flex, states, `cursor`), and the plugin compiles them to prop objects for [OpenTUI](https://opentui.com) renderables instead of classes; `@cssints/tui` applies their states and themes: [packages/tui](packages/tui/README.md), docs/API.md "TUI".
|
|
97
|
+
|
|
98
|
+
More in [docs/API.md](docs/API.md): property names and short names, `flex()` and `grid()` chains, conditions and layers, tokens and themes, `cx`, `cn` and `cv`, and the errors you can get.
|
|
99
|
+
|
|
100
|
+
## Debugging
|
|
101
|
+
|
|
102
|
+
`CSSINTS_TRACE=otlp bun run build` (or `dev`) sends a trace of every Vite hook, with the file of each module, to a local OpenTelemetry backend; unset, it costs nothing. How to start the backend in one `docker run`, and the spans: [docs/API.md](docs/API.md#debugging-traces-of-the-engine-cssints_trace-cssints-r2qq).
|
|
103
|
+
|
|
104
|
+
## For agents
|
|
105
|
+
|
|
106
|
+
`cssints` ships two [agent skills](https://agentskills.io) in its package, `skills/cssints` (writing styles: setup,
|
|
107
|
+
`cn`/`cx`/`cv`, conditions, tokens and themes, the plugin packages, build errors) and `skills/cssints-plugin` (writing
|
|
108
|
+
a plugin on `scope()`, with its tests). Install them into your agent's skills folder:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npx skills-npm # links the skills of every installed package that ships some
|
|
112
|
+
npx skills add ./node_modules/cssints/skills # or the skills CLI, for opencode, Claude Code, Codex, Cursor, ...
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Until 0.1 is on npm, point `npx skills add` at `packages/cssints/skills` of this repository. Agents working on this
|
|
116
|
+
repository get `.agents/skills/cssints-contributor` (also `.claude/skills`) with no install.
|
|
117
|
+
|
|
118
|
+
`@cssints/mcp` is an MCP server with the build's own checks (`check_declaration`, `check_support`, `check_contrast`,
|
|
119
|
+
`compile`, `search_docs`, `list_plugins`), in [packages/mcp](packages/mcp) with the config for opencode, Claude Code
|
|
120
|
+
and Cursor. The skills use it when it is configured and work without it.
|
|
121
|
+
|
|
122
|
+
## Layout
|
|
123
|
+
|
|
124
|
+
| Path | What |
|
|
125
|
+
|---|---|
|
|
126
|
+
| `packages/cssints` | Vite plugin (`cssints/vite`) on the Vite Module Runner, and the `cssints` library |
|
|
127
|
+
| `packages/css-grammar` | Type-level recognizer and its runtime twin over mdn-data grammars, Typed OM values, browser support and prose rules |
|
|
128
|
+
| `packages/icons` | `@cssints/icons`: icons from iconify JSON collections or SVG folders, a mask style with no runtime |
|
|
129
|
+
| `packages/mise-en-mode` | `@cssints/mise-en-mode`: looks as themes in the layers app < author < viewer, on `data-mode` scopes, checked against the tokens and by `check.contrast` |
|
|
130
|
+
| `apps/demo` | React demo of every 0.1 feature |
|
|
131
|
+
| `apps/docs` | The documentation site: this file and `docs/API.md` as pages, with search and type hovers (`cd apps/docs && bun run dev`) |
|
|
132
|
+
| `docs/research`, `docs/archive` | Comparisons with other libraries; outdated plans |
|
|
133
|
+
|
|
134
|
+
## Development
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
bun install
|
|
138
|
+
bun run test # all packages (vp run -r test, cached where possible); includes the type-check of the code in docs/API.md and this file
|
|
139
|
+
bun run bench # type instantiation budgets (tsc and tsgo)
|
|
140
|
+
bun run check # format, lint, type-check (vp check), then the Effect diagnostics (bun run typecheck)
|
|
141
|
+
bun run diff:check # the added lines against master: anti-slop rules, key-file changes (tools/ai-automation)
|
|
142
|
+
cd apps/demo && bun run dev
|
|
143
|
+
cd apps/docs && bun run dev # the documentation site, on the pages of README.md and docs/API.md
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
See [AGENTS.md](AGENTS.md) for the layout, commands and code style.
|
|
147
|
+
|
|
148
|
+
## Credits
|
|
149
|
+
|
|
150
|
+
cssints is MIT. It stands on other people's work; this is what we took, from whom, and under which license. A package that copies data or code carries the upstream notice (a Credits or Licenses section of its README, or `THIRD_PARTY_NOTICES.md`).
|
|
151
|
+
|
|
152
|
+
### Data and code that ships
|
|
153
|
+
|
|
154
|
+
| Where | What | From | License |
|
|
155
|
+
|---|---|---|---|
|
|
156
|
+
| [@cssints/tokens](packages/tokens/README.md) | the Open Props, Radix Colors, Flexoki and Reasonable Colors sets | [Open Props](https://github.com/argyleink/open-props) (Adam Argyle), [Radix Colors](https://github.com/radix-ui/colors), [Flexoki](https://github.com/kepano/flexoki) (Steph Ango), [Reasonable Colors](https://github.com/matthewhowell/reasonable-colors) (Matthew Howell) | MIT, notices in its README |
|
|
157
|
+
| [@cssints/css-grammar](packages/css-grammar/THIRD_PARTY_NOTICES.md) | the CSS syntax strings (`src/mdn.ts`, `keywords.ts`, `functions.ts`), also in the types of `cssints` | [mdn-data](https://github.com/mdn/data); the numeric ranges it omits from [@webref/css](https://github.com/w3c/webref) | CC0-1.0; MIT (W3C) |
|
|
158
|
+
| @cssints/css-grammar | browser support warnings, read from the package (not copied) | [@mdn/browser-compat-data](https://github.com/mdn/browser-compat-data) | CC0-1.0 |
|
|
159
|
+
| [@cssints/fonts](packages/fonts/README.md) | the latin character weights and the metrics of Arial, Times New Roman and Courier New | [Capsize](https://github.com/seek-oss/capsize) (SEEK) | MIT, notice in its README |
|
|
160
|
+
| [@cssints/icons](packages/icons/README.md) | nothing: the collections are your dependency | [Iconify](https://iconify.design) `@iconify-json/*` | each collection's own |
|
|
161
|
+
| `tools/ai-automation/vendor` | lint rules, not published | [dmmulroy/anti-slop](https://github.com/dmmulroy/anti-slop) (Dillon Mulroy) | MIT, `LICENSE` and `UPSTREAM.md` |
|
|
162
|
+
| [apps/sky](apps/sky/NOTICE.md) | layout and token values; Inter; Phosphor icons | Mu and `@bsky.app/alf` (Bluesky Social PBC), [Inter](https://github.com/rsms/inter), [Phosphor](https://phosphoricons.com) | MIT; OFL-1.1; MIT |
|
|
163
|
+
| apps/demo | Material Design Icons (`@iconify-json/mdi`) | Pictogrammers | Apache-2.0 |
|
|
164
|
+
|
|
165
|
+
### Ideas and designs
|
|
166
|
+
|
|
167
|
+
No code is copied from these; each package README says which part follows which.
|
|
168
|
+
|
|
169
|
+
- **Plugin packages.** [Every Layout](https://every-layout.dev) and [smolcss](https://smolcss.dev) (layout), [nytimes/text-balancer](https://github.com/nytimes/text-balancer) and [react-wrap-balancer](https://github.com/shuding/react-wrap-balancer) (balance), [fluid-tailwind](https://github.com/barvian/fluid-tailwind) (fluid), [postcss-easing-gradients](https://github.com/larsenwork/postcss-easing-gradients) (gradient), [tailwindcss-motion](https://github.com/romboHQ/tailwindcss-motion) and [tailwindcss-animate](https://github.com/jamiebuilds/tailwindcss-animate) (motion), [the supersonic plugin](https://github.com/the-illarionov/the-supersonic-plugin-for-scroll-based-animation) and [lax.js](https://github.com/alexfoxy/lax.js) (reveal), [sync-skeleton](https://github.com/crutchcorn/sync-skeleton) (skeleton), [bramus/sticky-observer](https://github.com/bramus/sticky-observer) (stuck), [unpic-placeholder](https://github.com/ascorbic/unpic-placeholder) and [ThumbHash](https://github.com/evanw/thumbhash) (placeholder), [nutelch](https://github.com/meodai/nutelch) and [Leonardo](https://github.com/adobe/leonardo) (ramp), the resets of Josh Comeau, Jake Lazaroff, Vale and Andy Bell (reset), [Mise en Mode](https://standard.mode.place) and its Mode Contract (mise-en-mode), [brendonovich/vite-plugin-opencode](https://github.com/Brendonovich/vite-plugin-opencode) (the prompt box of devtools).
|
|
170
|
+
- **The engine.** The comparisons in [docs/research](docs/research) record what we took from [StyleX](https://stylexjs.com), [vanilla-extract](https://vanilla-extract.style), [Tailwind CSS](https://tailwindcss.com), [Tokenami](https://tokenami.com), [SugarCube](https://sugarcube.sh) and the [React Spectrum](https://react-spectrum.adobe.com) style macros; the first spark was [Haz's post](https://bsky.app/profile/haz.dev/post/3mebm2mx6jk27) on a CSS framework in TypeScript. Tokens follow the [Design Tokens Community Group](https://www.designtokens.org) format.
|
|
171
|
+
- **apps/sky** follows the look of Mu and the hue slider of Witchsky.
|
|
172
|
+
|
|
173
|
+
### Built on
|
|
174
|
+
|
|
175
|
+
[Effect](https://effect.website), [Vite](https://vite.dev) and Vite+, [OXC](https://oxc.rs), [LightningCSS](https://lightningcss.dev) (MPL-2.0; its wasm build runs in the playground), [culori](https://culorijs.org), [TypeScript](https://www.typescriptlang.org) and TypeScript Go, [Bun](https://bun.sh), [Solid](https://www.solidjs.com), [OpenTUI](https://opentui.com), [Shiki](https://shiki.style), [Monaco Editor](https://microsoft.github.io/monaco-editor/), [Playwright](https://playwright.dev), [fast-check](https://fast-check.dev), [Quint](https://quint-lang.org), [atcute](https://github.com/mary-ext/atcute), and [Beans](https://github.com/hmans/beans) for the tickets. Phosphor icons (MIT) are on this site through `@iconify-json/ph`. Every dependency keeps its own license; none is copied into the repository.
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
The code of `@cssints/css-grammar` is MIT (`LICENSE`). The generated data in `src/` (and `dist/`) keeps the license of its
|
|
4
|
+
source.
|
|
5
|
+
|
|
6
|
+
## Data
|
|
7
|
+
|
|
8
|
+
- **mdn-data** (`src/mdn.ts`, `src/keywords.ts`, `src/functions.ts`): the CSS syntax strings, copied verbatim by
|
|
9
|
+
`bun run extract`. CC0 1.0 Universal, the mdn-data contributors. <https://github.com/mdn/data>
|
|
10
|
+
- **@webref/css** (`src/mdn.ts`): the numeric ranges that mdn-data leaves out, copied by `bun run extract`. MIT,
|
|
11
|
+
Copyright (c) 2020 World Wide Web Consortium. <https://github.com/w3c/webref>
|
|
12
|
+
- **@mdn/browser-compat-data**: read at build time for the support warnings, not copied. CC0 1.0 Universal.
|
|
13
|
+
<https://github.com/mdn/browser-compat-data>
|
|
14
|
+
- `src/longhands.ts` and `scripts/webref-properties.json` are written by `bun run longhands` and `bun run webref`, which
|
|
15
|
+
ask Chrome how it expands a shorthand and what it accepts. They hold facts, no text of a source.
|
|
16
|
+
|
|
17
|
+
The MIT notice of @webref/css, Copyright (c) 2020 World Wide Web Consortium:
|
|
18
|
+
|
|
19
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
|
20
|
+
> documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
|
21
|
+
> rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
22
|
+
> persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
23
|
+
>
|
|
24
|
+
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
|
25
|
+
> Software.
|
|
26
|
+
>
|
|
27
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
28
|
+
> WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
29
|
+
> COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
30
|
+
> OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
31
|
+
|
|
32
|
+
CC0 1.0 Universal needs no notice. The full text is in the `LICENSE` of the `mdn-data` and `@mdn/browser-compat-data`
|
|
33
|
+
packages.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Condition } from "./query.mjs";
|
|
2
|
+
//#region src/api-query.d.ts
|
|
3
|
+
export declare const media: Condition<"media", string>;
|
|
4
|
+
export declare const container: Condition<"container", string>;
|
|
5
|
+
export declare const supports: Condition<"supports", string>;
|
|
6
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { properties } from "./mdn.mjs";
|
|
2
|
+
import { Sentinel, Valid } from "./css.mjs";
|
|
3
|
+
import { CSSStyleValue } from "./values.mjs";
|
|
4
|
+
//#region src/api-typed.d.ts
|
|
5
|
+
type Part = string | CSSStyleValue;
|
|
6
|
+
type Text<P> = P extends string ? P : P extends CSSStyleValue<infer T> ? Sentinel<T> : never;
|
|
7
|
+
export type Join<A extends readonly Part[]> = A extends readonly [infer H, ...infer R extends readonly Part[]] ? R extends readonly [] ? Text<H> : `${Text<H>} ${Join<R>}` : "";
|
|
8
|
+
type Check<P extends keyof typeof properties, A extends readonly Part[]> = Valid<P, Join<A>> extends (infer V) ? (V extends Join<A> ? A : { [K in keyof A]: V; }) : never;
|
|
9
|
+
export type TypedPropertyFn<P extends keyof typeof properties> = <const A extends readonly Part[]>(...parts: Check<P, A>) => string;
|
|
10
|
+
export declare const padding: TypedPropertyFn<"padding">;
|
|
11
|
+
export declare const margin: TypedPropertyFn<"margin">;
|
|
12
|
+
export declare const width: TypedPropertyFn<"width">;
|
|
13
|
+
export declare const gap: TypedPropertyFn<"gap">;
|
|
14
|
+
export declare const border: TypedPropertyFn<"border">;
|
|
15
|
+
export declare const color: TypedPropertyFn<"color">;
|
|
16
|
+
export declare const opacity: TypedPropertyFn<"opacity">;
|
|
17
|
+
export declare const fontSize: TypedPropertyFn<"font-size">;
|
|
18
|
+
//#endregion
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/api.d.mts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { PropertyFn } from "./css.mjs";
|
|
2
|
+
//#region src/api.d.ts
|
|
3
|
+
export declare const padding: PropertyFn<"padding">;
|
|
4
|
+
export declare const margin: PropertyFn<"margin">;
|
|
5
|
+
export declare const width: PropertyFn<"width">;
|
|
6
|
+
export declare const gap: PropertyFn<"gap">;
|
|
7
|
+
export declare const border: PropertyFn<"border">;
|
|
8
|
+
export declare const color: PropertyFn<"color">;
|
|
9
|
+
export declare const alignItems: PropertyFn<"align-items">;
|
|
10
|
+
export declare const display: PropertyFn<"display">;
|
|
11
|
+
export declare const borderRadius: PropertyFn<"border-radius">;
|
|
12
|
+
export declare const fontSize: PropertyFn<"font-size">;
|
|
13
|
+
//#endregion
|
package/dist/api.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BrowsersError } from "./errors.mjs";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
//#region src/browsers.ts
|
|
4
|
+
const browserslist = process.getBuiltinModule("node:module").createRequire(import.meta.url)("browserslist");
|
|
5
|
+
const browsers = Effect.fn("browsers")(function* (query, path) {
|
|
6
|
+
return yield* Effect.try({
|
|
7
|
+
try: () => browserslist(query, path === void 0 ? void 0 : { path }),
|
|
8
|
+
catch: (e) => new BrowsersError({
|
|
9
|
+
message: e instanceof Error ? e.message : String(e),
|
|
10
|
+
query
|
|
11
|
+
})
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
//#endregion
|
|
15
|
+
export { browsers };
|
package/dist/check.d.mts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { QueryKind } from "./query.mjs";
|
|
2
|
+
import { RuleError, TwinError } from "./errors.mjs";
|
|
3
|
+
import { Warning } from "./support.mjs";
|
|
4
|
+
import { Effect } from "effect";
|
|
5
|
+
//#region src/check.d.ts
|
|
6
|
+
export type DeclarationError = TwinError | RuleError;
|
|
7
|
+
export declare const isDeclarationError: (e: unknown) => e is DeclarationError;
|
|
8
|
+
export declare function checkDeclarationNow(p: string, v: string, warnings: boolean): Warning[];
|
|
9
|
+
export declare const checkValueNow: (label: string, grammar: string, v: string) => void;
|
|
10
|
+
/** The support warnings of `p: v` (none unless `warnings`), or why the declaration is invalid. */
|
|
11
|
+
export declare const checkDeclaration: (p: string, v: string, warnings: boolean) => Effect.Effect<Warning[], DeclarationError, never>;
|
|
12
|
+
export declare function checkQueryNow(kind: QueryKind, q: string): void;
|
|
13
|
+
/** Twin of ValidQuery<K, S> (query.ts): the query of a media(), container() or supports() call is valid, or why not. */
|
|
14
|
+
export declare const checkQuery: (kind: "media" | "container" | "supports", q: string) => Effect.Effect<void, TwinError, never>;
|
|
15
|
+
/** The selector of a `css.global()` call is a <complex-selector-list>, or why not (selector.ts). */
|
|
16
|
+
export declare const checkSelector: (selector: string) => Effect.Effect<void, TwinError, never>;
|
|
17
|
+
//#endregion
|
package/dist/check.mjs
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { InvalidValueError, RuleError, isTwinError } from "./errors.mjs";
|
|
2
|
+
import { syntaxes } from "./mdn.mjs";
|
|
3
|
+
import { ENTRY } from "./query.mjs";
|
|
4
|
+
import { consume, parseGrammar, spaced, valid } from "./twin-core.mjs";
|
|
5
|
+
import { violation } from "./rules.mjs";
|
|
6
|
+
import { checkSelectorNow } from "./selector.mjs";
|
|
7
|
+
import { supportOf } from "./support.mjs";
|
|
8
|
+
import { Effect } from "effect";
|
|
9
|
+
//#region src/check.ts
|
|
10
|
+
const isDeclarationError = (e) => isTwinError(e) || e instanceof RuleError;
|
|
11
|
+
const passed = /* @__PURE__ */ new Set();
|
|
12
|
+
function checkDeclarationNow(p, v, warnings) {
|
|
13
|
+
if (p.startsWith("--")) return [];
|
|
14
|
+
const key = `${p}\0${v}`;
|
|
15
|
+
if (!passed.has(key)) {
|
|
16
|
+
valid(p, v);
|
|
17
|
+
const error = violation(p, v);
|
|
18
|
+
if (error) throw error;
|
|
19
|
+
passed.add(key);
|
|
20
|
+
}
|
|
21
|
+
return warnings ? supportOf(p, v) : [];
|
|
22
|
+
}
|
|
23
|
+
const checkValueNow = (label, grammar, v) => {
|
|
24
|
+
valid(label, v, grammar);
|
|
25
|
+
};
|
|
26
|
+
/** The support warnings of `p: v` (none unless `warnings`), or why the declaration is invalid. */
|
|
27
|
+
const checkDeclaration = Effect.fnUntraced(function* (p, v, warnings) {
|
|
28
|
+
return yield* Effect.try({
|
|
29
|
+
try: () => checkDeclarationNow(p, v, warnings),
|
|
30
|
+
catch: (e) => {
|
|
31
|
+
if (isDeclarationError(e)) return e;
|
|
32
|
+
throw e;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
function checkQueryNow(kind, q) {
|
|
37
|
+
const syntax = syntaxes;
|
|
38
|
+
const v = spaced(q).trimStart();
|
|
39
|
+
const ctx = {
|
|
40
|
+
len: v.length,
|
|
41
|
+
far: -1,
|
|
42
|
+
expected: /* @__PURE__ */ new Set()
|
|
43
|
+
};
|
|
44
|
+
const rs = consume(parseGrammar(syntax[ENTRY[kind]]), v, ctx);
|
|
45
|
+
if (rs.has("")) return;
|
|
46
|
+
for (const r of rs) {
|
|
47
|
+
const at = v.length - r.length;
|
|
48
|
+
if (at > ctx.far) Object.assign(ctx, {
|
|
49
|
+
far: at,
|
|
50
|
+
expected: /* @__PURE__ */ new Set()
|
|
51
|
+
});
|
|
52
|
+
if (at === ctx.far) ctx.expected.add("end of query");
|
|
53
|
+
}
|
|
54
|
+
const token = /^[^ ,)]*/.exec(v.slice(ctx.far))[0];
|
|
55
|
+
const expected = [...ctx.expected];
|
|
56
|
+
throw new InvalidValueError({
|
|
57
|
+
message: `@${kind}: ${token ? `unexpected "${token}"` : "unexpected end"} in "${q}", expected ${expected.join(" | ")}`,
|
|
58
|
+
property: `@${kind}`,
|
|
59
|
+
value: q,
|
|
60
|
+
position: ctx.far,
|
|
61
|
+
expected
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/** Twin of ValidQuery<K, S> (query.ts): the query of a media(), container() or supports() call is valid, or why not. */
|
|
65
|
+
const checkQuery = Effect.fnUntraced(function* (kind, q) {
|
|
66
|
+
return yield* Effect.try({
|
|
67
|
+
try: () => checkQueryNow(kind, q),
|
|
68
|
+
catch: (e) => {
|
|
69
|
+
if (isTwinError(e)) return e;
|
|
70
|
+
throw e;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
/** The selector of a `css.global()` call is a <complex-selector-list>, or why not (selector.ts). */
|
|
75
|
+
const checkSelector = Effect.fnUntraced(function* (selector) {
|
|
76
|
+
return yield* Effect.try({
|
|
77
|
+
try: () => checkSelectorNow(selector),
|
|
78
|
+
catch: (e) => {
|
|
79
|
+
if (isTwinError(e)) return e;
|
|
80
|
+
throw e;
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
//#endregion
|
|
85
|
+
export { checkDeclaration, checkDeclarationNow, checkQuery, checkQueryNow, checkSelector, checkValueNow, isDeclarationError };
|