@navecss/core 0.2.0 → 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/dist/vite.d.ts ADDED
@@ -0,0 +1,430 @@
1
+ import { AtomName, AtomDefinition } from './atoms.js';
2
+
3
+ /**
4
+ * The few shapes of Vite's (and Rollup's) own objects the plugin touches, declared here rather
5
+ * than imported: `@navecss/core/vite` takes no dependency and no peer, and a type import from
6
+ * `vite` would make the peer real for every consumer who type-checks it. Each interface is a
7
+ * structural subset of the real one, so Vite's own `Plugin` type accepts the plugin as it is.
8
+ */
9
+ interface LoggerLike {
10
+ warn(message: string, options?: unknown): void;
11
+ }
12
+ interface ResolvedConfigLike {
13
+ readonly root: string;
14
+ readonly command: string;
15
+ /**
16
+ * The config object the host was handed, which every environment of one invocation shares.
17
+ */
18
+ readonly inlineConfig?: object;
19
+ readonly cacheDir?: string;
20
+ /**
21
+ * Set when the config asks for a builder, so one process builds every environment.
22
+ */
23
+ readonly builder?: unknown;
24
+ readonly css?: {
25
+ readonly devSourcemap?: boolean;
26
+ readonly transformer?: string;
27
+ };
28
+ readonly build?: {
29
+ readonly lib?: unknown;
30
+ readonly sourcemap?: unknown;
31
+ };
32
+ readonly logger: LoggerLike;
33
+ /**
34
+ * The plugins of the build, Vite's own among them.
35
+ */
36
+ readonly plugins?: readonly PluginLike[];
37
+ }
38
+ /**
39
+ * A plugin as another plugin finds it in an environment's list: by name, with a `transform` that
40
+ * is a function or Rolldown's `{ handler }` object.
41
+ */
42
+ interface PluginLike {
43
+ readonly name: string;
44
+ readonly transform?: unknown;
45
+ }
46
+ /**
47
+ * A module of a dev server's module graph: its id and URL, the modules that import it and the
48
+ * ones it imports (static and dynamic alike).
49
+ */
50
+ interface GraphModuleLike {
51
+ readonly id: string | null;
52
+ readonly url: string;
53
+ readonly importers: ReadonlySet<GraphModuleLike>;
54
+ readonly importedModules: ReadonlySet<GraphModuleLike>;
55
+ }
56
+ /**
57
+ * The builder `buildApp` is given: its environments by name, and whether each has been built.
58
+ */
59
+ interface BuilderLike {
60
+ readonly environments: Readonly<Record<string, {
61
+ readonly isBuilt: boolean;
62
+ }>>;
63
+ }
64
+ /**
65
+ * The environment a hook runs for: a name, whether it renders for a browser or a server, and the
66
+ * plugins it runs.
67
+ */
68
+ interface EnvironmentLike {
69
+ readonly name: string;
70
+ readonly config: {
71
+ readonly command?: string;
72
+ readonly consumer: string;
73
+ readonly inlineConfig?: object;
74
+ readonly root?: string;
75
+ };
76
+ readonly plugins: readonly PluginLike[];
77
+ }
78
+ /**
79
+ * A location in the shape Rollup reports one: 1-based line, 0-based column.
80
+ */
81
+ interface LogLocation {
82
+ readonly file?: string;
83
+ readonly line: number;
84
+ readonly column: number;
85
+ }
86
+ interface PluginLog {
87
+ readonly message: string;
88
+ readonly id?: string;
89
+ readonly loc?: LogLocation;
90
+ }
91
+ interface IncomingSourceMap {
92
+ readonly sources: readonly string[];
93
+ readonly sourceRoot?: string | undefined;
94
+ readonly sourcesContent?: readonly (string | null)[] | undefined;
95
+ readonly names?: readonly string[] | undefined;
96
+ readonly mappings: string;
97
+ }
98
+ /**
99
+ * What the host tells a `transform` hook about the module besides its text.
100
+ */
101
+ interface TransformMeta {
102
+ readonly moduleType?: string;
103
+ }
104
+ interface TransformContext {
105
+ error(error: PluginLog): never;
106
+ warn(warning: PluginLog): void;
107
+ addWatchFile(id: string): void;
108
+ getCombinedSourcemap(): IncomingSourceMap;
109
+ /**
110
+ The environment the module is being transformed for; `client` when a host gives none.
111
+ */
112
+ readonly environment?: EnvironmentLike;
113
+ /**
114
+ * The host's parse of `code`, an ESTree (read as an `AstNode`).
115
+ */
116
+ parse(code: string, options?: {
117
+ readonly lang?: 'dts' | 'js' | 'jsx' | 'ts' | 'tsx';
118
+ }): unknown;
119
+ /**
120
+ * Resolves `source` as imported from `importer`.
121
+ */
122
+ resolve?(source: string, importer: string): Promise<{
123
+ readonly id: string;
124
+ } | null>;
125
+ /**
126
+ * Loads, and so transforms, the module `options.id`.
127
+ */
128
+ load?(options: {
129
+ readonly id: string;
130
+ }): Promise<unknown>;
131
+ }
132
+ /**
133
+ * What the dev server hands `hotUpdate`: the file that changed.
134
+ */
135
+ interface HotUpdateOptions {
136
+ readonly file: string;
137
+ /**
138
+ * The modules the changed file belongs to, which the update is about to reload.
139
+ */
140
+ readonly modules?: readonly GraphModuleLike[];
141
+ }
142
+ /**
143
+ * The environment `hotUpdate` runs in: its module graph, and the channel to its client.
144
+ */
145
+ interface HotUpdateContext {
146
+ readonly environment: {
147
+ readonly config?: {
148
+ readonly command?: string;
149
+ readonly consumer?: string;
150
+ readonly inlineConfig?: object;
151
+ };
152
+ readonly hot: {
153
+ send(payload: {
154
+ type: 'full-reload';
155
+ }): void;
156
+ };
157
+ readonly moduleGraph: {
158
+ getModuleById(id: string): unknown;
159
+ invalidateModule(module: never): void;
160
+ };
161
+ readonly name: string;
162
+ transformRequest?(url: string): Promise<unknown>;
163
+ };
164
+ }
165
+ interface BundleContext {
166
+ error(error: PluginLog): never;
167
+ warn(warning: PluginLog | string): void;
168
+ readonly environment?: EnvironmentLike;
169
+ }
170
+ /**
171
+ * What the module graph holds about one module: its transformed text, and who imports it.
172
+ */
173
+ interface ModuleInfoLike {
174
+ readonly code: string | null;
175
+ readonly importers: readonly string[];
176
+ readonly dynamicImporters: readonly string[];
177
+ /**
178
+ * The ids the module imports, statically and dynamically, externals included.
179
+ */
180
+ readonly importedIds?: readonly string[];
181
+ readonly dynamicallyImportedIds?: readonly string[];
182
+ }
183
+ /**
184
+ * What `renderChunk` and `buildEnd` are given: the environment, and the ways to fail or warn.
185
+ */
186
+ interface RenderContext {
187
+ error(error: PluginLog | string): never;
188
+ warn(warning: PluginLog | string): void;
189
+ readonly environment: EnvironmentLike;
190
+ /**
191
+ * The ids of every module the environment's build loaded, externals included.
192
+ */
193
+ getModuleIds?(): IterableIterator<string>;
194
+ /**
195
+ * What the module graph holds about the module `id`, or `null` when it holds none.
196
+ */
197
+ getModuleInfo?(id: string): ModuleInfoLike | null;
198
+ /**
199
+ * Resolves `source` as imported from `importer`.
200
+ */
201
+ resolve?(source: string, importer?: string): Promise<{
202
+ readonly id: string;
203
+ } | null>;
204
+ /**
205
+ * The host's parse of `code`, an ESTree (read as an `AstNode`).
206
+ */
207
+ parse?(code: string): unknown;
208
+ }
209
+ interface RenderedChunk {
210
+ readonly modules: Readonly<Record<string, unknown>>;
211
+ }
212
+ interface BundleEntry {
213
+ readonly type: string;
214
+ readonly fileName: string;
215
+ readonly source?: string | Uint8Array;
216
+ }
217
+ interface TransformResultLike {
218
+ readonly code: string;
219
+ readonly map: string;
220
+ }
221
+
222
+ /**
223
+ * The options that choose which atoms the Vite plugin ships, and their validation. A value a
224
+ * type would refuse in TypeScript is refused here too, so a JavaScript config gets the same
225
+ * answer; every text opens `navePlugin(): `, the prefix of the plugin's config-level messages.
226
+ */
227
+
228
+ interface UsedAtomOptions {
229
+ /**
230
+ * Which atoms the build ships. `'used'` (the default): the atoms your `cx()` calls and your
231
+ * written Nave classes name, plus those in `keep` and `keepFor`. Under the default the build
232
+ * filters the atomic layer of every stylesheet it can reach, and the dev server serves the same
233
+ * set as far as it has read; a stylesheet imported with `?inline` or `?raw` ships every atom
234
+ * with a warning; a `cx()` call whose atoms the build cannot read fails the build, and is an
235
+ * error in the dev server.
236
+ * `'all'`: every atom, and no `cx()` call is read, as with the PostCSS plugin.
237
+ */
238
+ atomic?: 'all' | 'used';
239
+ /**
240
+ * Atoms always shipped, whether or not the build reads a use of them: every atom your own
241
+ * `cx.dynamic()` calls can take, and the atom of each Nave class written where the build cannot
242
+ * read it, such as in a server template or in CMS text.
243
+ */
244
+ keep?: readonly AtomName[];
245
+ /**
246
+ * By package name: the atoms a dependency's own `cx()` calls can produce, for a package whose
247
+ * calls the build cannot read. They ship as if they were in `keep`, beside the atoms of the
248
+ * package's calls the build does read. The calls it cannot read are not changed, so any other
249
+ * atom they apply has no rule unless the build ships it for another reason. An empty list is
250
+ * accepted: it says those calls produce no atom, so the list adds none, and a `cx.dynamic()` call
251
+ * in the package still fails the build, as it does with no entry. A package in your own workspace
252
+ * is your code, not a dependency. The entry stands in for the package's own calls only: a
253
+ * re-export of `cx` in the package that the build reads and a module of yours takes (imports,
254
+ * re-exports or reads off a namespace, directly or through re-exports of it that the build reads,
255
+ * as `export ... from` or an import exported unchanged, in this package or another) still fails
256
+ * the build, because the calls your module makes through it would ship with no rule, and the
257
+ * message says how to clear it. Listing here a package that only re-exports it does not clear a
258
+ * take of yours, since a re-export is not a call. A server build that leaves the package external
259
+ * does not read it, so a take only your server code makes is judged by what the client build
260
+ * read: it fails the build as above when the client build read the re-export it takes and the
261
+ * build can read the take, and gets a warning naming `ssr.noExternal` when the build cannot tell,
262
+ * because no environment read the file the server loads, or your file reaches the package in a
263
+ * way the build cannot read as a take (a `require()`, say, or a `#` import); with separate client
264
+ * and server commands, the next client command judges what the last build of each server recorded
265
+ * of server files that still exist.
266
+ */
267
+ keepFor?: Readonly<Record<string, readonly AtomName[]>>;
268
+ /**
269
+ * Modules that re-export `cx` from `@navecss/core/cx` unchanged, as
270
+ * `export { cx } from '@navecss/core/cx'`, in your code or in a dependency: a file that imports
271
+ * `cx` from one is read as if it imported it from `@navecss/core/cx`. The build follows a listed
272
+ * module one step. A relative entry (`'./src/ui/index.ts'`) is a path from Vite's `root`. A
273
+ * package name or subpath, an alias or an absolute path matches an import written the same way.
274
+ * A `#` entry matches an import written the same way only where that import resolves to a listed
275
+ * file, since a `#` import resolves through the `package.json` nearest the file that writes it.
276
+ * Every entry also matches an import that resolves to its file through a specifier naming that
277
+ * file or, for an `index` file, its directory; in your code, an import that reaches the file
278
+ * through any other specifier fails the build instead. A relative entry that resolves to no file
279
+ * is ignored, and so is an entry naming `@navecss/core/cx`, which the build always reads. The
280
+ * same setting, with the same entries, as `@navecss/eslint-plugin`'s `cxModules`, which reads a
281
+ * relative entry from the working directory instead of Vite's `root`.
282
+ */
283
+ cxModules?: readonly string[];
284
+ }
285
+
286
+ interface HtmlHook {
287
+ readonly order: 'pre';
288
+ handler(html: string, context: {
289
+ readonly filename?: string;
290
+ }): undefined;
291
+ }
292
+ interface NaveCollectPlugin {
293
+ readonly name: 'nave:collect';
294
+ readonly enforce: 'post';
295
+ transform(this: TransformContext, code: string, id: string, meta?: TransformMeta): Promise<undefined>;
296
+ readonly transformIndexHtml: HtmlHook;
297
+ buildStart(this: RenderContext): Promise<void>;
298
+ buildEnd(this: RenderContext, error?: unknown): Promise<void>;
299
+ }
300
+
301
+ /**
302
+ * A module worker is bundled by a build of its own, which runs the plugins of `worker.plugins`
303
+ * and none of the build's. The code it ships is code the build reads, so the plugin adds this one:
304
+ * it reads each module of that build as a module of the client environment, into the state the
305
+ * build's own plugins share, and reports nothing itself (its problems are reported once, with
306
+ * the rest, when the build ends), except that a worker's import of `cx` through an alias fails
307
+ * its own build, since no later step sees the worker's module graph.
308
+ */
309
+
310
+ interface NaveWorkerPlugin {
311
+ readonly name: 'nave:collect-worker';
312
+ readonly enforce: 'post';
313
+ transform(this: TransformContext, code: string, id: string, meta?: TransformMeta): Promise<undefined>;
314
+ buildEnd(this: RenderContext, error?: unknown): Promise<void>;
315
+ }
316
+
317
+ /**
318
+ * The config the plugin adds under the default. `cx.dynamic()` resolves through the map of the
319
+ * atoms in `keep` and every `keepFor` list, handed to it as a `define` constant: static data,
320
+ * folded into the bundle in a build, and in dev the same map behind the console texts. And
321
+ * `@navecss/core` is bundled into every server environment, so that constant folds into a server
322
+ * build's `cx.dynamic()` too, and it is left out of the dev server's prebundling, so a
323
+ * prebundled dependency keeps its import of `cx` and the plugin reads the calls it makes.
324
+ */
325
+
326
+ interface UsedConfig {
327
+ readonly define: Record<string, string>;
328
+ /**
329
+ * The dev server serves `@navecss/core` as its own modules, not one prebundled chunk.
330
+ */
331
+ readonly optimizeDeps: {
332
+ readonly exclude: string[];
333
+ };
334
+ /**
335
+ * A module worker is bundled by a build of its own: this adds the plugin that reads its code.
336
+ */
337
+ readonly worker: {
338
+ readonly plugins: () => NaveWorkerPlugin[];
339
+ };
340
+ }
341
+
342
+ /**
343
+ * Nave Vite plugin: expands `@nave` directives in every stylesheet Vite compiles, fails the build
344
+ * when one survives into its CSS output, and by default filters the atomic layer of every stylesheet it can reach down to the atoms the build reads a use for.
345
+ *
346
+ * Setup:
347
+ * import { navePlugin } from '@navecss/core/vite'
348
+ * export default { plugins: [navePlugin()] } // Nave atoms only, fails on a problem
349
+ * navePlugin({ extend: myAtoms }) // Nave + consumer atoms
350
+ * navePlugin({ extend: './my-atoms.mjs' }) // the same, from a module Vite watches
351
+ * navePlugin({ onUnknown: 'warn' }) // report a problem and skip it
352
+ * navePlugin({ keep: ['grid'] }) // atoms a cx.dynamic() call can take
353
+ * navePlugin({ cxModules: ['./src/ui/index.ts'] }) // modules that re-export cx
354
+ * navePlugin({ atomic: 'all' }) // ship every atom, read no cx() call
355
+ *
356
+ * `navePlugin()` returns two plain Vite plugin objects with no dependency and no peer, in an array
357
+ * that `plugins` takes as one entry. The first runs in Vite's normal order, after Vite's own CSS
358
+ * step, so a stylesheet reached through `@import`, a Sass or Less file, a CSS Module, and a Vue
359
+ * or Svelte style block are all read as the CSS they compile to. It never runs before Vite's CSS
360
+ * step: that order misses `@import`-reached files and breaks Sass `@mixin`. The second runs in
361
+ * post order and reads the JavaScript. Neither adds runtime machinery to the browser bundle.
362
+ */
363
+
364
+ interface NaveViteOptions extends UsedAtomOptions {
365
+ /**
366
+ * Consumer-defined atoms merged with Nave built-in atoms. Consumer atoms win on name collision.
367
+ * These atoms resolve via @nave only. No global class. Not available in cx().
368
+ *
369
+ * A string is a path to a module instead, resolved against Vite's project root, whose default
370
+ * export is the atom map. The module is loaded again whenever its bytes change and Vite watches
371
+ * it, so editing it re-runs the stylesheets that use it with no restart. An atom object written
372
+ * inline here is not a file Vite can watch.
373
+ */
374
+ extend?: Record<string, AtomDefinition> | string;
375
+ /**
376
+ * Behaviour on a problem in a @nave directive: an unknown atom name, no atom named at all,
377
+ * anything but a name between the names (a comma, a string), a {} block, or a place the
378
+ * directive cannot expand. Under 'error', every such problem in one stylesheet is reported in
379
+ * one error.
380
+ * 'warn' — log and skip
381
+ * 'error' — fail the build (default)
382
+ * 'ignore' — silently skip
383
+ */
384
+ onUnknown?: 'warn' | 'error' | 'ignore';
385
+ }
386
+ /**
387
+ * The first plugin object. Its `name` is the public string `nave`, the prefix of every message it
388
+ * prints.
389
+ */
390
+ interface NaveVitePlugin {
391
+ readonly name: 'nave';
392
+ config(config?: unknown, env?: {
393
+ readonly command?: string;
394
+ }): UsedConfig | undefined;
395
+ configEnvironment(name: string, options: {
396
+ readonly consumer?: string;
397
+ }): {
398
+ resolve: {
399
+ noExternal: string[];
400
+ };
401
+ } | undefined;
402
+ configResolved(config: ResolvedConfigLike): void;
403
+ configureServer(server: unknown): void;
404
+ closeBundle(this: {
405
+ readonly environment?: object;
406
+ }): void;
407
+ readonly buildApp: {
408
+ handler(this: {
409
+ warn(message: string): void;
410
+ }, builder: BuilderLike): Promise<void>;
411
+ readonly order: 'post';
412
+ };
413
+ transform(this: TransformContext, code: string, id: string): Promise<TransformResultLike | undefined>;
414
+ hotUpdate(this: HotUpdateContext, options: HotUpdateOptions): Promise<never[] | undefined> | never[] | undefined;
415
+ renderChunk(this: RenderContext, code: string, chunk: RenderedChunk): Promise<undefined>;
416
+ readonly generateBundle: {
417
+ handler(this: BundleContext, options: unknown, bundle: Record<string, BundleEntry>): void;
418
+ readonly order: 'post';
419
+ };
420
+ }
421
+ /**
422
+ * What `navePlugin()` returns: the same two plugin objects whatever the options.
423
+ */
424
+ type NavePlugins = [NaveVitePlugin, NaveCollectPlugin];
425
+ /**
426
+ * The Nave Vite plugin: one entry in `plugins`.
427
+ */
428
+ declare function navePlugin(options?: NaveViteOptions): NavePlugins;
429
+
430
+ export { type NavePlugins, type NaveViteOptions, type NaveVitePlugin, navePlugin as default, navePlugin };