@navecss/core 0.1.1 → 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.
@@ -0,0 +1,115 @@
1
+ import { createPositionFinder, tokenize, matchBrackets, readItem, isNaveAtKeyword } from './chunk-NFS2REPQ.js';
2
+
3
+ // src/directive/find-survivors.ts
4
+ var NATURAL_STOP_CHARS = /* @__PURE__ */ new Set(["\n", ";", "}"]);
5
+ function naturalTextAfter(css, offset) {
6
+ let end = css.length;
7
+ for (let i = offset; i < css.length; i++) {
8
+ if (NATURAL_STOP_CHARS.has(css[i])) {
9
+ end = i;
10
+ break;
11
+ }
12
+ }
13
+ return css.slice(offset, end).trim();
14
+ }
15
+ function isStructural(token) {
16
+ return token.type !== "whitespace-token" && token.type !== "comment";
17
+ }
18
+ function skipInert(tokens, i, limit) {
19
+ let j = i;
20
+ while (j < limit && !isStructural(tokens[j])) j++;
21
+ return j;
22
+ }
23
+ var Scan = class {
24
+ closerFor;
25
+ css;
26
+ survivors = [];
27
+ tokens;
28
+ constructor(css) {
29
+ this.css = css;
30
+ this.tokens = tokenize(css);
31
+ this.closerFor = matchBrackets(this.tokens);
32
+ }
33
+ };
34
+ function scanForNaveTokens(scan, start, end, selector) {
35
+ for (let i = start; i < end; i++) {
36
+ const token = scan.tokens[i];
37
+ if (isNaveAtKeyword(token))
38
+ scan.survivors.push({
39
+ offset: token.startIndex,
40
+ text: naturalTextAfter(scan.css, token.startIndex),
41
+ selector
42
+ });
43
+ }
44
+ }
45
+ function ruleSelector(scan, item) {
46
+ const braceIndex = item.blockStart - 1;
47
+ return scan.css.slice(scan.tokens[item.start].startIndex, scan.tokens[braceIndex].startIndex).trim();
48
+ }
49
+ function childFrameFor(scan, item, selector) {
50
+ if (item.blockStart === void 0 || item.blockEnd === void 0) return void 0;
51
+ const childSelector = item.kind === "rule" ? ruleSelector(scan, item) : selector;
52
+ return {
53
+ i: skipInert(scan.tokens, item.blockStart, item.blockEnd),
54
+ limit: item.blockEnd,
55
+ selector: childSelector
56
+ };
57
+ }
58
+ function preludeEnd(item) {
59
+ return item.blockStart === void 0 ? item.end : item.blockStart - 1;
60
+ }
61
+ function visitItem(scan, item, selector) {
62
+ switch (item.kind) {
63
+ case "at-rule":
64
+ case "rule": {
65
+ scanForNaveTokens(scan, item.start, preludeEnd(item), selector);
66
+ return childFrameFor(scan, item, selector);
67
+ }
68
+ case "declaration":
69
+ case "invalid": {
70
+ scanForNaveTokens(scan, item.start, item.end, selector);
71
+ return void 0;
72
+ }
73
+ }
74
+ }
75
+ function walkBlock(scan, start, limit, selector) {
76
+ const stack = [{ i: skipInert(scan.tokens, start, limit), limit, selector }];
77
+ while (stack.length > 0) {
78
+ const frame = stack.at(-1);
79
+ if (frame.i >= frame.limit) {
80
+ stack.pop();
81
+ continue;
82
+ }
83
+ const item = readItem(scan.tokens, frame.i, frame.limit, scan.closerFor);
84
+ frame.i = skipInert(scan.tokens, item.end, frame.limit);
85
+ const child = visitItem(scan, item, frame.selector);
86
+ if (child) stack.push(child);
87
+ }
88
+ }
89
+ function findSurvivors(css) {
90
+ const scan = new Scan(css);
91
+ walkBlock(scan, 0, scan.tokens.length, void 0);
92
+ return scan.survivors;
93
+ }
94
+
95
+ // src/directive/findings.ts
96
+ function findingsInText(file, raw) {
97
+ const css = raw.startsWith("\uFEFF") ? raw.slice(1) : raw;
98
+ const positionAt = createPositionFinder(css);
99
+ return findSurvivors(css).map((survivor) => {
100
+ const position = positionAt(survivor.offset);
101
+ return {
102
+ file,
103
+ line: position.line,
104
+ column: position.column + 1,
105
+ text: survivor.text,
106
+ ...survivor.selector !== void 0 && { selector: survivor.selector }
107
+ };
108
+ });
109
+ }
110
+ function formatFinding(finding) {
111
+ const where = finding.selector === void 0 ? "" : ` (in ${finding.selector.replaceAll(/\s+/g, " ")})`;
112
+ return `${finding.file}:${finding.line}:${finding.column}: ${finding.text}${where}`;
113
+ }
114
+
115
+ export { findingsInText, formatFinding };
@@ -0,0 +1,152 @@
1
+ import { findingsInText } from './chunk-UANF3FGO.js';
2
+ import { readFile, stat, realpath, readdir } from 'fs/promises';
3
+ import path from 'path';
4
+
5
+ var NotAStylesheetPathError = class extends Error {
6
+ path;
7
+ constructor(path2) {
8
+ super(`${path2} is not a stylesheet file`);
9
+ this.path = path2;
10
+ this.name = "NotAStylesheetPathError";
11
+ }
12
+ };
13
+ function hasCssExtension(name) {
14
+ return path.extname(name).toLowerCase() === ".css";
15
+ }
16
+ async function entryKind(entry, entryPath, state) {
17
+ if (entry.isDirectory()) return "directory";
18
+ if (entry.isFile()) return hasCssExtension(entry.name) ? "css-file" : "skip";
19
+ if (!entry.isSymbolicLink()) return "skip";
20
+ let targetStats;
21
+ try {
22
+ targetStats = await stat(entryPath);
23
+ } catch {
24
+ if (hasCssExtension(entry.name)) state.unreadablePaths.push(entryPath);
25
+ return "skip";
26
+ }
27
+ if (targetStats.isDirectory()) return "directory";
28
+ if (targetStats.isFile()) return hasCssExtension(entry.name) ? "css-file" : "skip";
29
+ return "skip";
30
+ }
31
+ async function listSubdirectory(entryPath, state) {
32
+ let canonicalPath;
33
+ try {
34
+ canonicalPath = await realpath(entryPath);
35
+ } catch {
36
+ state.unreadablePaths.push(entryPath);
37
+ return [];
38
+ }
39
+ if (state.visitedDirs.has(canonicalPath)) return [];
40
+ state.visitedDirs.add(canonicalPath);
41
+ return listDirectory(entryPath, state);
42
+ }
43
+ async function cssFileIfNew(entryPath, state) {
44
+ let canonicalFile;
45
+ try {
46
+ canonicalFile = await realpath(entryPath);
47
+ } catch {
48
+ state.unreadablePaths.push(entryPath);
49
+ return void 0;
50
+ }
51
+ if (state.reportedRealFiles.has(canonicalFile)) return void 0;
52
+ state.reportedRealFiles.add(canonicalFile);
53
+ return entryPath;
54
+ }
55
+ async function listDirectory(dir, state) {
56
+ let entries;
57
+ try {
58
+ entries = await readdir(dir, { withFileTypes: true });
59
+ } catch {
60
+ state.unreadablePaths.push(dir);
61
+ return [];
62
+ }
63
+ const files = [];
64
+ for (const entry of entries) {
65
+ const entryPath = path.join(dir, entry.name);
66
+ const kind = await entryKind(entry, entryPath, state);
67
+ if (kind === "directory") {
68
+ files.push(...await listSubdirectory(entryPath, state));
69
+ } else if (kind === "css-file") {
70
+ const file = await cssFileIfNew(entryPath, state);
71
+ if (file) files.push(file);
72
+ }
73
+ }
74
+ return files;
75
+ }
76
+ async function listCssFiles(source) {
77
+ const stats = await stat(source);
78
+ if (!stats.isDirectory()) {
79
+ if (!stats.isFile()) throw new NotAStylesheetPathError(source);
80
+ return { files: [source], unreadablePaths: [] };
81
+ }
82
+ const canonicalRoot = await realpath(source);
83
+ const state = {
84
+ reportedRealFiles: /* @__PURE__ */ new Set(),
85
+ unreadablePaths: [],
86
+ visitedDirs: /* @__PURE__ */ new Set([canonicalRoot])
87
+ };
88
+ const files = await listDirectory(source, state);
89
+ return { files, unreadablePaths: state.unreadablePaths };
90
+ }
91
+
92
+ // src/directive/check-run.ts
93
+ async function wasFileRead(file, findings) {
94
+ let raw;
95
+ try {
96
+ raw = await readFile(file, "utf8");
97
+ } catch {
98
+ return false;
99
+ }
100
+ for (const finding of findingsInText(file, raw)) findings.push(finding);
101
+ return true;
102
+ }
103
+ async function sourceOutcome(source) {
104
+ try {
105
+ return { kind: "listing", listing: await listCssFiles(source) };
106
+ } catch (error) {
107
+ if (error instanceof NotAStylesheetPathError) return { kind: "not-a-stylesheet" };
108
+ return { kind: "unreadable" };
109
+ }
110
+ }
111
+ function statusFor(hasUnreadableSource, stylesheetsRead, findingCount) {
112
+ if (hasUnreadableSource || stylesheetsRead === 0) return 2;
113
+ return findingCount > 0 ? 1 : 0;
114
+ }
115
+ async function runCheck(source) {
116
+ const findings = [];
117
+ const unreadablePaths = [];
118
+ const notStylesheetPaths = [];
119
+ let stylesheetsRead = 0;
120
+ let hasUnreadableSource = false;
121
+ for (const one of source) {
122
+ const outcome = await sourceOutcome(one);
123
+ if (outcome.kind === "unreadable") {
124
+ hasUnreadableSource = true;
125
+ unreadablePaths.push(one);
126
+ continue;
127
+ }
128
+ if (outcome.kind === "not-a-stylesheet") {
129
+ hasUnreadableSource = true;
130
+ notStylesheetPaths.push(one);
131
+ continue;
132
+ }
133
+ const listing = outcome.listing;
134
+ if (listing.unreadablePaths.length > 0) {
135
+ hasUnreadableSource = true;
136
+ unreadablePaths.push(...listing.unreadablePaths);
137
+ }
138
+ for (const file of listing.files) {
139
+ const wasReadable = await wasFileRead(file, findings);
140
+ if (wasReadable) {
141
+ stylesheetsRead++;
142
+ } else {
143
+ hasUnreadableSource = true;
144
+ unreadablePaths.push(file);
145
+ }
146
+ }
147
+ }
148
+ const status = statusFor(hasUnreadableSource, stylesheetsRead, findings.length);
149
+ return { result: { status, findings, stylesheetsRead }, unreadablePaths, notStylesheetPaths };
150
+ }
151
+
152
+ export { runCheck };
package/dist/cx.d.ts CHANGED
@@ -9,10 +9,13 @@ import { AtomName } from './atoms.js';
9
9
  * unknown name is a compile error.
10
10
  * cx.raw(...) — any class string, returned untouched. The declared way to
11
11
  * step outside the system.
12
+ * cx.dynamic(name) — one atom chosen at run time, for a name the Vite plugin's build
13
+ * cannot read (listed in the plugin's `keep` option).
12
14
  *
13
- * Both accept falsy arguments (undefined, null, false) and filter them out, so
14
- * conditional classes work the same on either side. Both return a
15
- * space-separated class string for className={}.
15
+ * cx() and cx.raw() accept falsy arguments (undefined, null, false) and filter
16
+ * them out, so conditional classes work the same on either side. Both return a
17
+ * space-separated class string for className={}. cx.dynamic() takes one atom
18
+ * name, or a falsy value, and returns that atom's class, or an empty string.
16
19
  *
17
20
  * Validation, not just autocomplete:
18
21
  * cx() takes AtomName, so a typo'd name ('interactve'), a name typed from
@@ -40,6 +43,14 @@ import { AtomName } from './atoms.js';
40
43
  * An atom name held in a variable needs a literal type. `const n = 'flex'`
41
44
  * is one; a let binding, an array element or an object property widens to
42
45
  * string, so annotate it with the exported AtomName type (or `as const`).
46
+ * Under the Vite plugin the build reads the value as well as the type, and
47
+ * only a value it can list builds. It can list a string literal, null,
48
+ * undefined and false; a condition choosing between values it can list;
49
+ * and a binding in the same file that is never assigned again (a const,
50
+ * say) and is bound to a value it can list, another such binding included.
51
+ * An array element or an object property fails the build whatever its
52
+ * type. To choose by a value, call cx() once per case and pick between the
53
+ * results: ({ row: cx('flex'), grid: cx('grid') })[variant].
43
54
  *
44
55
  * Why cx.raw() never maps:
45
56
  * cx() resolves an atom name to that atom's global class, so cx('container')
@@ -51,10 +62,11 @@ import { AtomName } from './atoms.js';
51
62
  * relative, absolute, gap, truncate, interactive.
52
63
  *
53
64
  * What is NOT checked:
54
- * Nothing here looks at the rest of the className attribute. A bare string
55
- * sitting beside these calls is not seen by anything, so cx.raw() is a
56
- * DECLARED escape channel (greppable: `grep -r 'cx.raw'`), not an enforced
57
- * one.
65
+ * Nothing here looks at the rest of the className attribute. @navecss/eslint-plugin does:
66
+ * install it for an ENFORCED escape channel, reporting an undeclared literal class written
67
+ * in className and requiring a reason on a cx.raw() call that carries one (a class the
68
+ * project declares as its own passes by design). Without it, cx.raw() is only a DECLARED
69
+ * escape channel (greppable: `grep -r 'cx.raw'`).
58
70
  *
59
71
  * Note on consumer atoms:
60
72
  * Atoms defined via navePlugin({ extend }) are @nave-directive only.
@@ -66,6 +78,14 @@ type Falsy = false | null | undefined;
66
78
  interface Cx {
67
79
  (...args: (AtomName | Falsy)[]): string;
68
80
  raw: (...args: (Falsy | string)[]) => string;
81
+ /**
82
+ * One atom chosen at run time, for a name the build cannot read. Under the Vite plugin the
83
+ * name must be one the plugin ships: list every atom it can take in `keep` (or, for a package,
84
+ * in `keepFor`). Without the plugin it maps through every atom, like `cx()`, except that a
85
+ * name that is no atom returns `''` instead of passing through, so it never carries a class
86
+ * from outside Nave.
87
+ */
88
+ dynamic: (name: AtomName | Falsy) => string;
69
89
  }
70
90
  declare const cx: Cx;
71
91
 
package/dist/cx.js CHANGED
@@ -1,9 +1,14 @@
1
- import { atomClassMap } from './chunk-BVON7XKC.js';
1
+ import { atomClassMap } from './chunk-LIUB4EES.js';
2
2
 
3
3
  // src/cx.ts
4
4
  var cx = (...args) => args.filter(Boolean).map(
5
5
  (arg) => Object.hasOwn(atomClassMap, arg) ? atomClassMap[arg] : arg
6
6
  ).join(" ");
7
7
  cx.raw = (...args) => args.filter(Boolean).join(" ");
8
+ cx.dynamic = (name) => {
9
+ if (!name) return "";
10
+ const map = typeof __NAVE_KEEP_CLASSES__ === "undefined" ? atomClassMap : __NAVE_KEEP_CLASSES__;
11
+ return Object.hasOwn(map, name) ? map[name] : "";
12
+ };
8
13
 
9
14
  export { cx };
@@ -0,0 +1,50 @@
1
+ import { AtomDefinition } from './atoms.js';
2
+
3
+ interface NaveLightningOptions {
4
+ /**
5
+ * Consumer-defined atoms merged with Nave built-in atoms. Consumer atoms win on name collision.
6
+ * These atoms resolve via @nave only. No global class. Not available in cx().
7
+ *
8
+ * An object only: `expand` is synchronous, for `transform()`, so it cannot load a module.
9
+ * Import your atoms into the script that calls `navePlugin()`.
10
+ */
11
+ extend?: Record<string, AtomDefinition>;
12
+ /**
13
+ * Behaviour on a problem in a @nave directive: an unknown atom name, no atom named at all,
14
+ * anything but a name between the names (a comma, a string), a {} block, or a place the
15
+ * directive cannot expand. Under 'error', every such problem in one stylesheet is reported in
16
+ * one thrown error.
17
+ * 'warn' — print each with `console.warn` and skip it
18
+ * 'error' — throw (default)
19
+ * 'ignore' — silently skip
20
+ */
21
+ onUnknown?: 'warn' | 'error' | 'ignore';
22
+ }
23
+ /**
24
+ * What `navePlugin()` returns: `expand` for `transform()`, and `resolver` for `bundleAsync()`.
25
+ */
26
+ interface NaveLightningAdapter {
27
+ /**
28
+ * Expands the directives of `code` (the stylesheet's text, or its bytes) and returns the result
29
+ * as bytes with its source map, ready to pass to `transform()` as `code` and `inputSourceMap`.
30
+ * `filename` is what a message names.
31
+ */
32
+ expand(code: string | Uint8Array, filename: string): {
33
+ code: Uint8Array;
34
+ map: string;
35
+ };
36
+ /**
37
+ * For `bundleAsync()`: `read` reads a file and returns its expanded text. It returns no source
38
+ * map, and the inserted text adds no line breaks, so line numbers hold. A leading byte order
39
+ * mark is dropped, since the file is joined into a bundle, where one would sit mid-way.
40
+ */
41
+ resolver: {
42
+ read(filePath: string): string;
43
+ };
44
+ }
45
+ /**
46
+ * The Lightning CSS adapter: `expand` for `transform()` and `resolver` for `bundleAsync()`.
47
+ */
48
+ declare function navePlugin(options?: NaveLightningOptions): NaveLightningAdapter;
49
+
50
+ export { type NaveLightningAdapter, type NaveLightningOptions, navePlugin as default, navePlugin };
@@ -0,0 +1,42 @@
1
+ import { splitByteOrderMark, warningTexts, foldedText } from './chunk-IZQLFUQU.js';
2
+ import { validateExtendAtomsHostFree } from './chunk-R6JJZGXC.js';
3
+ import { snapshotExtendMap, expandText } from './chunk-S7DZUVV3.js';
4
+ import './chunk-NFS2REPQ.js';
5
+ import './chunk-LIUB4EES.js';
6
+ import { readFileSync } from 'fs';
7
+
8
+ function report(diagnostics, file, extend, onUnknown) {
9
+ if (onUnknown === "ignore" || diagnostics.length === 0) return;
10
+ if (onUnknown === "warn") {
11
+ for (const text of warningTexts(diagnostics, file, extend)) console.warn(text);
12
+ return;
13
+ }
14
+ throw new Error(foldedText(diagnostics, file, extend));
15
+ }
16
+ function navePlugin(options = {}) {
17
+ const onUnknown = options.onUnknown ?? "error";
18
+ const extend = snapshotExtendMap(options.extend ?? {});
19
+ validateExtendAtomsHostFree(extend);
20
+ const expandToText = (text, file) => {
21
+ const result = expandText(text, { extend, onUnknown, from: file });
22
+ report(result.diagnostics, file, extend, onUnknown);
23
+ return result;
24
+ };
25
+ return {
26
+ expand(code, filename) {
27
+ const raw = typeof code === "string" ? code : new TextDecoder("utf-8", { ignoreBOM: true }).decode(code);
28
+ const { bom, text } = splitByteOrderMark(raw);
29
+ const { css, map } = expandToText(text, filename);
30
+ return { code: new TextEncoder().encode(bom + css), map };
31
+ },
32
+ resolver: {
33
+ read: (filePath) => {
34
+ const { text } = splitByteOrderMark(readFileSync(filePath, "utf8"));
35
+ return expandToText(text, filePath).css;
36
+ }
37
+ }
38
+ };
39
+ }
40
+ var lightningcss_default = navePlugin;
41
+
42
+ export { lightningcss_default as default, navePlugin };
@@ -12,13 +12,13 @@
12
12
  * WHAT YOU MUST SUPPLY. This entry ships Nave's reset and atomic layers and
13
13
  * imports no token values at all, so every '--nave-' custom property those
14
14
  * two layers read has to come from your own stylesheet, not only the colours.
15
- * A property you do not define is not an error: the declaration that reads it is
16
- * discarded, and the property does NOT fall back to whatever Nave's earlier rules
17
- * set for it, so the element silently loses that piece of styling.
18
- * To pick one that matters, the focus outline on '.nave-focus-ring' is built
19
- * from '--nave-border-width-focus', so a token layer that defines every colour
20
- * and not that width leaves an element carrying that class with no visible
21
- * outline when it is focused.
15
+ * A property you do not define is not an error: a declaration that reads it with
16
+ * no fallback is discarded, and the property does NOT fall back to whatever Nave's
17
+ * earlier rules set for it, so the element silently loses that piece of styling.
18
+ * To pick one, '.nave-border' is a single 'border' shorthand built from
19
+ * '--nave-border-width-sm' and '--nave-color-border-default', so a token layer
20
+ * that defines every width and not that colour leaves an element carrying that
21
+ * class with no border from it at all, not a border in some other colour.
22
22
  *
23
23
  * Nave ships a contract manifest listing the custom properties it requires
24
24
  * ('@navecss/tokens/core-contract'). The manifest is generated by scanning
@@ -0,0 +1 @@
1
+ module.exports = require('./postcss.js').navePlugin
@@ -0,0 +1,2 @@
1
+ import { navePlugin } from './postcss.js'
2
+ export = navePlugin
package/dist/postcss.d.ts CHANGED
@@ -4,11 +4,13 @@ import { AtomDefinition } from './atoms.js';
4
4
  /**
5
5
  * Nave PostCSS plugin — resolves @nave directives.
6
6
  *
7
- * Inlines atomic utility declarations at build time.
8
- * Pseudo rules, @media and @container blocks are emitted as native CSS
9
- * nesting inside the parent rule (`&:focus-visible { … }`), never hoisted
10
- * out as sibling rules. Browser floor: Baseline 2024.
11
- * See https://github.com/navecss/navecss/blob/main/docs/04-adr/0001-native-css-nesting.md
7
+ * A thin adapter over the host-free directive core (`src/directive/`):
8
+ * `plan()` decides what a directive expands to and where it goes, this
9
+ * file only wires the PostCSS plugin lifecycle to `handleAtRule()`
10
+ * (`postcss-at-rule.ts`), which walks the AST to answer `plan()`'s three
11
+ * facts and splices its result back in as PostCSS nodes. Setup, options and
12
+ * observable behaviour are unchanged except where this package's CHANGELOG
13
+ * says so.
12
14
  *
13
15
  * Setup:
14
16
  * import { navePlugin } from '@navecss/core/postcss'
@@ -16,6 +18,13 @@ import { AtomDefinition } from './atoms.js';
16
18
  * navePlugin({ extend: myAtoms }) // Nave + consumer atoms
17
19
  * navePlugin({ onUnknown: 'warn' }) // Log and skip instead of failing the build
18
20
  *
21
+ * `extend` is trusted, consumer-authored code (your build config, or the module a path names),
22
+ * which can already run arbitrary JavaScript at build time: it is not sanitised input. Every
23
+ * declaration, pseudo selector key, and media/container condition an atom carries is still
24
+ * parsed, and one that does not parse as exactly that one construct is refused, since a typo
25
+ * there is otherwise silent CSS injection into the generated output rather than a build error
26
+ * at the point of the mistake.
27
+ *
19
28
  * Consumer atoms:
20
29
  * import type { AtomDefinition } from '@navecss/core/postcss'
21
30
  * import { media } from '@navecss/tokens/breakpoints'
@@ -45,11 +54,23 @@ interface NavePluginOptions {
45
54
  * Consumer-defined atoms merged with Nave built-in atoms.
46
55
  * Consumer atoms win on name collision — your system owns its vocabulary.
47
56
  * These atoms resolve via @nave only. No global class. Not available in cx().
57
+ *
58
+ * A string is a path to a module instead, resolved against `process.cwd()`
59
+ * at construction (a path that names no file throws right there, naming
60
+ * the path and the directory; a package name is not looked up), then
61
+ * loaded for its default export on every run and re-read whenever the
62
+ * file's own bytes change (the modules it imports are not). Pass a
63
+ * path when your host's build cache needs to see it as a dependency: an
64
+ * inline object is invisible to a cached host's own cache key. A path
65
+ * makes the plugin async: use `process(css).then(cb)`, not the sync `.css`
66
+ * getter.
48
67
  */
49
- extend?: Record<string, AtomDefinition>;
68
+ extend?: Record<string, AtomDefinition> | string;
50
69
  /**
51
- * Behaviour on an unknown atom name, or a @nave directive that names no
52
- * atom at all.
70
+ * Behaviour on a problem in a @nave directive: an unknown atom name, no
71
+ * atom named at all, anything but a name between the names (a comma, a
72
+ * string), a {} block, or a place the directive cannot expand. Under
73
+ * 'error', every such problem in one stylesheet is reported in one error.
53
74
  * 'warn' — log and skip
54
75
  * 'error' — throw, failing the build (default)
55
76
  * 'ignore' — silently skip
@@ -61,4 +82,4 @@ declare const navePlugin: {
61
82
  postcss: boolean;
62
83
  };
63
84
 
64
- export { AtomDefinition, type NavePluginOptions, navePlugin };
85
+ export { AtomDefinition, type NavePluginOptions, navePlugin as default, navePlugin };