praxis-kit 4.1.3 → 5.0.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/_shared/diagnostics.d.ts +10 -1
- package/dist/_shared/diagnostics.js +12 -0
- package/dist/{chunk-R2RKHZNX.js → chunk-SKAY22CZ.js} +67 -33
- package/dist/codemod/index.js +39 -22
- package/dist/contract/index.d.ts +18 -2
- package/dist/eslint/index.js +16 -16
- package/dist/lit/index.d.ts +18 -2
- package/dist/lit/index.js +64 -33
- package/dist/preact/index.d.ts +18 -2
- package/dist/preact/index.js +66 -33
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +1 -1
- package/dist/react/legacy.d.ts +2 -2
- package/dist/react/legacy.js +1 -1
- package/dist/{react-options-XrRof248.d.ts → react-options-D6rRB2gJ.d.ts} +18 -2
- package/dist/solid/index.d.ts +18 -2
- package/dist/solid/index.js +109 -64
- package/dist/svelte/Polymorphic.svelte +146 -0
- package/dist/svelte/index.d.ts +34 -3
- package/dist/svelte/index.js +67 -33
- package/dist/vite-plugin/index.d.ts +31 -0
- package/dist/vite-plugin/index.js +32 -15
- package/dist/vue/index.d.ts +18 -2
- package/dist/vue/index.js +67 -33
- package/dist/web/index.d.ts +18 -2
- package/dist/web/index.js +64 -33
- package/package.json +60 -7
package/dist/svelte/index.js
CHANGED
|
@@ -1760,17 +1760,22 @@ var RuleValidator = class _RuleValidator extends InvariantBase {
|
|
|
1760
1760
|
};
|
|
1761
1761
|
|
|
1762
1762
|
// ../../lib/contract/src/children/children-evaluator.ts
|
|
1763
|
+
var isTextLike = (child) => isString(child) || isNumber(child);
|
|
1763
1764
|
var ChildrenEvaluator = class extends InvariantBase {
|
|
1764
1765
|
#context;
|
|
1765
1766
|
#rules;
|
|
1766
1767
|
#ruleNames;
|
|
1767
1768
|
#matcher;
|
|
1768
1769
|
#ruleValidator;
|
|
1769
|
-
|
|
1770
|
+
#exclusiveChildren;
|
|
1771
|
+
#allowText;
|
|
1772
|
+
constructor(rules, diagnostics, context = "Component", options = {}) {
|
|
1770
1773
|
super(diagnostics);
|
|
1771
1774
|
this.#context = context;
|
|
1772
1775
|
this.#rules = rules.map((r) => normalizeChildRule(r));
|
|
1773
1776
|
this.#ruleNames = this.#rules.map((r) => r.name);
|
|
1777
|
+
this.#exclusiveChildren = options.exclusiveChildren ?? false;
|
|
1778
|
+
this.#allowText = options.allowText ?? true;
|
|
1774
1779
|
iterate.forEach(this.#rules, (rule) => {
|
|
1775
1780
|
const { name, position, cardinality } = rule;
|
|
1776
1781
|
if ((position === "first" || position === "last") && (cardinality.kind === "unbounded" || cardinality.max > 1)) {
|
|
@@ -1784,8 +1789,17 @@ var ChildrenEvaluator = class extends InvariantBase {
|
|
|
1784
1789
|
}
|
|
1785
1790
|
evaluate(children) {
|
|
1786
1791
|
if (!this.active) return;
|
|
1787
|
-
const {
|
|
1792
|
+
const {
|
|
1793
|
+
matrix,
|
|
1794
|
+
unexpectedIndices: rawUnexpectedIndices,
|
|
1795
|
+
ambiguousIndices
|
|
1796
|
+
} = this.#matcher.match(children);
|
|
1788
1797
|
this.#ruleValidator.validate(this.#rules, matrix, children.length);
|
|
1798
|
+
const unexpectedIndices = new Set(
|
|
1799
|
+
[...rawUnexpectedIndices].filter(
|
|
1800
|
+
(ci) => isTextLike(children[ci]) ? this.#allowText === false : this.#exclusiveChildren
|
|
1801
|
+
)
|
|
1802
|
+
);
|
|
1789
1803
|
if (unexpectedIndices.size === 0 && ambiguousIndices.size === 0) return;
|
|
1790
1804
|
const violating = [...unexpectedIndices, ...ambiguousIndices].sort((a, b) => a - b);
|
|
1791
1805
|
iterate.forEach(violating, (ci) => {
|
|
@@ -1907,8 +1921,11 @@ function metadata(name = "metadata") {
|
|
|
1907
1921
|
function firstOptional(name, tag) {
|
|
1908
1922
|
return { name, match: isTag(tag), cardinality: { max: 1 }, position: "first" };
|
|
1909
1923
|
}
|
|
1910
|
-
function contract(children) {
|
|
1911
|
-
return { diagnostics: warnDiagnostics, children };
|
|
1924
|
+
function contract(children, options) {
|
|
1925
|
+
return { diagnostics: warnDiagnostics, children, ...options };
|
|
1926
|
+
}
|
|
1927
|
+
function closedContract(children) {
|
|
1928
|
+
return contract(children, { exclusiveChildren: true });
|
|
1912
1929
|
}
|
|
1913
1930
|
function ariaContract(aria) {
|
|
1914
1931
|
return { diagnostics: warnDiagnostics, aria };
|
|
@@ -1934,8 +1951,10 @@ var VOID_TAGS = [
|
|
|
1934
1951
|
];
|
|
1935
1952
|
var TEXT_ONLY_TAGS = ["option", "script", "style", "textarea", "title"];
|
|
1936
1953
|
var LANDMARK_TAGS = ["article", "aside", "footer", "header", "main", "nav"];
|
|
1937
|
-
var listContract =
|
|
1938
|
-
|
|
1954
|
+
var listContract = closedContract([
|
|
1955
|
+
{ name: "list-item", match: isTag("li", ...METADATA_TAGS) }
|
|
1956
|
+
]);
|
|
1957
|
+
var tableContract = closedContract([
|
|
1939
1958
|
firstOptional("caption", "caption"),
|
|
1940
1959
|
{ name: "colgroup", match: isTag("colgroup") },
|
|
1941
1960
|
{ name: "thead", match: isTag("thead"), cardinality: { max: 1 } },
|
|
@@ -1943,29 +1962,31 @@ var tableContract = contract([
|
|
|
1943
1962
|
{ name: "tfoot", match: isTag("tfoot"), cardinality: { max: 1 } },
|
|
1944
1963
|
{ name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
|
|
1945
1964
|
]);
|
|
1946
|
-
var tableBodyContract =
|
|
1965
|
+
var tableBodyContract = closedContract([
|
|
1947
1966
|
{ name: "table-row", match: isTag("tr", ...METADATA_TAGS) }
|
|
1948
1967
|
]);
|
|
1949
|
-
var tableRowContract =
|
|
1968
|
+
var tableRowContract = closedContract([
|
|
1950
1969
|
{ name: "table-cell", match: isTag("td", "th", ...METADATA_TAGS) }
|
|
1951
1970
|
]);
|
|
1952
|
-
var colgroupContract =
|
|
1953
|
-
|
|
1971
|
+
var colgroupContract = closedContract([
|
|
1972
|
+
{ name: "column", match: isTag("col", "template") }
|
|
1973
|
+
]);
|
|
1974
|
+
var dlContract = closedContract([
|
|
1954
1975
|
{ name: "term", match: isTag("dt") },
|
|
1955
1976
|
{ name: "description", match: isTag("dd") },
|
|
1956
1977
|
{ name: "group", match: isTag("div") },
|
|
1957
1978
|
metadata()
|
|
1958
1979
|
]);
|
|
1959
|
-
var selectContract =
|
|
1980
|
+
var selectContract = closedContract([
|
|
1960
1981
|
{ name: "option", match: isTag("option", "optgroup", "hr", ...METADATA_TAGS) }
|
|
1961
1982
|
]);
|
|
1962
|
-
var optgroupContract =
|
|
1983
|
+
var optgroupContract = closedContract([
|
|
1963
1984
|
{ name: "option", match: isTag("option", ...METADATA_TAGS) }
|
|
1964
1985
|
]);
|
|
1965
|
-
var datalistContract =
|
|
1986
|
+
var datalistContract = closedContract([
|
|
1966
1987
|
{ name: "option", match: isTag("option", ...METADATA_TAGS) }
|
|
1967
1988
|
]);
|
|
1968
|
-
var pictureContract =
|
|
1989
|
+
var pictureContract = closedContract([
|
|
1969
1990
|
{ name: "source", match: isTag("source", ...METADATA_TAGS) },
|
|
1970
1991
|
{ name: "image", match: isTag("img"), cardinality: { min: 1, max: 1 }, position: "last" }
|
|
1971
1992
|
]);
|
|
@@ -1981,23 +2002,18 @@ var mediaContract = contract([
|
|
|
1981
2002
|
metadata(),
|
|
1982
2003
|
{ name: "content", match: isOpenContent("source", "track", ...METADATA_TAGS) }
|
|
1983
2004
|
]);
|
|
1984
|
-
var headContract =
|
|
2005
|
+
var headContract = closedContract([
|
|
1985
2006
|
{
|
|
1986
2007
|
name: "metadata",
|
|
1987
2008
|
match: isTag("base", "link", "meta", "noscript", "script", "style", "template", "title")
|
|
1988
2009
|
}
|
|
1989
2010
|
]);
|
|
1990
|
-
var htmlContract =
|
|
2011
|
+
var htmlContract = closedContract([
|
|
1991
2012
|
{ name: "head", match: isTag("head"), cardinality: { min: 1, max: 1 }, position: "first" },
|
|
1992
2013
|
{ name: "body", match: isTag("body"), cardinality: { min: 1, max: 1 } }
|
|
1993
2014
|
]);
|
|
1994
|
-
var voidContract = contract([]);
|
|
1995
|
-
var textOnlyContract = contract([
|
|
1996
|
-
{
|
|
1997
|
-
name: "text",
|
|
1998
|
-
match: (child) => isString(child) || isNumber(child)
|
|
1999
|
-
}
|
|
2000
|
-
]);
|
|
2015
|
+
var voidContract = contract([], { exclusiveChildren: true, allowText: false });
|
|
2016
|
+
var textOnlyContract = contract([], { exclusiveChildren: true });
|
|
2001
2017
|
var landmarkContract = ariaContract([landmarkRoleRule, landmarkNameAdvisory]);
|
|
2002
2018
|
var dialogContract = ariaContract([requireAccessibleName]);
|
|
2003
2019
|
var menuContract = ariaContract([requireAccessibleName]);
|
|
@@ -2042,9 +2058,15 @@ var htmlContracts = {
|
|
|
2042
2058
|
var htmlDiagnostics = warnDiagnostics2;
|
|
2043
2059
|
function buildEvaluatorMap() {
|
|
2044
2060
|
const map2 = /* @__PURE__ */ new Map();
|
|
2045
|
-
iterate.forEachEntry(htmlContracts, (tag, { children }) => {
|
|
2046
|
-
if (children?.length) {
|
|
2047
|
-
map2.set(
|
|
2061
|
+
iterate.forEachEntry(htmlContracts, (tag, { children, exclusiveChildren, allowText }) => {
|
|
2062
|
+
if (children?.length || exclusiveChildren || allowText === false) {
|
|
2063
|
+
map2.set(
|
|
2064
|
+
tag,
|
|
2065
|
+
new ChildrenEvaluator(children ?? [], htmlDiagnostics, `<${tag}>`, {
|
|
2066
|
+
exclusiveChildren,
|
|
2067
|
+
allowText
|
|
2068
|
+
})
|
|
2069
|
+
);
|
|
2048
2070
|
}
|
|
2049
2071
|
});
|
|
2050
2072
|
return map2;
|
|
@@ -2255,7 +2277,7 @@ function definePipeline(factory) {
|
|
|
2255
2277
|
}
|
|
2256
2278
|
|
|
2257
2279
|
// ../core/src/options/resolve-factory-options.ts
|
|
2258
|
-
import { silentDiagnostics } from "../_shared/diagnostics.js";
|
|
2280
|
+
import { resolveDiagnostics, silentDiagnostics } from "../_shared/diagnostics.js";
|
|
2259
2281
|
var EMPTY_VARIANT_KEYS = /* @__PURE__ */ new Set();
|
|
2260
2282
|
function composeNormalizers(normalizers, fn) {
|
|
2261
2283
|
if (!normalizers?.length) return fn;
|
|
@@ -2276,7 +2298,7 @@ function resolveFactoryOptions(options = {}) {
|
|
|
2276
2298
|
const variantKeys = styling?.variants === void 0 ? EMPTY_VARIANT_KEYS : new Set(Object.keys(styling.variants));
|
|
2277
2299
|
return Object.freeze({
|
|
2278
2300
|
defaultTag: options.tag ?? "div",
|
|
2279
|
-
diagnostics: enforcement?.diagnostics
|
|
2301
|
+
diagnostics: resolveDiagnostics(enforcement?.diagnostics, silentDiagnostics),
|
|
2280
2302
|
variantKeys,
|
|
2281
2303
|
...whenDefined("displayName", options.name),
|
|
2282
2304
|
...whenDefined("defaultProps", options.defaults),
|
|
@@ -2289,6 +2311,8 @@ function resolveFactoryOptions(options = {}) {
|
|
|
2289
2311
|
...whenDefined("normalizeFn", composedNormalizeFn),
|
|
2290
2312
|
...whenDefined("ariaRules", enforcement?.aria),
|
|
2291
2313
|
...whenDefined("childRules", enforcement?.children),
|
|
2314
|
+
...whenDefined("exclusiveChildren", enforcement?.exclusiveChildren),
|
|
2315
|
+
...whenDefined("allowText", enforcement?.allowText),
|
|
2292
2316
|
...whenDefined("allowedAs", enforcement?.allowedAs),
|
|
2293
2317
|
...whenDefined("precomputedClasses", styling?.precomputedClasses)
|
|
2294
2318
|
});
|
|
@@ -2464,16 +2488,22 @@ function buildCoreRuntime(normalized) {
|
|
|
2464
2488
|
}
|
|
2465
2489
|
|
|
2466
2490
|
// ../../lib/adapter-utils/src/runtime/build-engines.ts
|
|
2467
|
-
function buildEngines(diagnostics, childRules, context) {
|
|
2468
|
-
|
|
2491
|
+
function buildEngines(diagnostics, childRules, context, childrenOptions) {
|
|
2492
|
+
const { exclusiveChildren, allowText } = childrenOptions ?? {};
|
|
2493
|
+
return childRules?.length || exclusiveChildren || allowText === false ? {
|
|
2494
|
+
childrenEvaluator: new ChildrenEvaluator(childRules ?? [], diagnostics, context, {
|
|
2495
|
+
exclusiveChildren,
|
|
2496
|
+
allowText
|
|
2497
|
+
})
|
|
2498
|
+
} : {};
|
|
2469
2499
|
}
|
|
2470
2500
|
|
|
2471
2501
|
// ../../lib/adapter-utils/src/runtime/resolve-adapter-common-options.ts
|
|
2472
|
-
import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics2 } from "../_shared/diagnostics.js";
|
|
2502
|
+
import { throwDiagnostics as throwDiagnostics2, silentDiagnostics as silentDiagnostics2, resolveDiagnostics as resolveDiagnostics2 } from "../_shared/diagnostics.js";
|
|
2473
2503
|
function resolveAdapterCommonOptions(options, defaultName = "PolymorphicComponent", defaultDiagnostics = throwDiagnostics2) {
|
|
2474
2504
|
return {
|
|
2475
2505
|
name: options.name ?? defaultName,
|
|
2476
|
-
diagnostics: options.enforcement?.diagnostics
|
|
2506
|
+
diagnostics: resolveDiagnostics2(options.enforcement?.diagnostics, defaultDiagnostics)
|
|
2477
2507
|
};
|
|
2478
2508
|
}
|
|
2479
2509
|
|
|
@@ -2518,7 +2548,11 @@ function buildRuntime(options) {
|
|
|
2518
2548
|
const { childrenEvaluator } = buildEngines(
|
|
2519
2549
|
normalized.diagnostics,
|
|
2520
2550
|
normalized.enforcement?.children,
|
|
2521
|
-
normalized.name
|
|
2551
|
+
normalized.name,
|
|
2552
|
+
{
|
|
2553
|
+
exclusiveChildren: normalized.enforcement?.exclusiveChildren,
|
|
2554
|
+
allowText: normalized.enforcement?.allowText
|
|
2555
|
+
}
|
|
2522
2556
|
);
|
|
2523
2557
|
const filterProps = composeFilter(ownedKeys, normalized.filterProps);
|
|
2524
2558
|
const slotValidator = new SlotValidator(normalized.name, normalized.diagnostics, "Snippet");
|
|
@@ -165,6 +165,13 @@ type ComponentConstraint = {
|
|
|
165
165
|
defaultTag?: string;
|
|
166
166
|
/** True when `enforcement.aria` is a non-empty array literal in the factory call. */
|
|
167
167
|
hasAriaRules: boolean;
|
|
168
|
+
/**
|
|
169
|
+
* True when `enforcement.exclusiveChildren` is statically `true` in the factory call.
|
|
170
|
+
* Only when this is true does an "over the max" child count constitute a real
|
|
171
|
+
* violation — enforcement.children is open-by-default, so extra unmatched children
|
|
172
|
+
* are otherwise allowed regardless of `totalMax`.
|
|
173
|
+
*/
|
|
174
|
+
exclusiveChildren: boolean;
|
|
168
175
|
};
|
|
169
176
|
|
|
170
177
|
/** A diagnostic produced by the static analysis pass. */
|
|
@@ -208,6 +215,11 @@ type PluginOptions = {
|
|
|
208
215
|
* are skipped — their child count is unknowable at build time.
|
|
209
216
|
* - Named const declarations: `export const X = factory(...)` and destructured
|
|
210
217
|
* patterns are not collected; cross-file analysis is future work.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* const diagnostics = analyze(source, 'Button.tsx', { severity: 'error' })
|
|
222
|
+
* ```
|
|
211
223
|
*/
|
|
212
224
|
declare function analyze(code: string, filename: string, options?: PluginOptions): Diagnostic[];
|
|
213
225
|
|
|
@@ -228,6 +240,25 @@ declare function analyze(code: string, filename: string, options?: PluginOptions
|
|
|
228
240
|
* - `styling.compounds` contains non-literal conditions or class values
|
|
229
241
|
* - The total number of combinations exceeds MAX_COMBINATIONS
|
|
230
242
|
* - The styling object already has a `precomputedClasses` property
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* Before:
|
|
246
|
+
* ```ts
|
|
247
|
+
* styling: {
|
|
248
|
+
* variants: { size: { sm: 'text-sm', lg: 'text-lg' } },
|
|
249
|
+
* }
|
|
250
|
+
* ```
|
|
251
|
+
* After:
|
|
252
|
+
* ```ts
|
|
253
|
+
* styling: {
|
|
254
|
+
* variants: { size: { sm: 'text-sm', lg: 'text-lg' } },
|
|
255
|
+
* precomputedClasses: {
|
|
256
|
+
* '__none__:': '',
|
|
257
|
+
* '__none__:size:s:sm': 'text-sm',
|
|
258
|
+
* '__none__:size:s:lg': 'text-lg',
|
|
259
|
+
* },
|
|
260
|
+
* }
|
|
261
|
+
* ```
|
|
231
262
|
*/
|
|
232
263
|
|
|
233
264
|
/**
|
|
@@ -189,7 +189,7 @@ function asArray(node) {
|
|
|
189
189
|
if (!node) return void 0;
|
|
190
190
|
return ts.isArrayLiteralExpression(node) ? node : void 0;
|
|
191
191
|
}
|
|
192
|
-
function
|
|
192
|
+
function asNonNegativeInt(node) {
|
|
193
193
|
if (!node) return void 0;
|
|
194
194
|
if (ts.isNumericLiteral(node)) {
|
|
195
195
|
const n = Number(node.text);
|
|
@@ -197,6 +197,17 @@ function asPositiveInt(node) {
|
|
|
197
197
|
}
|
|
198
198
|
return void 0;
|
|
199
199
|
}
|
|
200
|
+
function asBooleanLiteral(node) {
|
|
201
|
+
if (!node) return void 0;
|
|
202
|
+
switch (node.kind) {
|
|
203
|
+
case ts.SyntaxKind.TrueKeyword:
|
|
204
|
+
return true;
|
|
205
|
+
case ts.SyntaxKind.FalseKeyword:
|
|
206
|
+
return false;
|
|
207
|
+
default:
|
|
208
|
+
return void 0;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
200
211
|
function isFactoryCall(call, names) {
|
|
201
212
|
const { expression } = call;
|
|
202
213
|
if (ts.isIdentifier(expression)) return names.has(expression.text);
|
|
@@ -204,7 +215,7 @@ function isFactoryCall(call, names) {
|
|
|
204
215
|
return false;
|
|
205
216
|
}
|
|
206
217
|
function firstObjectArg(call) {
|
|
207
|
-
const
|
|
218
|
+
const first = call.arguments[0];
|
|
208
219
|
return first && ts.isObjectLiteralExpression(first) ? first : void 0;
|
|
209
220
|
}
|
|
210
221
|
function* walk(node) {
|
|
@@ -316,11 +327,11 @@ function enumerateCombinations(variantMap) {
|
|
|
316
327
|
return total <= MAX_COMBINATIONS;
|
|
317
328
|
});
|
|
318
329
|
if (!totalUnderMaxLimit) return null;
|
|
319
|
-
function
|
|
330
|
+
function enumerateRecursive(remaining) {
|
|
320
331
|
if (remaining.length === 0) return [{}];
|
|
321
332
|
const first = remaining[0];
|
|
322
333
|
const rest = remaining.slice(1);
|
|
323
|
-
const restCombos =
|
|
334
|
+
const restCombos = enumerateRecursive(rest);
|
|
324
335
|
const valueKeys = Object.keys(variantMap[first]);
|
|
325
336
|
const out = [];
|
|
326
337
|
iterate.forEach(restCombos, (combo) => {
|
|
@@ -331,7 +342,7 @@ function enumerateCombinations(variantMap) {
|
|
|
331
342
|
});
|
|
332
343
|
return out;
|
|
333
344
|
}
|
|
334
|
-
return
|
|
345
|
+
return enumerateRecursive(keys2);
|
|
335
346
|
}
|
|
336
347
|
function buildCacheKey(props) {
|
|
337
348
|
const parts = Object.keys(props).sort().map((k) => `${k}:s:${props[k]}`);
|
|
@@ -459,8 +470,8 @@ function extractBound(element) {
|
|
|
459
470
|
if (cardObj) {
|
|
460
471
|
const minNode = getProperty(cardObj, "min");
|
|
461
472
|
const maxNode = getProperty(cardObj, "max");
|
|
462
|
-
const min =
|
|
463
|
-
const max =
|
|
473
|
+
const min = asNonNegativeInt(minNode) ?? 0;
|
|
474
|
+
const max = asNonNegativeInt(maxNode);
|
|
464
475
|
if (min === 0 && max === void 0) {
|
|
465
476
|
cardinality = { kind: "unbounded" };
|
|
466
477
|
} else {
|
|
@@ -497,6 +508,8 @@ function processVariableStatement(node, calleeNames, out) {
|
|
|
497
508
|
const ariaNode = enfObj ? getProperty(enfObj, "aria") : void 0;
|
|
498
509
|
const ariaArr = asArray(ariaNode);
|
|
499
510
|
const hasAriaRules = ariaArr !== void 0 && ariaArr.elements.length > 0;
|
|
511
|
+
const exclusiveChildrenNode = enfObj ? getProperty(enfObj, "exclusiveChildren") : void 0;
|
|
512
|
+
const exclusiveChildren = asBooleanLiteral(exclusiveChildrenNode) ?? false;
|
|
500
513
|
const childrenProp = enfObj ? getProperty(enfObj, "children") : void 0;
|
|
501
514
|
const childrenArr = asArray(childrenProp);
|
|
502
515
|
const rules = [];
|
|
@@ -506,7 +519,7 @@ function processVariableStatement(node, calleeNames, out) {
|
|
|
506
519
|
if (bound) rules.push(bound);
|
|
507
520
|
});
|
|
508
521
|
}
|
|
509
|
-
if (rules.length === 0 && !hasAriaRules && !defaultTag) return;
|
|
522
|
+
if (rules.length === 0 && !hasAriaRules && !defaultTag && !exclusiveChildren) return;
|
|
510
523
|
let totalMin = 0;
|
|
511
524
|
let totalMax = 0;
|
|
512
525
|
iterate.forEach(rules, (rule) => {
|
|
@@ -522,7 +535,8 @@ function processVariableStatement(node, calleeNames, out) {
|
|
|
522
535
|
totalMin,
|
|
523
536
|
totalMax,
|
|
524
537
|
...defaultTag !== void 0 && { defaultTag },
|
|
525
|
-
hasAriaRules
|
|
538
|
+
hasAriaRules,
|
|
539
|
+
exclusiveChildren
|
|
526
540
|
});
|
|
527
541
|
});
|
|
528
542
|
}
|
|
@@ -734,7 +748,7 @@ function analyzeJsxSites(source, constraints, severity) {
|
|
|
734
748
|
const getPos = () => pos ??= source.getLineAndCharacterOfPosition(node.getStart(source));
|
|
735
749
|
if (count !== void 0) {
|
|
736
750
|
const c = byName.get(tagName);
|
|
737
|
-
if (c && (count.max < c.totalMin || count.min > c.totalMax)) {
|
|
751
|
+
if (c && (count.max < c.totalMin || c.exclusiveChildren && count.min > c.totalMax)) {
|
|
738
752
|
const { line, character } = getPos();
|
|
739
753
|
diagnostics.push({
|
|
740
754
|
diagnostic: ViteDiagnostics.cardinalityViolation(
|
|
@@ -868,8 +882,8 @@ function diagnoseUsages(source, constraints, severity) {
|
|
|
868
882
|
const constraint = byName.get(tagName);
|
|
869
883
|
if (!constraint) return;
|
|
870
884
|
if (count === void 0) return;
|
|
871
|
-
const { totalMin, totalMax, name } = constraint;
|
|
872
|
-
if (count.max < totalMin || count.min > totalMax) {
|
|
885
|
+
const { totalMin, totalMax, name, exclusiveChildren } = constraint;
|
|
886
|
+
if (count.max < totalMin || exclusiveChildren && count.min > totalMax) {
|
|
873
887
|
const { line, character } = source.getLineAndCharacterOfPosition(node.getStart(source));
|
|
874
888
|
diagnostics.push({
|
|
875
889
|
diagnostic: ViteDiagnostics.cardinalityViolation(
|
|
@@ -948,9 +962,11 @@ var ConstraintRegistry = class {
|
|
|
948
962
|
if (count === void 0) return;
|
|
949
963
|
const constraint = this.resolveConstraint(fileId, tagName);
|
|
950
964
|
if (!constraint) return;
|
|
951
|
-
const { totalMin, totalMax, name } = constraint;
|
|
965
|
+
const { totalMin, totalMax, name, exclusiveChildren } = constraint;
|
|
952
966
|
const { min, max } = count;
|
|
953
|
-
|
|
967
|
+
const tooFew = max < totalMin;
|
|
968
|
+
const tooMany = exclusiveChildren && min > totalMax;
|
|
969
|
+
if (!tooFew && !tooMany) return;
|
|
954
970
|
result.push({
|
|
955
971
|
fileId,
|
|
956
972
|
diagnostic: ViteDiagnostics.cardinalityViolation(name, totalMin, totalMax, min, max),
|
|
@@ -1379,8 +1395,9 @@ function composeStatically(source, calleeNames, importedComponents = /* @__PURE_
|
|
|
1379
1395
|
}
|
|
1380
1396
|
|
|
1381
1397
|
// ../../plugins/vite/src/analyze.ts
|
|
1398
|
+
import { extname } from "path";
|
|
1382
1399
|
function analyze(code, filename, options) {
|
|
1383
|
-
const ext = filename
|
|
1400
|
+
const ext = extname(filename).slice(1);
|
|
1384
1401
|
if (!JSX_EXTS.has(ext)) return [];
|
|
1385
1402
|
const calleeNames = new Set(options?.calleeNames ?? DEFAULT_CALLEE_NAMES);
|
|
1386
1403
|
const severity = options?.severity ?? "warning";
|
package/dist/vue/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequireAtLeastOne, Simplify, ReadonlyDeep } from 'type-fest';
|
|
2
|
-
import { Diagnostics, DiagnosticInput } from '../_shared/diagnostics.js';
|
|
2
|
+
import { Diagnostics, DiagnosticInput, DiagnosticsMode } from '../_shared/diagnostics.js';
|
|
3
3
|
import * as vue from 'vue';
|
|
4
4
|
import { AllowedComponentProps } from 'vue';
|
|
5
5
|
|
|
@@ -214,9 +214,25 @@ type AriaRule<C extends AriaContext = AriaContext> = (context: C) => readonly Ar
|
|
|
214
214
|
type PropNormalizer = (props: Readonly<AnyRecord & IntrinsicProps>) => Partial<AnyRecord & IntrinsicProps>;
|
|
215
215
|
|
|
216
216
|
type EnforcementOptions<TAllowed extends ElementType = ElementType> = {
|
|
217
|
-
|
|
217
|
+
/**
|
|
218
|
+
* Accepts a preset name (`'warn'`, `'throw'`, `'silent'`) or a full `Diagnostics`
|
|
219
|
+
* instance for custom reporting/policy. The string form needs no import from
|
|
220
|
+
* `@praxis-kit/diagnostics`.
|
|
221
|
+
*/
|
|
222
|
+
readonly diagnostics?: Diagnostics | DiagnosticsMode;
|
|
218
223
|
readonly aria?: readonly AriaRule[];
|
|
219
224
|
readonly children?: readonly ChildRuleInput[];
|
|
225
|
+
/**
|
|
226
|
+
* When true, only children matching a `children` rule (or text, per `allowText`)
|
|
227
|
+
* are valid — anything else is rejected. Default: false (open — children not
|
|
228
|
+
* matching any rule are allowed).
|
|
229
|
+
*/
|
|
230
|
+
readonly exclusiveChildren?: boolean;
|
|
231
|
+
/**
|
|
232
|
+
* When false, text/number child nodes are rejected regardless of exclusiveChildren
|
|
233
|
+
* or any listed rule. Default: true.
|
|
234
|
+
*/
|
|
235
|
+
readonly allowText?: boolean;
|
|
220
236
|
readonly props?: readonly PropNormalizer[];
|
|
221
237
|
/** Restricts the `as` prop to this set of tags. Violations route through diagnostics. */
|
|
222
238
|
readonly allowedAs?: readonly TAllowed[];
|