@nysds/mcp-server 1.19.3 → 1.20.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.
@@ -165,5 +165,5 @@ The following NYSDS components support `showError` and `errorMessage`:
165
165
 
166
166
  1. **Error summary links**: Include anchor links to fields for keyboard navigation
167
167
  2. **Focus management**: Move focus to error summary or first error field on validation failure
168
- 3. **ARIA attributes**: NYSDS components automatically set `aria-invalid` and `aria-describedby`
168
+ 3. **ARIA attributes**: NYSDS form components automatically set `aria-invalid` on the control and associate the error message via `aria-errormessage`, and associate the visible `<nys-label>` with the control via `aria-labelledby` — no manual wiring needed
169
169
  4. **Clear error messages**: Use specific, actionable error text
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * New York State Design System v1.19.3
2
+ * New York State Design System v1.20.0
3
3
  * Description: A design system for New York State's digital products.
4
4
  * Repository: https://github.com/its-hcd/nysds
5
5
  * License: MIT
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Guide Loading & Indexing
3
+ *
4
+ * Single source of truth for reading guide markdown from data/guides/.
5
+ * Also builds a reverse index of which guides mention which component tags,
6
+ * so component lookups can point at the guides that actually cover them.
7
+ */
8
+ export declare const GUIDE_TOPICS: readonly ["installation", "form-validation", "styles", "fonts", "page-structure", "themes"];
9
+ export declare const GUIDE_FRAMEWORKS: readonly ["angular", "react", "dotnet", "drupal", "vanilla"];
10
+ export type GuideTopic = (typeof GUIDE_TOPICS)[number];
11
+ export type GuideFramework = (typeof GUIDE_FRAMEWORKS)[number];
12
+ /**
13
+ * Load a topic guide's markdown content.
14
+ */
15
+ export declare function loadTopicGuide(topic: GuideTopic): string;
16
+ /**
17
+ * Load a framework-specific guide's markdown content.
18
+ */
19
+ export declare function loadFrameworkGuide(framework: GuideFramework): string;
20
+ export interface GuideReference {
21
+ /** Human-readable name of the guide, e.g. "form-validation" */
22
+ guide: string;
23
+ /** Topic guide key, e.g. "form-validation" */
24
+ topic: GuideTopic;
25
+ /** Framework guide key, when the reference came from a framework guide */
26
+ framework?: GuideFramework;
27
+ /** The get_guide call that retrieves it */
28
+ call: string;
29
+ }
30
+ /**
31
+ * Get the guides that mention a given component tag.
32
+ *
33
+ * Framework guides are collapsed into a single "see framework guides" hint
34
+ * rather than five near-identical entries, since every framework guide uses
35
+ * nys-button and nys-alert as its example markup.
36
+ */
37
+ export declare function getGuidesMentioning(tagName: string): GuideReference[];
38
+ /**
39
+ * Clear the cached index (useful for testing).
40
+ */
41
+ export declare function clearGuideCache(): void;
42
+ //# sourceMappingURL=guides.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guides.d.ts","sourceRoot":"","sources":["../../src/lib/guides.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH,eAAO,MAAM,YAAY,6FAOf,CAAC;AAEX,eAAO,MAAM,gBAAgB,8DAMnB,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AACvD,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAW/D;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMxD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,CASpE;AAMD,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,8CAA8C;IAC9C,KAAK,EAAE,UAAU,CAAC;IAClB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAmED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,EAAE,CAcrE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Guide Loading & Indexing
3
+ *
4
+ * Single source of truth for reading guide markdown from data/guides/.
5
+ * Also builds a reverse index of which guides mention which component tags,
6
+ * so component lookups can point at the guides that actually cover them.
7
+ */
8
+ import { readFileSync } from "node:fs";
9
+ import { join, dirname } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ // Path to guides directory (relative to dist/lib/)
13
+ const GUIDES_DIR = join(__dirname, "../../data/guides");
14
+ export const GUIDE_TOPICS = [
15
+ "installation",
16
+ "form-validation",
17
+ "styles",
18
+ "fonts",
19
+ "page-structure",
20
+ "themes",
21
+ ];
22
+ export const GUIDE_FRAMEWORKS = [
23
+ "angular",
24
+ "react",
25
+ "dotnet",
26
+ "drupal",
27
+ "vanilla",
28
+ ];
29
+ const TOPIC_TO_FILE = {
30
+ installation: "installation.md",
31
+ "form-validation": "form-validation.md",
32
+ styles: "styles.md",
33
+ fonts: "fonts.md",
34
+ "page-structure": "page-structure.md",
35
+ themes: "themes.md",
36
+ };
37
+ /**
38
+ * Load a topic guide's markdown content.
39
+ */
40
+ export function loadTopicGuide(topic) {
41
+ try {
42
+ return readFileSync(join(GUIDES_DIR, TOPIC_TO_FILE[topic]), "utf-8");
43
+ }
44
+ catch {
45
+ return `Guide not found: ${topic}`;
46
+ }
47
+ }
48
+ /**
49
+ * Load a framework-specific guide's markdown content.
50
+ */
51
+ export function loadFrameworkGuide(framework) {
52
+ try {
53
+ return readFileSync(join(GUIDES_DIR, "frameworks", `${framework}.md`), "utf-8");
54
+ }
55
+ catch {
56
+ return `Framework guide not found: ${framework}`;
57
+ }
58
+ }
59
+ let cachedTagIndex = null;
60
+ const TAG_PATTERN = /nys-[a-z][a-z0-9-]*/g;
61
+ function indexGuide(content, ref, index) {
62
+ const seen = new Set();
63
+ for (const match of content.matchAll(TAG_PATTERN)) {
64
+ const tag = match[0];
65
+ if (seen.has(tag))
66
+ continue;
67
+ seen.add(tag);
68
+ const existing = index.get(tag);
69
+ if (existing) {
70
+ existing.push(ref);
71
+ }
72
+ else {
73
+ index.set(tag, [ref]);
74
+ }
75
+ }
76
+ }
77
+ /**
78
+ * Build (and cache) the tag -> guides index.
79
+ *
80
+ * The index is keyed on every `nys-*` string found in guide markdown, which
81
+ * includes non-component matches like CSS variables (`--nys-color-*`) and
82
+ * utility classes (`nys-grid-col-6`). Callers are expected to look up real
83
+ * component tag names, so those extra keys are never read.
84
+ */
85
+ function getTagIndex() {
86
+ if (cachedTagIndex)
87
+ return cachedTagIndex;
88
+ const index = new Map();
89
+ for (const topic of GUIDE_TOPICS) {
90
+ indexGuide(loadTopicGuide(topic), {
91
+ guide: topic,
92
+ topic,
93
+ call: `get_guide({ topic: "${topic}" })`,
94
+ }, index);
95
+ }
96
+ for (const framework of GUIDE_FRAMEWORKS) {
97
+ indexGuide(loadFrameworkGuide(framework), {
98
+ guide: `${framework} setup`,
99
+ topic: "installation",
100
+ framework,
101
+ call: `get_guide({ topic: "installation", framework: "${framework}" })`,
102
+ }, index);
103
+ }
104
+ cachedTagIndex = index;
105
+ return index;
106
+ }
107
+ /**
108
+ * Get the guides that mention a given component tag.
109
+ *
110
+ * Framework guides are collapsed into a single "see framework guides" hint
111
+ * rather than five near-identical entries, since every framework guide uses
112
+ * nys-button and nys-alert as its example markup.
113
+ */
114
+ export function getGuidesMentioning(tagName) {
115
+ const refs = getTagIndex().get(tagName.toLowerCase()) ?? [];
116
+ const topicRefs = refs.filter((r) => !r.framework);
117
+ const frameworkRefs = refs.filter((r) => r.framework);
118
+ const result = [...topicRefs];
119
+ if (frameworkRefs.length > 0) {
120
+ result.push({
121
+ guide: `framework setup (${frameworkRefs.map((r) => r.framework).join(", ")})`,
122
+ topic: "installation",
123
+ call: `get_guide({ topic: "installation", framework: "${frameworkRefs[0].framework}" })`,
124
+ });
125
+ }
126
+ return result;
127
+ }
128
+ /**
129
+ * Clear the cached index (useful for testing).
130
+ */
131
+ export function clearGuideCache() {
132
+ cachedTagIndex = null;
133
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Component Relationships & Integration
3
+ *
4
+ * Derives how components connect to each other, to their npm packages, and to
5
+ * the guides that cover them — all from the Custom Elements Manifest, so it
6
+ * stays in sync as components are added or renamed.
7
+ *
8
+ * Two derivation passes:
9
+ *
10
+ * 1. **Family** — components declared under the same `packages/<name>/` source
11
+ * directory ship in the same npm package. Containment *within* a family is
12
+ * read from the docs rather than the directory name, which is unreliable
13
+ * (`packages/nys-checkbox` contains the container `nys-checkboxgroup`):
14
+ *
15
+ * a. A container's slot descriptions name its children — "Default slot for
16
+ * `nys-checkbox` elements", "Accepts `<nys-tab>` and `<nys-tabpanel>`".
17
+ * b. A child's description names its container — "for use within
18
+ * `nys-select`", "a single step within `nys-stepper`".
19
+ * c. A component marked "**Slotted component.**" or "**Internal
20
+ * component.**" falls back to the only unmarked member of its family.
21
+ *
22
+ * This is how `nys-option` is known to belong inside `nys-select`, and
23
+ * `nys-checkbox` inside `nys-checkboxgroup` rather than the reverse.
24
+ *
25
+ * 2. **Mentions** — component JSDoc names sibling and alternative components in
26
+ * prose (`For 7+ options, use \`nys-select\``). Scanning descriptions, slots,
27
+ * and attribute docs recovers those edges in both directions.
28
+ *
29
+ * Mentions are filtered against the set of registered tag names, which drops
30
+ * event names (`nys-change`, `nys-input`), CSS variables, and stale references
31
+ * to components that no longer exist. A tag that is *also* an event name
32
+ * (`nys-select` is both a component and an event emitted by `nys-textarea`) is
33
+ * additionally checked against its surrounding phrasing so an "emits
34
+ * `nys-select`" sentence does not fabricate a component relationship.
35
+ */
36
+ import { type CEMDeclaration } from "./cem-parser.js";
37
+ import { type GuideReference } from "./guides.js";
38
+ export type RelationKind = "parent" | "child" | "sibling" | "mentions" | "mentioned-by" | "mutual";
39
+ export interface RelatedComponent {
40
+ tagName: string;
41
+ summary: string;
42
+ relation: RelationKind;
43
+ /** Why this edge exists, in one line */
44
+ note: string;
45
+ /** Same npm package as the component being described */
46
+ samePackage: boolean;
47
+ }
48
+ export interface ComponentIntegration {
49
+ package: string;
50
+ install: string;
51
+ imports: {
52
+ component: string;
53
+ allComponents: string;
54
+ react: string;
55
+ styles: string;
56
+ };
57
+ stylesNote: string;
58
+ /** Subcomponents / parents that must be present for correct usage */
59
+ requires: RelatedComponent[];
60
+ /** Components commonly used alongside this one */
61
+ usedWith: RelatedComponent[];
62
+ /** Components the docs point to as alternatives for other situations */
63
+ alternatives: RelatedComponent[];
64
+ guides: GuideReference[];
65
+ styling: {
66
+ cssCustomProperties: {
67
+ name: string;
68
+ description?: string;
69
+ }[];
70
+ spacing: string;
71
+ tokens: string;
72
+ };
73
+ nextSteps: string[];
74
+ }
75
+ /**
76
+ * Get the npm package a component ships in.
77
+ * Subcomponents resolve to their parent's package.
78
+ */
79
+ export declare function getPackageName(tagName: string): string;
80
+ export interface ComponentRelationships {
81
+ /** The npm package family this component belongs to */
82
+ package: string;
83
+ /** Container component, when this is a subcomponent */
84
+ parent?: RelatedComponent;
85
+ /** Subcomponents this component contains */
86
+ children: RelatedComponent[];
87
+ /** Other subcomponents in the same package */
88
+ siblings: RelatedComponent[];
89
+ /** Components referenced across package boundaries */
90
+ related: RelatedComponent[];
91
+ }
92
+ export declare function getRelationships(tagName: string): ComponentRelationships;
93
+ /**
94
+ * Build the full integration payload for a component: what to install, what to
95
+ * import, what has to be nested inside it, and which guides cover it.
96
+ */
97
+ export declare function getIntegration(component: CEMDeclaration): ComponentIntegration;
98
+ /**
99
+ * Clear cached derivations (useful for testing).
100
+ */
101
+ export declare function clearRelationshipCache(): void;
102
+ //# sourceMappingURL=relationships.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationships.d.ts","sourceRoot":"","sources":["../../src/lib/relationships.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAMvE,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,OAAO,GACP,SAAS,GACT,UAAU,GACV,cAAc,GACd,QAAQ,CAAC;AAEb,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,kDAAkD;IAClD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,wEAAwE;IACxE,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,OAAO,EAAE;QACP,mBAAmB,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,EAAE,CAAC;QAC9D,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAuKD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAItD;AAyHD,MAAM,WAAW,sBAAsB;IACrC,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,4CAA4C;IAC5C,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,8CAA8C;IAC9C,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,sDAAsD;IACtD,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB,CAqFxE;AAWD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,cAAc,GACxB,oBAAoB,CAuEtB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAM7C"}