@fragments-sdk/classifier 0.2.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 +84 -0
- package/dist/index.d.ts +184 -0
- package/dist/index.js +1856 -0
- package/dist/index.js.map +1 -0
- package/package.json +45 -0
- package/src/__tests__/combiner.test.ts +222 -0
- package/src/__tests__/fixtures.ts +96 -0
- package/src/ai/__tests__/cache-key.test.ts +50 -0
- package/src/ai/__tests__/prompt.test.ts +95 -0
- package/src/ai/__tests__/schema.test.ts +145 -0
- package/src/ai/__tests__/secret-scrub.test.ts +70 -0
- package/src/ai/__tests__/signal.test.ts +94 -0
- package/src/ai/cache-key.ts +46 -0
- package/src/ai/index.ts +42 -0
- package/src/ai/prompt.ts +154 -0
- package/src/ai/schema.ts +148 -0
- package/src/ai/secret-scrub.ts +116 -0
- package/src/ai/signal.ts +81 -0
- package/src/ai/version.ts +15 -0
- package/src/canonical-vocab/resolve-by-html-element.ts +72 -0
- package/src/combiner/__tests__/band.test.ts +155 -0
- package/src/combiner/__tests__/group.test.ts +85 -0
- package/src/combiner/__tests__/rank.test.ts +54 -0
- package/src/combiner/band.ts +85 -0
- package/src/combiner/group.ts +62 -0
- package/src/combiner/rank.ts +57 -0
- package/src/combiner.ts +124 -0
- package/src/index.ts +76 -0
- package/src/signals/__tests__/aria-role.test.ts +53 -0
- package/src/signals/__tests__/barrel-export.test.ts +29 -0
- package/src/signals/__tests__/html-root.test.ts +55 -0
- package/src/signals/__tests__/input-type.test.ts +58 -0
- package/src/signals/__tests__/library-reexport.test.ts +68 -0
- package/src/signals/__tests__/name-match.test.ts +43 -0
- package/src/signals/__tests__/path-hint.test.ts +55 -0
- package/src/signals/__tests__/prop-fingerprint.test.ts +105 -0
- package/src/signals/__tests__/registry.test.ts +27 -0
- package/src/signals/aria-role.ts +94 -0
- package/src/signals/barrel-export.ts +28 -0
- package/src/signals/html-root.ts +85 -0
- package/src/signals/index.ts +39 -0
- package/src/signals/input-type.ts +63 -0
- package/src/signals/library-reexport.ts +70 -0
- package/src/signals/name-match.ts +92 -0
- package/src/signals/path-hint.ts +94 -0
- package/src/signals/prop-fingerprint.ts +121 -0
- package/src/types.ts +58 -0
- package/src/vocabulary/canonicals.ts +106 -0
- package/src/vocabulary/library-map.ts +301 -0
- package/src/vocabulary/prop-fingerprints.ts +433 -0
- package/src/vocabulary/synonyms.ts +130 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// PROP_FINGERPRINT — `01-architecture.md` §9.5.
|
|
2
|
+
//
|
|
3
|
+
// Medium-precision signal (base weight 0.3). For each canonical fingerprint:
|
|
4
|
+
// - All required tests must pass to fire.
|
|
5
|
+
// - Optional matches add 0.05 each, capped so total weight ≤ 0.6.
|
|
6
|
+
// - Anti-fingerprint hits subtract 0.15 each (per-canonical).
|
|
7
|
+
// - Polymorphic prop (`as`/`component`/...) reduces every hypothesis by 0.1
|
|
8
|
+
// (applied at emit time).
|
|
9
|
+
|
|
10
|
+
import type { PropFact, UniversalComponentFact } from '@fragments-sdk/extract';
|
|
11
|
+
|
|
12
|
+
import type { CanonicalId, SignalExtractor, SignalRecord } from '../types.js';
|
|
13
|
+
import {
|
|
14
|
+
POLYMORPHIC_PROP_NAMES,
|
|
15
|
+
PROP_FINGERPRINTS,
|
|
16
|
+
type AntiPropTest,
|
|
17
|
+
type OptionalPropTest,
|
|
18
|
+
type RequiredPropTest,
|
|
19
|
+
} from '../vocabulary/prop-fingerprints.js';
|
|
20
|
+
|
|
21
|
+
const BASE_WEIGHT = 0.3;
|
|
22
|
+
const OPTIONAL_INCREMENT = 0.05;
|
|
23
|
+
const ANTI_DECREMENT = 0.15;
|
|
24
|
+
const POLYMORPHIC_PENALTY = 0.1;
|
|
25
|
+
const MAX_WEIGHT = 0.6;
|
|
26
|
+
|
|
27
|
+
function findProp(props: ReadonlyArray<PropFact>, name: string): PropFact | undefined {
|
|
28
|
+
// Aliases like `aria-label` come through verbatim; case-sensitive match.
|
|
29
|
+
return props.find((p) => p.name === name);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function requiredMatches(
|
|
33
|
+
props: ReadonlyArray<PropFact>,
|
|
34
|
+
test: RequiredPropTest,
|
|
35
|
+
): { matched: true; via: string } | { matched: false } {
|
|
36
|
+
for (const candidate of test.oneOf) {
|
|
37
|
+
const prop = findProp(props, candidate.name);
|
|
38
|
+
if (!prop) continue;
|
|
39
|
+
if (candidate.typeMatcher && !candidate.typeMatcher(prop.typeText)) continue;
|
|
40
|
+
return { matched: true, via: candidate.name };
|
|
41
|
+
}
|
|
42
|
+
return { matched: false };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function optionalMatches(
|
|
46
|
+
props: ReadonlyArray<PropFact>,
|
|
47
|
+
test: OptionalPropTest,
|
|
48
|
+
): boolean {
|
|
49
|
+
const prop = findProp(props, test.name);
|
|
50
|
+
if (!prop) return false;
|
|
51
|
+
if (test.typeMatcher && !test.typeMatcher(prop.typeText)) return false;
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function antiMatches(
|
|
56
|
+
props: ReadonlyArray<PropFact>,
|
|
57
|
+
test: AntiPropTest,
|
|
58
|
+
): boolean {
|
|
59
|
+
const prop = findProp(props, test.name);
|
|
60
|
+
if (!prop) return false;
|
|
61
|
+
if (test.typeMatcher && !test.typeMatcher(prop.typeText)) return false;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isPolymorphic(props: ReadonlyArray<PropFact>): boolean {
|
|
66
|
+
return props.some((prop) => POLYMORPHIC_PROP_NAMES.has(prop.name));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const propFingerprint: SignalExtractor = (
|
|
70
|
+
ucf: UniversalComponentFact,
|
|
71
|
+
): SignalRecord[] => {
|
|
72
|
+
const polymorphic = isPolymorphic(ucf.props);
|
|
73
|
+
const out: SignalRecord[] = [];
|
|
74
|
+
|
|
75
|
+
for (const [canonical, fingerprint] of PROP_FINGERPRINTS.entries()) {
|
|
76
|
+
const requiredHits: string[] = [];
|
|
77
|
+
let allRequired = true;
|
|
78
|
+
for (const required of fingerprint.required) {
|
|
79
|
+
const result = requiredMatches(ucf.props, required);
|
|
80
|
+
if (!result.matched) {
|
|
81
|
+
allRequired = false;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
requiredHits.push(result.via);
|
|
85
|
+
}
|
|
86
|
+
if (!allRequired) continue;
|
|
87
|
+
|
|
88
|
+
const optionalHits: string[] = [];
|
|
89
|
+
for (const optional of fingerprint.optional) {
|
|
90
|
+
if (optionalMatches(ucf.props, optional)) optionalHits.push(optional.name);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const antiHits: string[] = [];
|
|
94
|
+
for (const anti of fingerprint.anti) {
|
|
95
|
+
if (antiMatches(ucf.props, anti)) antiHits.push(anti.name);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let weight = BASE_WEIGHT + optionalHits.length * OPTIONAL_INCREMENT;
|
|
99
|
+
weight -= antiHits.length * ANTI_DECREMENT;
|
|
100
|
+
if (polymorphic) weight -= POLYMORPHIC_PENALTY;
|
|
101
|
+
|
|
102
|
+
if (weight <= 0) continue;
|
|
103
|
+
if (weight > MAX_WEIGHT) weight = MAX_WEIGHT;
|
|
104
|
+
|
|
105
|
+
out.push({
|
|
106
|
+
type: 'PROP_FINGERPRINT',
|
|
107
|
+
canonical: canonical as CanonicalId,
|
|
108
|
+
weight,
|
|
109
|
+
evidence: {
|
|
110
|
+
requiredHits,
|
|
111
|
+
optionalHits,
|
|
112
|
+
antiHits,
|
|
113
|
+
polymorphic,
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return out;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export default propFingerprint;
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// @fragments-sdk/classifier — public types.
|
|
2
|
+
//
|
|
3
|
+
// Mirrors `apps/cloud/docs/canonical-primitive-map/01-architecture.md` §9.
|
|
4
|
+
// Each heuristic signal extractor is a pure function `(ucf) => SignalRecord[]`.
|
|
5
|
+
// The combiner (brief 04) iterates these and applies §10 confidence math.
|
|
6
|
+
|
|
7
|
+
import type { UniversalComponentFact } from '@fragments-sdk/extract';
|
|
8
|
+
|
|
9
|
+
export type CanonicalId = string & { readonly __brand: 'CanonicalId' };
|
|
10
|
+
|
|
11
|
+
export function canonicalId(value: string): CanonicalId {
|
|
12
|
+
return value as CanonicalId;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type SignalType =
|
|
16
|
+
| 'LIBRARY_REEXPORT'
|
|
17
|
+
| 'HTML_ROOT'
|
|
18
|
+
| 'ARIA_ROLE'
|
|
19
|
+
| 'INPUT_TYPE'
|
|
20
|
+
| 'PROP_FINGERPRINT'
|
|
21
|
+
| 'NAME_MATCH'
|
|
22
|
+
| 'PATH_HINT'
|
|
23
|
+
| 'BARREL_EXPORT'
|
|
24
|
+
| 'AI_SEMANTIC';
|
|
25
|
+
|
|
26
|
+
export type HeuristicSignalType = Exclude<SignalType, 'AI_SEMANTIC'>;
|
|
27
|
+
|
|
28
|
+
export interface SignalRecord {
|
|
29
|
+
type: SignalType;
|
|
30
|
+
canonical: CanonicalId;
|
|
31
|
+
weight: number;
|
|
32
|
+
evidence: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type SignalExtractor = (ucf: UniversalComponentFact) => SignalRecord[];
|
|
36
|
+
|
|
37
|
+
export type SignalRegistry = Record<HeuristicSignalType, SignalExtractor>;
|
|
38
|
+
|
|
39
|
+
// `01-architecture.md` §10.3 — confidence band assigned by the combiner.
|
|
40
|
+
export type Band = 'auto' | 'suggested' | 'possible' | 'unknown';
|
|
41
|
+
|
|
42
|
+
export interface ClassificationAlternate {
|
|
43
|
+
canonical: CanonicalId;
|
|
44
|
+
confidence: number;
|
|
45
|
+
signals: SignalRecord[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// `01-architecture.md` §10.5 — "show your work" payload.
|
|
49
|
+
export interface Classification {
|
|
50
|
+
canonical: CanonicalId | 'unknown';
|
|
51
|
+
confidence: number; // adjusted, post-disagreement-penalty
|
|
52
|
+
rawConfidence: number; // pre-penalty composition
|
|
53
|
+
band: Band;
|
|
54
|
+
signals: SignalRecord[]; // contributing signals for the leading canonical
|
|
55
|
+
alternates: ClassificationAlternate[];
|
|
56
|
+
classifierVersion: string;
|
|
57
|
+
vocabVersion: string;
|
|
58
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Vocabulary v0 — ~50 canonical primitives across six categories.
|
|
2
|
+
// Verbatim port of `01-architecture.md` §5.
|
|
3
|
+
|
|
4
|
+
import { canonicalId, type CanonicalId } from '../types.js';
|
|
5
|
+
|
|
6
|
+
export type CanonicalCategory =
|
|
7
|
+
| 'inputs'
|
|
8
|
+
| 'overlays'
|
|
9
|
+
| 'navigation'
|
|
10
|
+
| 'feedback'
|
|
11
|
+
| 'data'
|
|
12
|
+
| 'layout';
|
|
13
|
+
|
|
14
|
+
export interface CanonicalEntry {
|
|
15
|
+
id: CanonicalId;
|
|
16
|
+
category: CanonicalCategory;
|
|
17
|
+
primaryHtmlElement?: string;
|
|
18
|
+
primaryAriaRole?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const c = canonicalId;
|
|
22
|
+
|
|
23
|
+
export const VOCAB_V0_VERSION = 'vocab_v0';
|
|
24
|
+
|
|
25
|
+
export const VOCAB_V0: ReadonlyArray<CanonicalEntry> = [
|
|
26
|
+
// §5.1 inputs & form controls
|
|
27
|
+
{ id: c('Button'), category: 'inputs', primaryHtmlElement: 'button', primaryAriaRole: 'button' },
|
|
28
|
+
{ id: c('IconButton'), category: 'inputs', primaryHtmlElement: 'button', primaryAriaRole: 'button' },
|
|
29
|
+
{ id: c('ToggleButton'), category: 'inputs', primaryHtmlElement: 'button', primaryAriaRole: 'button' },
|
|
30
|
+
{ id: c('Input'), category: 'inputs', primaryHtmlElement: 'input', primaryAriaRole: 'textbox' },
|
|
31
|
+
{ id: c('Textarea'), category: 'inputs', primaryHtmlElement: 'textarea', primaryAriaRole: 'textbox' },
|
|
32
|
+
{ id: c('NumberInput'), category: 'inputs', primaryHtmlElement: 'input', primaryAriaRole: 'spinbutton' },
|
|
33
|
+
{ id: c('PasswordInput'), category: 'inputs', primaryHtmlElement: 'input', primaryAriaRole: 'textbox' },
|
|
34
|
+
{ id: c('Checkbox'), category: 'inputs', primaryHtmlElement: 'input', primaryAriaRole: 'checkbox' },
|
|
35
|
+
{ id: c('Radio'), category: 'inputs', primaryHtmlElement: 'input', primaryAriaRole: 'radio' },
|
|
36
|
+
{ id: c('RadioGroup'), category: 'inputs', primaryAriaRole: 'radiogroup' },
|
|
37
|
+
{ id: c('Switch'), category: 'inputs', primaryHtmlElement: 'input', primaryAriaRole: 'switch' },
|
|
38
|
+
{ id: c('Slider'), category: 'inputs', primaryAriaRole: 'slider' },
|
|
39
|
+
{ id: c('Select'), category: 'inputs', primaryHtmlElement: 'select', primaryAriaRole: 'combobox' },
|
|
40
|
+
{ id: c('Combobox'), category: 'inputs', primaryAriaRole: 'combobox' },
|
|
41
|
+
{ id: c('MultiSelect'), category: 'inputs', primaryAriaRole: 'listbox' },
|
|
42
|
+
{ id: c('DatePicker'), category: 'inputs' },
|
|
43
|
+
{ id: c('TimePicker'), category: 'inputs' },
|
|
44
|
+
{ id: c('Calendar'), category: 'inputs' },
|
|
45
|
+
{ id: c('Form'), category: 'inputs', primaryHtmlElement: 'form', primaryAriaRole: 'form' },
|
|
46
|
+
{ id: c('Field'), category: 'inputs' },
|
|
47
|
+
{ id: c('Label'), category: 'inputs', primaryHtmlElement: 'label' },
|
|
48
|
+
{ id: c('FieldError'), category: 'inputs', primaryAriaRole: 'alert' },
|
|
49
|
+
{ id: c('FieldHint'), category: 'inputs' },
|
|
50
|
+
|
|
51
|
+
// §5.2 disclosure & overlays
|
|
52
|
+
{ id: c('Dialog'), category: 'overlays', primaryHtmlElement: 'dialog', primaryAriaRole: 'dialog' },
|
|
53
|
+
{ id: c('AlertDialog'), category: 'overlays', primaryHtmlElement: 'dialog', primaryAriaRole: 'alertdialog' },
|
|
54
|
+
{ id: c('Drawer'), category: 'overlays', primaryAriaRole: 'dialog' },
|
|
55
|
+
{ id: c('Sheet'), category: 'overlays', primaryAriaRole: 'dialog' },
|
|
56
|
+
{ id: c('Popover'), category: 'overlays', primaryAriaRole: 'dialog' },
|
|
57
|
+
{ id: c('Tooltip'), category: 'overlays', primaryAriaRole: 'tooltip' },
|
|
58
|
+
{ id: c('HoverCard'), category: 'overlays' },
|
|
59
|
+
{ id: c('Toast'), category: 'overlays', primaryAriaRole: 'status' },
|
|
60
|
+
|
|
61
|
+
// §5.3 navigation & disclosure-group
|
|
62
|
+
{ id: c('Tabs'), category: 'navigation', primaryAriaRole: 'tablist' },
|
|
63
|
+
{ id: c('Accordion'), category: 'navigation' },
|
|
64
|
+
{ id: c('Disclosure'), category: 'navigation', primaryHtmlElement: 'details' },
|
|
65
|
+
{ id: c('Menu'), category: 'navigation', primaryAriaRole: 'menu' },
|
|
66
|
+
{ id: c('ContextMenu'), category: 'navigation', primaryAriaRole: 'menu' },
|
|
67
|
+
{ id: c('MenuBar'), category: 'navigation', primaryAriaRole: 'menubar' },
|
|
68
|
+
{ id: c('Breadcrumb'), category: 'navigation', primaryHtmlElement: 'nav', primaryAriaRole: 'navigation' },
|
|
69
|
+
{ id: c('Pagination'), category: 'navigation', primaryHtmlElement: 'nav', primaryAriaRole: 'navigation' },
|
|
70
|
+
{ id: c('Stepper'), category: 'navigation' },
|
|
71
|
+
{ id: c('NavigationMenu'), category: 'navigation', primaryHtmlElement: 'nav', primaryAriaRole: 'navigation' },
|
|
72
|
+
|
|
73
|
+
// §5.4 display & feedback
|
|
74
|
+
{ id: c('Card'), category: 'feedback' },
|
|
75
|
+
{ id: c('Badge'), category: 'feedback' },
|
|
76
|
+
{ id: c('Chip'), category: 'feedback' },
|
|
77
|
+
{ id: c('Tag'), category: 'feedback' },
|
|
78
|
+
{ id: c('Avatar'), category: 'feedback' },
|
|
79
|
+
{ id: c('Alert'), category: 'feedback', primaryAriaRole: 'alert' },
|
|
80
|
+
{ id: c('Banner'), category: 'feedback' },
|
|
81
|
+
{ id: c('Skeleton'), category: 'feedback' },
|
|
82
|
+
{ id: c('Spinner'), category: 'feedback', primaryAriaRole: 'progressbar' },
|
|
83
|
+
{ id: c('Progress'), category: 'feedback', primaryHtmlElement: 'progress', primaryAriaRole: 'progressbar' },
|
|
84
|
+
{ id: c('Separator'), category: 'feedback', primaryHtmlElement: 'hr', primaryAriaRole: 'separator' },
|
|
85
|
+
|
|
86
|
+
// §5.5 data display
|
|
87
|
+
{ id: c('Table'), category: 'data', primaryHtmlElement: 'table', primaryAriaRole: 'table' },
|
|
88
|
+
{ id: c('DataTable'), category: 'data', primaryHtmlElement: 'table', primaryAriaRole: 'grid' },
|
|
89
|
+
{ id: c('List'), category: 'data', primaryHtmlElement: 'ul', primaryAriaRole: 'list' },
|
|
90
|
+
{ id: c('Tree'), category: 'data', primaryAriaRole: 'tree' },
|
|
91
|
+
{ id: c('ScrollArea'), category: 'data' },
|
|
92
|
+
|
|
93
|
+
// §5.6 layout primitives (controversial — see §22)
|
|
94
|
+
{ id: c('Stack'), category: 'layout' },
|
|
95
|
+
{ id: c('Grid'), category: 'layout' },
|
|
96
|
+
{ id: c('Box'), category: 'layout' },
|
|
97
|
+
{ id: c('Container'), category: 'layout' },
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
export const VOCAB_V0_INDEX: ReadonlyMap<string, CanonicalEntry> = new Map(
|
|
101
|
+
VOCAB_V0.map((entry) => [entry.id as string, entry]),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
export function isCanonicalId(value: string): value is CanonicalId {
|
|
105
|
+
return VOCAB_V0_INDEX.has(value);
|
|
106
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
// LIBRARY_REEXPORT lookup table — `01-architecture.md` §9.1.
|
|
2
|
+
//
|
|
3
|
+
// Keyed by `package → importedName → canonical`. The signal fires when a
|
|
4
|
+
// component imports a known primitive AND uses the local binding as a JSX
|
|
5
|
+
// root. Sub-primitive policy (§9.1 final paragraph): only root-aligned wrappers
|
|
6
|
+
// emit, so we map only the root-level identifier per package and let
|
|
7
|
+
// compound-children detection on the parent classify the sub-parts.
|
|
8
|
+
|
|
9
|
+
import { canonicalId, type CanonicalId } from '../types.js';
|
|
10
|
+
|
|
11
|
+
export interface LibraryMapEntry {
|
|
12
|
+
canonical: CanonicalId;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type LibraryMap = ReadonlyMap<
|
|
16
|
+
string,
|
|
17
|
+
ReadonlyMap<string, LibraryMapEntry>
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
const c = canonicalId;
|
|
21
|
+
|
|
22
|
+
function entries(
|
|
23
|
+
pkg: string,
|
|
24
|
+
...rows: Array<[string, CanonicalId]>
|
|
25
|
+
): [string, ReadonlyMap<string, LibraryMapEntry>] {
|
|
26
|
+
return [pkg, new Map(rows.map(([imported, canon]) => [imported, { canonical: canon }]))];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Default exports use the literal key 'default'. Namespace imports (`* as ns`)
|
|
30
|
+
// are matched per-name by walking the namespace usage at signal time.
|
|
31
|
+
export const LIBRARY_MAP: LibraryMap = new Map([
|
|
32
|
+
// ── Radix UI ──────────────────────────────────────────────────────
|
|
33
|
+
entries('@radix-ui/react-dialog', ['Root', c('Dialog')], ['default', c('Dialog')]),
|
|
34
|
+
entries('@radix-ui/react-tooltip', ['Root', c('Tooltip')]),
|
|
35
|
+
entries('@radix-ui/react-popover', ['Root', c('Popover')]),
|
|
36
|
+
entries('@radix-ui/react-tabs', ['Root', c('Tabs')]),
|
|
37
|
+
entries('@radix-ui/react-accordion', ['Root', c('Accordion')]),
|
|
38
|
+
entries('@radix-ui/react-checkbox', ['Root', c('Checkbox')]),
|
|
39
|
+
entries('@radix-ui/react-switch', ['Root', c('Switch')]),
|
|
40
|
+
entries('@radix-ui/react-slider', ['Root', c('Slider')]),
|
|
41
|
+
entries('@radix-ui/react-select', ['Root', c('Select')]),
|
|
42
|
+
entries('@radix-ui/react-radio-group', ['Root', c('RadioGroup')]),
|
|
43
|
+
entries('@radix-ui/react-progress', ['Root', c('Progress')]),
|
|
44
|
+
entries('@radix-ui/react-separator', ['Root', c('Separator')]),
|
|
45
|
+
entries('@radix-ui/react-alert-dialog', ['Root', c('AlertDialog')]),
|
|
46
|
+
entries('@radix-ui/react-context-menu', ['Root', c('ContextMenu')]),
|
|
47
|
+
entries('@radix-ui/react-dropdown-menu', ['Root', c('Menu')]),
|
|
48
|
+
entries('@radix-ui/react-hover-card', ['Root', c('HoverCard')]),
|
|
49
|
+
entries('@radix-ui/react-menubar', ['Root', c('MenuBar')]),
|
|
50
|
+
entries('@radix-ui/react-navigation-menu', ['Root', c('NavigationMenu')]),
|
|
51
|
+
entries('@radix-ui/react-scroll-area', ['Root', c('ScrollArea')]),
|
|
52
|
+
entries('@radix-ui/react-toast', ['Root', c('Toast')]),
|
|
53
|
+
entries('@radix-ui/react-toggle', ['Root', c('ToggleButton')]),
|
|
54
|
+
entries('@radix-ui/react-toggle-group', ['Root', c('ToggleButton')]),
|
|
55
|
+
entries('@radix-ui/react-avatar', ['Root', c('Avatar')]),
|
|
56
|
+
entries('@radix-ui/react-label', ['Root', c('Label')]),
|
|
57
|
+
entries('@radix-ui/react-form', ['Root', c('Form')]),
|
|
58
|
+
|
|
59
|
+
// ── Base UI ───────────────────────────────────────────────────────
|
|
60
|
+
entries('@base-ui-components/react/dialog', ['Root', c('Dialog')], ['Dialog', c('Dialog')]),
|
|
61
|
+
entries('@base-ui-components/react/tooltip', ['Root', c('Tooltip')], ['Tooltip', c('Tooltip')]),
|
|
62
|
+
entries('@base-ui-components/react/menu', ['Root', c('Menu')], ['Menu', c('Menu')]),
|
|
63
|
+
entries('@base-ui-components/react/select', ['Root', c('Select')], ['Select', c('Select')]),
|
|
64
|
+
entries('@base-ui-components/react/combobox', ['Root', c('Combobox')], ['Combobox', c('Combobox')]),
|
|
65
|
+
entries('@base-ui-components/react/tabs', ['Root', c('Tabs')], ['Tabs', c('Tabs')]),
|
|
66
|
+
entries('@base-ui-components/react/popover', ['Root', c('Popover')], ['Popover', c('Popover')]),
|
|
67
|
+
entries('@base-ui-components/react/checkbox', ['Root', c('Checkbox')], ['Checkbox', c('Checkbox')]),
|
|
68
|
+
entries('@base-ui-components/react/switch', ['Root', c('Switch')], ['Switch', c('Switch')]),
|
|
69
|
+
entries('@base-ui-components/react/slider', ['Root', c('Slider')], ['Slider', c('Slider')]),
|
|
70
|
+
entries('@base-ui-components/react/radio-group', ['Root', c('RadioGroup')], ['RadioGroup', c('RadioGroup')]),
|
|
71
|
+
entries('@base-ui-components/react/accordion', ['Root', c('Accordion')], ['Accordion', c('Accordion')]),
|
|
72
|
+
entries('@base-ui-components/react/separator', ['Root', c('Separator')], ['Separator', c('Separator')]),
|
|
73
|
+
entries('@base-ui-components/react/progress', ['Root', c('Progress')], ['Progress', c('Progress')]),
|
|
74
|
+
entries('@base-ui-components/react/scroll-area', ['Root', c('ScrollArea')]),
|
|
75
|
+
entries('@base-ui-components/react/toggle', ['Root', c('ToggleButton')]),
|
|
76
|
+
entries('@base-ui-components/react/toggle-group', ['Root', c('ToggleButton')]),
|
|
77
|
+
entries('@base-ui-components/react/alert-dialog', ['Root', c('AlertDialog')]),
|
|
78
|
+
entries('@base-ui-components/react/context-menu', ['Root', c('ContextMenu')]),
|
|
79
|
+
entries('@base-ui-components/react/menubar', ['Root', c('MenuBar')]),
|
|
80
|
+
entries('@base-ui-components/react/navigation-menu', ['Root', c('NavigationMenu')]),
|
|
81
|
+
entries('@base-ui-components/react/avatar', ['Root', c('Avatar')]),
|
|
82
|
+
entries('@base-ui-components/react/field', ['Root', c('Field')]),
|
|
83
|
+
entries('@base-ui-components/react/form', ['Root', c('Form')]),
|
|
84
|
+
|
|
85
|
+
// ── Headless UI ───────────────────────────────────────────────────
|
|
86
|
+
entries(
|
|
87
|
+
'@headlessui/react',
|
|
88
|
+
['Dialog', c('Dialog')],
|
|
89
|
+
['Menu', c('Menu')],
|
|
90
|
+
['Listbox', c('Select')],
|
|
91
|
+
['Combobox', c('Combobox')],
|
|
92
|
+
['Switch', c('Switch')],
|
|
93
|
+
['RadioGroup', c('RadioGroup')],
|
|
94
|
+
['Tab', c('Tabs')],
|
|
95
|
+
['Disclosure', c('Disclosure')],
|
|
96
|
+
['Popover', c('Popover')],
|
|
97
|
+
['Transition', c('Box')],
|
|
98
|
+
),
|
|
99
|
+
|
|
100
|
+
// ── React Aria Components ─────────────────────────────────────────
|
|
101
|
+
entries(
|
|
102
|
+
'react-aria-components',
|
|
103
|
+
['Button', c('Button')],
|
|
104
|
+
['ToggleButton', c('ToggleButton')],
|
|
105
|
+
['Checkbox', c('Checkbox')],
|
|
106
|
+
['Radio', c('Radio')],
|
|
107
|
+
['RadioGroup', c('RadioGroup')],
|
|
108
|
+
['Switch', c('Switch')],
|
|
109
|
+
['Slider', c('Slider')],
|
|
110
|
+
['Select', c('Select')],
|
|
111
|
+
['ComboBox', c('Combobox')],
|
|
112
|
+
['ListBox', c('Select')],
|
|
113
|
+
['Menu', c('Menu')],
|
|
114
|
+
['Dialog', c('Dialog')],
|
|
115
|
+
['Modal', c('Dialog')],
|
|
116
|
+
['Popover', c('Popover')],
|
|
117
|
+
['Tooltip', c('Tooltip')],
|
|
118
|
+
['Tabs', c('Tabs')],
|
|
119
|
+
['DateField', c('DatePicker')],
|
|
120
|
+
['DatePicker', c('DatePicker')],
|
|
121
|
+
['Calendar', c('Calendar')],
|
|
122
|
+
['NumberField', c('NumberInput')],
|
|
123
|
+
['TextField', c('Input')],
|
|
124
|
+
['SearchField', c('Input')],
|
|
125
|
+
['ProgressBar', c('Progress')],
|
|
126
|
+
['Breadcrumbs', c('Breadcrumb')],
|
|
127
|
+
),
|
|
128
|
+
|
|
129
|
+
// ── MUI ───────────────────────────────────────────────────────────
|
|
130
|
+
entries('@mui/material', ['Button', c('Button')], ['default', c('Button')]),
|
|
131
|
+
entries('@mui/material/Button', ['default', c('Button')]),
|
|
132
|
+
entries('@mui/material/IconButton', ['default', c('IconButton')]),
|
|
133
|
+
entries('@mui/material/ToggleButton', ['default', c('ToggleButton')]),
|
|
134
|
+
entries('@mui/material/TextField', ['default', c('Input')]),
|
|
135
|
+
entries('@mui/material/OutlinedInput', ['default', c('Input')]),
|
|
136
|
+
entries('@mui/material/FilledInput', ['default', c('Input')]),
|
|
137
|
+
entries('@mui/material/Input', ['default', c('Input')]),
|
|
138
|
+
entries('@mui/material/InputBase', ['default', c('Input')]),
|
|
139
|
+
entries('@mui/material/Checkbox', ['default', c('Checkbox')]),
|
|
140
|
+
entries('@mui/material/Radio', ['default', c('Radio')]),
|
|
141
|
+
entries('@mui/material/RadioGroup', ['default', c('RadioGroup')]),
|
|
142
|
+
entries('@mui/material/Switch', ['default', c('Switch')]),
|
|
143
|
+
entries('@mui/material/Slider', ['default', c('Slider')]),
|
|
144
|
+
entries('@mui/material/Select', ['default', c('Select')]),
|
|
145
|
+
entries('@mui/material/Autocomplete', ['default', c('Combobox')]),
|
|
146
|
+
entries('@mui/material/Dialog', ['default', c('Dialog')]),
|
|
147
|
+
entries('@mui/material/Drawer', ['default', c('Drawer')]),
|
|
148
|
+
entries('@mui/material/Popover', ['default', c('Popover')]),
|
|
149
|
+
entries('@mui/material/Tooltip', ['default', c('Tooltip')]),
|
|
150
|
+
entries('@mui/material/Snackbar', ['default', c('Toast')]),
|
|
151
|
+
entries('@mui/material/Alert', ['default', c('Alert')]),
|
|
152
|
+
entries('@mui/material/Tabs', ['default', c('Tabs')]),
|
|
153
|
+
entries('@mui/material/Tab', ['default', c('Tabs')]),
|
|
154
|
+
entries('@mui/material/Accordion', ['default', c('Accordion')]),
|
|
155
|
+
entries('@mui/material/Menu', ['default', c('Menu')]),
|
|
156
|
+
entries('@mui/material/Breadcrumbs', ['default', c('Breadcrumb')]),
|
|
157
|
+
entries('@mui/material/Pagination', ['default', c('Pagination')]),
|
|
158
|
+
entries('@mui/material/Stepper', ['default', c('Stepper')]),
|
|
159
|
+
entries('@mui/material/Avatar', ['default', c('Avatar')]),
|
|
160
|
+
entries('@mui/material/Badge', ['default', c('Badge')]),
|
|
161
|
+
entries('@mui/material/Chip', ['default', c('Chip')]),
|
|
162
|
+
entries('@mui/material/Card', ['default', c('Card')]),
|
|
163
|
+
entries('@mui/material/Skeleton', ['default', c('Skeleton')]),
|
|
164
|
+
entries('@mui/material/CircularProgress', ['default', c('Spinner')]),
|
|
165
|
+
entries('@mui/material/LinearProgress', ['default', c('Progress')]),
|
|
166
|
+
entries('@mui/material/Divider', ['default', c('Separator')]),
|
|
167
|
+
entries('@mui/material/Table', ['default', c('Table')]),
|
|
168
|
+
entries('@mui/material/List', ['default', c('List')]),
|
|
169
|
+
entries('@mui/material/Stack', ['default', c('Stack')]),
|
|
170
|
+
entries('@mui/material/Grid', ['default', c('Grid')]),
|
|
171
|
+
entries('@mui/material/Box', ['default', c('Box')]),
|
|
172
|
+
entries('@mui/material/Container', ['default', c('Container')]),
|
|
173
|
+
entries('@mui/material/FormLabel', ['default', c('Label')]),
|
|
174
|
+
entries('@mui/material/FormHelperText', ['default', c('FieldHint')]),
|
|
175
|
+
entries('@mui/material/FormControl', ['default', c('Field')]),
|
|
176
|
+
entries('@mui/x-date-pickers/DatePicker', ['DatePicker', c('DatePicker')]),
|
|
177
|
+
entries('@mui/x-date-pickers/TimePicker', ['TimePicker', c('TimePicker')]),
|
|
178
|
+
entries('@mui/x-date-pickers/DateCalendar', ['DateCalendar', c('Calendar')]),
|
|
179
|
+
entries('@mui/x-data-grid', ['DataGrid', c('DataTable')]),
|
|
180
|
+
|
|
181
|
+
// ── Chakra ────────────────────────────────────────────────────────
|
|
182
|
+
entries(
|
|
183
|
+
'@chakra-ui/react',
|
|
184
|
+
['Button', c('Button')],
|
|
185
|
+
['IconButton', c('IconButton')],
|
|
186
|
+
['Input', c('Input')],
|
|
187
|
+
['Textarea', c('Textarea')],
|
|
188
|
+
['NumberInput', c('NumberInput')],
|
|
189
|
+
['Checkbox', c('Checkbox')],
|
|
190
|
+
['Radio', c('Radio')],
|
|
191
|
+
['RadioGroup', c('RadioGroup')],
|
|
192
|
+
['Switch', c('Switch')],
|
|
193
|
+
['Slider', c('Slider')],
|
|
194
|
+
['Select', c('Select')],
|
|
195
|
+
['Modal', c('Dialog')],
|
|
196
|
+
['AlertDialog', c('AlertDialog')],
|
|
197
|
+
['Drawer', c('Drawer')],
|
|
198
|
+
['Popover', c('Popover')],
|
|
199
|
+
['Tooltip', c('Tooltip')],
|
|
200
|
+
['Toast', c('Toast')],
|
|
201
|
+
['Alert', c('Alert')],
|
|
202
|
+
['Tabs', c('Tabs')],
|
|
203
|
+
['Accordion', c('Accordion')],
|
|
204
|
+
['Menu', c('Menu')],
|
|
205
|
+
['Breadcrumb', c('Breadcrumb')],
|
|
206
|
+
['Avatar', c('Avatar')],
|
|
207
|
+
['Badge', c('Badge')],
|
|
208
|
+
['Tag', c('Tag')],
|
|
209
|
+
['Card', c('Card')],
|
|
210
|
+
['Skeleton', c('Skeleton')],
|
|
211
|
+
['Spinner', c('Spinner')],
|
|
212
|
+
['Progress', c('Progress')],
|
|
213
|
+
['Divider', c('Separator')],
|
|
214
|
+
['Table', c('Table')],
|
|
215
|
+
['List', c('List')],
|
|
216
|
+
['Stack', c('Stack')],
|
|
217
|
+
['HStack', c('Stack')],
|
|
218
|
+
['VStack', c('Stack')],
|
|
219
|
+
['Grid', c('Grid')],
|
|
220
|
+
['Box', c('Box')],
|
|
221
|
+
['Container', c('Container')],
|
|
222
|
+
['FormLabel', c('Label')],
|
|
223
|
+
['FormHelperText', c('FieldHint')],
|
|
224
|
+
['FormErrorMessage', c('FieldError')],
|
|
225
|
+
['FormControl', c('Field')],
|
|
226
|
+
),
|
|
227
|
+
entries('@chakra-ui/button', ['Button', c('Button')], ['IconButton', c('IconButton')]),
|
|
228
|
+
|
|
229
|
+
// ── Mantine ───────────────────────────────────────────────────────
|
|
230
|
+
entries(
|
|
231
|
+
'@mantine/core',
|
|
232
|
+
['Button', c('Button')],
|
|
233
|
+
['ActionIcon', c('IconButton')],
|
|
234
|
+
['UnstyledButton', c('Button')],
|
|
235
|
+
['TextInput', c('Input')],
|
|
236
|
+
['PasswordInput', c('PasswordInput')],
|
|
237
|
+
['NumberInput', c('NumberInput')],
|
|
238
|
+
['Textarea', c('Textarea')],
|
|
239
|
+
['Checkbox', c('Checkbox')],
|
|
240
|
+
['Radio', c('Radio')],
|
|
241
|
+
['Switch', c('Switch')],
|
|
242
|
+
['Slider', c('Slider')],
|
|
243
|
+
['RangeSlider', c('Slider')],
|
|
244
|
+
['Select', c('Select')],
|
|
245
|
+
['MultiSelect', c('MultiSelect')],
|
|
246
|
+
['Autocomplete', c('Combobox')],
|
|
247
|
+
['Combobox', c('Combobox')],
|
|
248
|
+
['Modal', c('Dialog')],
|
|
249
|
+
['Drawer', c('Drawer')],
|
|
250
|
+
['Popover', c('Popover')],
|
|
251
|
+
['Tooltip', c('Tooltip')],
|
|
252
|
+
['HoverCard', c('HoverCard')],
|
|
253
|
+
['Notification', c('Toast')],
|
|
254
|
+
['Alert', c('Alert')],
|
|
255
|
+
['Tabs', c('Tabs')],
|
|
256
|
+
['Accordion', c('Accordion')],
|
|
257
|
+
['Menu', c('Menu')],
|
|
258
|
+
['Breadcrumbs', c('Breadcrumb')],
|
|
259
|
+
['Pagination', c('Pagination')],
|
|
260
|
+
['Stepper', c('Stepper')],
|
|
261
|
+
['Avatar', c('Avatar')],
|
|
262
|
+
['Badge', c('Badge')],
|
|
263
|
+
['Chip', c('Chip')],
|
|
264
|
+
['Card', c('Card')],
|
|
265
|
+
['Skeleton', c('Skeleton')],
|
|
266
|
+
['Loader', c('Spinner')],
|
|
267
|
+
['Progress', c('Progress')],
|
|
268
|
+
['Divider', c('Separator')],
|
|
269
|
+
['Table', c('Table')],
|
|
270
|
+
['List', c('List')],
|
|
271
|
+
['Stack', c('Stack')],
|
|
272
|
+
['Group', c('Stack')],
|
|
273
|
+
['Grid', c('Grid')],
|
|
274
|
+
['Box', c('Box')],
|
|
275
|
+
['Container', c('Container')],
|
|
276
|
+
['ScrollArea', c('ScrollArea')],
|
|
277
|
+
['NavLink', c('NavigationMenu')],
|
|
278
|
+
),
|
|
279
|
+
entries('@mantine/dates', ['DatePicker', c('DatePicker')], ['DateInput', c('DatePicker')], ['TimeInput', c('TimePicker')], ['Calendar', c('Calendar')]),
|
|
280
|
+
|
|
281
|
+
// ── Specialised utility libraries (§9.1 named utilities) ──────────
|
|
282
|
+
entries('cmdk', ['Command', c('Combobox')], ['default', c('Combobox')]),
|
|
283
|
+
entries('vaul', ['Drawer', c('Drawer')], ['default', c('Drawer')]),
|
|
284
|
+
entries('react-day-picker', ['DayPicker', c('Calendar')], ['default', c('Calendar')]),
|
|
285
|
+
entries('react-datepicker', ['default', c('DatePicker')]),
|
|
286
|
+
entries('react-modal', ['default', c('Dialog')]),
|
|
287
|
+
entries('react-tooltip', ['Tooltip', c('Tooltip')]),
|
|
288
|
+
entries('react-toastify', ['ToastContainer', c('Toast')], ['toast', c('Toast')]),
|
|
289
|
+
entries('react-hot-toast', ['Toaster', c('Toast')], ['default', c('Toast')]),
|
|
290
|
+
entries('sonner', ['Toaster', c('Toast')], ['toast', c('Toast')]),
|
|
291
|
+
entries('react-select', ['default', c('Select')]),
|
|
292
|
+
entries('downshift', ['default', c('Combobox')], ['useCombobox', c('Combobox')]),
|
|
293
|
+
]);
|
|
294
|
+
|
|
295
|
+
// Quick lookup: package + imported name → canonical id (or undefined).
|
|
296
|
+
export function lookupLibraryImport(
|
|
297
|
+
pkg: string,
|
|
298
|
+
importedName: string,
|
|
299
|
+
): CanonicalId | undefined {
|
|
300
|
+
return LIBRARY_MAP.get(pkg)?.get(importedName)?.canonical;
|
|
301
|
+
}
|